1 /*
2 Minetest
3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "server.h"
21 #include <iostream>
22 #include <queue>
23 #include <algorithm>
24 #include "network/connection.h"
25 #include "network/networkprotocol.h"
26 #include "network/serveropcodes.h"
27 #include "ban.h"
28 #include "environment.h"
29 #include "map.h"
30 #include "threading/mutex_auto_lock.h"
31 #include "constants.h"
32 #include "voxel.h"
33 #include "config.h"
34 #include "version.h"
35 #include "filesys.h"
36 #include "mapblock.h"
37 #include "server/serveractiveobject.h"
38 #include "settings.h"
39 #include "profiler.h"
40 #include "log.h"
41 #include "scripting_server.h"
42 #include "nodedef.h"
43 #include "itemdef.h"
44 #include "craftdef.h"
45 #include "emerge.h"
46 #include "mapgen/mapgen.h"
47 #include "mapgen/mg_biome.h"
48 #include "content_mapnode.h"
49 #include "content_nodemeta.h"
50 #include "content/mods.h"
51 #include "modchannels.h"
52 #include "serverlist.h"
53 #include "util/string.h"
54 #include "rollback.h"
55 #include "util/serialize.h"
56 #include "util/thread.h"
57 #include "defaultsettings.h"
58 #include "server/mods.h"
59 #include "util/base64.h"
60 #include "util/sha1.h"
61 #include "util/hex.h"
62 #include "database/database.h"
63 #include "chatmessage.h"
64 #include "chat_interface.h"
65 #include "remoteplayer.h"
66 #include "server/player_sao.h"
67 #include "server/serverinventorymgr.h"
68 #include "translation.h"
69
70 class ClientNotFoundException : public BaseException
71 {
72 public:
ClientNotFoundException(const char * s)73 ClientNotFoundException(const char *s):
74 BaseException(s)
75 {}
76 };
77
78 class ServerThread : public Thread
79 {
80 public:
81
ServerThread(Server * server)82 ServerThread(Server *server):
83 Thread("Server"),
84 m_server(server)
85 {}
86
87 void *run();
88
89 private:
90 Server *m_server;
91 };
92
run()93 void *ServerThread::run()
94 {
95 BEGIN_DEBUG_EXCEPTION_HANDLER
96
97 /*
98 * The real business of the server happens on the ServerThread.
99 * How this works:
100 * AsyncRunStep() runs an actual server step as soon as enough time has
101 * passed (dedicated_server_loop keeps track of that).
102 * Receive() blocks at least(!) 30ms waiting for a packet (so this loop
103 * doesn't busy wait) and will process any remaining packets.
104 */
105
106 m_server->AsyncRunStep(true);
107
108 while (!stopRequested()) {
109 try {
110 m_server->AsyncRunStep();
111
112 m_server->Receive();
113
114 } catch (con::PeerNotFoundException &e) {
115 infostream<<"Server: PeerNotFoundException"<<std::endl;
116 } catch (ClientNotFoundException &e) {
117 } catch (con::ConnectionBindFailed &e) {
118 m_server->setAsyncFatalError(e.what());
119 } catch (LuaError &e) {
120 m_server->setAsyncFatalError(
121 "ServerThread::run Lua: " + std::string(e.what()));
122 }
123 }
124
125 END_DEBUG_EXCEPTION_HANDLER
126
127 return nullptr;
128 }
129
getPos(ServerEnvironment * env,bool * pos_exists) const130 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
131 {
132 if(pos_exists) *pos_exists = false;
133 switch(type){
134 case SSP_LOCAL:
135 return v3f(0,0,0);
136 case SSP_POSITIONAL:
137 if(pos_exists) *pos_exists = true;
138 return pos;
139 case SSP_OBJECT: {
140 if(object == 0)
141 return v3f(0,0,0);
142 ServerActiveObject *sao = env->getActiveObject(object);
143 if(!sao)
144 return v3f(0,0,0);
145 if(pos_exists) *pos_exists = true;
146 return sao->getBasePosition(); }
147 }
148 return v3f(0,0,0);
149 }
150
reset()151 void Server::ShutdownState::reset()
152 {
153 m_timer = 0.0f;
154 message.clear();
155 should_reconnect = false;
156 is_requested = false;
157 }
158
trigger(float delay,const std::string & msg,bool reconnect)159 void Server::ShutdownState::trigger(float delay, const std::string &msg, bool reconnect)
160 {
161 m_timer = delay;
162 message = msg;
163 should_reconnect = reconnect;
164 }
165
tick(float dtime,Server * server)166 void Server::ShutdownState::tick(float dtime, Server *server)
167 {
168 if (m_timer <= 0.0f)
169 return;
170
171 // Timed shutdown
172 static const float shutdown_msg_times[] =
173 {
174 1, 2, 3, 4, 5, 10, 20, 40, 60, 120, 180, 300, 600, 1200, 1800, 3600
175 };
176
177 // Automated messages
178 if (m_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
179 for (float t : shutdown_msg_times) {
180 // If shutdown timer matches an automessage, shot it
181 if (m_timer > t && m_timer - dtime < t) {
182 std::wstring periodicMsg = getShutdownTimerMessage();
183
184 infostream << wide_to_utf8(periodicMsg).c_str() << std::endl;
185 server->SendChatMessage(PEER_ID_INEXISTENT, periodicMsg);
186 break;
187 }
188 }
189 }
190
191 m_timer -= dtime;
192 if (m_timer < 0.0f) {
193 m_timer = 0.0f;
194 is_requested = true;
195 }
196 }
197
getShutdownTimerMessage() const198 std::wstring Server::ShutdownState::getShutdownTimerMessage() const
199 {
200 std::wstringstream ws;
201 ws << L"*** Server shutting down in "
202 << duration_to_string(myround(m_timer)).c_str() << ".";
203 return ws.str();
204 }
205
206 /*
207 Server
208 */
209
Server(const std::string & path_world,const SubgameSpec & gamespec,bool simple_singleplayer_mode,Address bind_addr,bool dedicated,ChatInterface * iface,std::string * on_shutdown_errmsg)210 Server::Server(
211 const std::string &path_world,
212 const SubgameSpec &gamespec,
213 bool simple_singleplayer_mode,
214 Address bind_addr,
215 bool dedicated,
216 ChatInterface *iface,
217 std::string *on_shutdown_errmsg
218 ):
219 m_bind_addr(bind_addr),
220 m_path_world(path_world),
221 m_gamespec(gamespec),
222 m_simple_singleplayer_mode(simple_singleplayer_mode),
223 m_dedicated(dedicated),
224 m_async_fatal_error(""),
225 m_con(std::make_shared<con::Connection>(PROTOCOL_ID,
226 512,
227 CONNECTION_TIMEOUT,
228 m_bind_addr.isIPv6(),
229 this)),
230 m_itemdef(createItemDefManager()),
231 m_nodedef(createNodeDefManager()),
232 m_craftdef(createCraftDefManager()),
233 m_thread(new ServerThread(this)),
234 m_clients(m_con),
235 m_admin_chat(iface),
236 m_on_shutdown_errmsg(on_shutdown_errmsg),
237 m_modchannel_mgr(new ModChannelMgr())
238 {
239 if (m_path_world.empty())
240 throw ServerError("Supplied empty world path");
241
242 if (!gamespec.isValid())
243 throw ServerError("Supplied invalid gamespec");
244
245 #if USE_PROMETHEUS
246 m_metrics_backend = std::unique_ptr<MetricsBackend>(createPrometheusMetricsBackend());
247 #else
248 m_metrics_backend = std::unique_ptr<MetricsBackend>(new MetricsBackend());
249 #endif
250
251 m_uptime_counter = m_metrics_backend->addCounter("minetest_core_server_uptime", "Server uptime (in seconds)");
252 m_player_gauge = m_metrics_backend->addGauge("minetest_core_player_number", "Number of connected players");
253
254 m_timeofday_gauge = m_metrics_backend->addGauge(
255 "minetest_core_timeofday",
256 "Time of day value");
257
258 m_lag_gauge = m_metrics_backend->addGauge(
259 "minetest_core_latency",
260 "Latency value (in seconds)");
261
262 m_aom_buffer_counter = m_metrics_backend->addCounter(
263 "minetest_core_aom_generated_count",
264 "Number of active object messages generated");
265
266 m_packet_recv_counter = m_metrics_backend->addCounter(
267 "minetest_core_server_packet_recv",
268 "Processable packets received");
269
270 m_packet_recv_processed_counter = m_metrics_backend->addCounter(
271 "minetest_core_server_packet_recv_processed",
272 "Valid received packets processed");
273
274 m_lag_gauge->set(g_settings->getFloat("dedicated_server_step"));
275 }
276
~Server()277 Server::~Server()
278 {
279
280 // Send shutdown message
281 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE,
282 L"*** Server shutting down"));
283
284 if (m_env) {
285 MutexAutoLock envlock(m_env_mutex);
286
287 infostream << "Server: Saving players" << std::endl;
288 m_env->saveLoadedPlayers();
289
290 infostream << "Server: Kicking players" << std::endl;
291 std::string kick_msg;
292 bool reconnect = false;
293 if (isShutdownRequested()) {
294 reconnect = m_shutdown_state.should_reconnect;
295 kick_msg = m_shutdown_state.message;
296 }
297 if (kick_msg.empty()) {
298 kick_msg = g_settings->get("kick_msg_shutdown");
299 }
300 m_env->saveLoadedPlayers(true);
301 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
302 kick_msg, reconnect);
303 }
304
305 actionstream << "Server: Shutting down" << std::endl;
306
307 // Do this before stopping the server in case mapgen callbacks need to access
308 // server-controlled resources (like ModStorages). Also do them before
309 // shutdown callbacks since they may modify state that is finalized in a
310 // callback.
311 if (m_emerge)
312 m_emerge->stopThreads();
313
314 if (m_env) {
315 MutexAutoLock envlock(m_env_mutex);
316
317 // Execute script shutdown hooks
318 infostream << "Executing shutdown hooks" << std::endl;
319 try {
320 m_script->on_shutdown();
321 } catch (ModError &e) {
322 errorstream << "ModError: " << e.what() << std::endl;
323 if (m_on_shutdown_errmsg) {
324 if (m_on_shutdown_errmsg->empty()) {
325 *m_on_shutdown_errmsg = std::string("ModError: ") + e.what();
326 } else {
327 *m_on_shutdown_errmsg += std::string("\nModError: ") + e.what();
328 }
329 }
330 }
331
332 infostream << "Server: Saving environment metadata" << std::endl;
333 m_env->saveMeta();
334 }
335
336 // Stop threads
337 if (m_thread) {
338 stop();
339 delete m_thread;
340 }
341
342 // Delete things in the reverse order of creation
343 delete m_emerge;
344 delete m_env;
345 delete m_rollback;
346 delete m_banmanager;
347 delete m_itemdef;
348 delete m_nodedef;
349 delete m_craftdef;
350
351 // Deinitialize scripting
352 infostream << "Server: Deinitializing scripting" << std::endl;
353 delete m_script;
354 delete m_startup_server_map; // if available
355 delete m_game_settings;
356
357 while (!m_unsent_map_edit_queue.empty()) {
358 delete m_unsent_map_edit_queue.front();
359 m_unsent_map_edit_queue.pop();
360 }
361 }
362
init()363 void Server::init()
364 {
365 infostream << "Server created for gameid \"" << m_gamespec.id << "\"";
366 if (m_simple_singleplayer_mode)
367 infostream << " in simple singleplayer mode" << std::endl;
368 else
369 infostream << std::endl;
370 infostream << "- world: " << m_path_world << std::endl;
371 infostream << "- game: " << m_gamespec.path << std::endl;
372
373 m_game_settings = Settings::createLayer(SL_GAME);
374
375 // Create world if it doesn't exist
376 try {
377 loadGameConfAndInitWorld(m_path_world,
378 fs::GetFilenameFromPath(m_path_world.c_str()),
379 m_gamespec, false);
380 } catch (const BaseException &e) {
381 throw ServerError(std::string("Failed to initialize world: ") + e.what());
382 }
383
384 // Create emerge manager
385 m_emerge = new EmergeManager(this);
386
387 // Create ban manager
388 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
389 m_banmanager = new BanManager(ban_path);
390
391 m_modmgr = std::unique_ptr<ServerModManager>(new ServerModManager(m_path_world));
392 std::vector<ModSpec> unsatisfied_mods = m_modmgr->getUnsatisfiedMods();
393 // complain about mods with unsatisfied dependencies
394 if (!m_modmgr->isConsistent()) {
395 m_modmgr->printUnsatisfiedModsError();
396 }
397
398 //lock environment
399 MutexAutoLock envlock(m_env_mutex);
400
401 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
402 ServerMap *servermap = new ServerMap(m_path_world, this, m_emerge, m_metrics_backend.get());
403 m_startup_server_map = servermap;
404
405 // Initialize scripting
406 infostream << "Server: Initializing Lua" << std::endl;
407
408 m_script = new ServerScripting(this);
409
410 // Must be created before mod loading because we have some inventory creation
411 m_inventory_mgr = std::unique_ptr<ServerInventoryManager>(new ServerInventoryManager());
412
413 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
414
415 m_modmgr->loadMods(m_script);
416
417 // Read Textures and calculate sha1 sums
418 fillMediaCache();
419
420 // Apply item aliases in the node definition manager
421 m_nodedef->updateAliases(m_itemdef);
422
423 // Apply texture overrides from texturepack/override.txt
424 std::vector<std::string> paths;
425 fs::GetRecursiveDirs(paths, g_settings->get("texture_path"));
426 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
427 for (const std::string &path : paths) {
428 TextureOverrideSource override_source(path + DIR_DELIM + "override.txt");
429 m_nodedef->applyTextureOverrides(override_source.getNodeTileOverrides());
430 m_itemdef->applyTextureOverrides(override_source.getItemTextureOverrides());
431 }
432
433 m_nodedef->setNodeRegistrationStatus(true);
434
435 // Perform pending node name resolutions
436 m_nodedef->runNodeResolveCallbacks();
437
438 // unmap node names in cross-references
439 m_nodedef->resolveCrossrefs();
440
441 // init the recipe hashes to speed up crafting
442 m_craftdef->initHashes(this);
443
444 // Initialize Environment
445 m_startup_server_map = nullptr; // Ownership moved to ServerEnvironment
446 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
447
448 m_inventory_mgr->setEnv(m_env);
449 m_clients.setEnv(m_env);
450
451 if (!servermap->settings_mgr.makeMapgenParams())
452 FATAL_ERROR("Couldn't create any mapgen type");
453
454 // Initialize mapgens
455 m_emerge->initMapgens(servermap->getMapgenParams());
456
457 if (g_settings->getBool("enable_rollback_recording")) {
458 // Create rollback manager
459 m_rollback = new RollbackManager(m_path_world, this);
460 }
461
462 // Give environment reference to scripting api
463 m_script->initializeEnvironment(m_env);
464
465 // Register us to receive map edit events
466 servermap->addEventReceiver(this);
467
468 m_env->loadMeta();
469
470 // Those settings can be overwritten in world.mt, they are
471 // intended to be cached after environment loading.
472 m_liquid_transform_every = g_settings->getFloat("liquid_update");
473 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
474 m_csm_restriction_flags = g_settings->getU64("csm_restriction_flags");
475 m_csm_restriction_noderange = g_settings->getU32("csm_restriction_noderange");
476 }
477
start()478 void Server::start()
479 {
480 init();
481
482 infostream << "Starting server on " << m_bind_addr.serializeString()
483 << "..." << std::endl;
484
485 // Stop thread if already running
486 m_thread->stop();
487
488 // Initialize connection
489 m_con->SetTimeoutMs(30);
490 m_con->Serve(m_bind_addr);
491
492 // Start thread
493 m_thread->start();
494
495 // ASCII art for the win!
496 std::cerr
497 << " .__ __ __ " << std::endl
498 << " _____ |__| ____ _____/ |_ ____ _______/ |_ " << std::endl
499 << " / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\" << std::endl
500 << "| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | " << std::endl
501 << "|__|_| /__|___| /\\___ >__| \\___ >____ > |__| " << std::endl
502 << " \\/ \\/ \\/ \\/ \\/ " << std::endl;
503 actionstream << "World at [" << m_path_world << "]" << std::endl;
504 actionstream << "Server for gameid=\"" << m_gamespec.id
505 << "\" listening on " << m_bind_addr.serializeString() << ":"
506 << m_bind_addr.getPort() << "." << std::endl;
507 }
508
stop()509 void Server::stop()
510 {
511 infostream<<"Server: Stopping and waiting threads"<<std::endl;
512
513 // Stop threads (set run=false first so both start stopping)
514 m_thread->stop();
515 //m_emergethread.setRun(false);
516 m_thread->wait();
517 //m_emergethread.stop();
518
519 infostream<<"Server: Threads stopped"<<std::endl;
520 }
521
step(float dtime)522 void Server::step(float dtime)
523 {
524 // Limit a bit
525 if (dtime > 2.0)
526 dtime = 2.0;
527 {
528 MutexAutoLock lock(m_step_dtime_mutex);
529 m_step_dtime += dtime;
530 }
531 // Throw if fatal error occurred in thread
532 std::string async_err = m_async_fatal_error.get();
533 if (!async_err.empty()) {
534 if (!m_simple_singleplayer_mode) {
535 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
536 g_settings->get("kick_msg_crash"),
537 g_settings->getBool("ask_reconnect_on_crash"));
538 }
539 throw ServerError("AsyncErr: " + async_err);
540 }
541 }
542
AsyncRunStep(bool initial_step)543 void Server::AsyncRunStep(bool initial_step)
544 {
545
546 float dtime;
547 {
548 MutexAutoLock lock1(m_step_dtime_mutex);
549 dtime = m_step_dtime;
550 }
551
552 {
553 // Send blocks to clients
554 SendBlocks(dtime);
555 }
556
557 if((dtime < 0.001) && !initial_step)
558 return;
559
560 ScopeProfiler sp(g_profiler, "Server::AsyncRunStep()", SPT_AVG);
561
562 {
563 MutexAutoLock lock1(m_step_dtime_mutex);
564 m_step_dtime -= dtime;
565 }
566
567 /*
568 Update uptime
569 */
570 m_uptime_counter->increment(dtime);
571
572 handlePeerChanges();
573
574 /*
575 Update time of day and overall game time
576 */
577 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
578
579 /*
580 Send to clients at constant intervals
581 */
582
583 m_time_of_day_send_timer -= dtime;
584 if (m_time_of_day_send_timer < 0.0) {
585 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
586 u16 time = m_env->getTimeOfDay();
587 float time_speed = g_settings->getFloat("time_speed");
588 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
589
590 m_timeofday_gauge->set(time);
591 }
592
593 {
594 MutexAutoLock lock(m_env_mutex);
595 // Figure out and report maximum lag to environment
596 float max_lag = m_env->getMaxLagEstimate();
597 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
598 if(dtime > max_lag){
599 if(dtime > 0.1 && dtime > max_lag * 2.0)
600 infostream<<"Server: Maximum lag peaked to "<<dtime
601 <<" s"<<std::endl;
602 max_lag = dtime;
603 }
604 m_env->reportMaxLagEstimate(max_lag);
605 // Step environment
606 m_env->step(dtime);
607 }
608
609 static const float map_timer_and_unload_dtime = 2.92;
610 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
611 {
612 MutexAutoLock lock(m_env_mutex);
613 // Run Map's timers and unload unused data
614 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
615 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
616 g_settings->getFloat("server_unload_unused_data_timeout"),
617 U32_MAX);
618 }
619
620 /*
621 Listen to the admin chat, if available
622 */
623 if (m_admin_chat) {
624 if (!m_admin_chat->command_queue.empty()) {
625 MutexAutoLock lock(m_env_mutex);
626 while (!m_admin_chat->command_queue.empty()) {
627 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
628 handleChatInterfaceEvent(evt);
629 delete evt;
630 }
631 }
632 m_admin_chat->outgoing_queue.push_back(
633 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
634 }
635
636 /*
637 Do background stuff
638 */
639
640 /* Transform liquids */
641 m_liquid_transform_timer += dtime;
642 if(m_liquid_transform_timer >= m_liquid_transform_every)
643 {
644 m_liquid_transform_timer -= m_liquid_transform_every;
645
646 MutexAutoLock lock(m_env_mutex);
647
648 ScopeProfiler sp(g_profiler, "Server: liquid transform");
649
650 std::map<v3s16, MapBlock*> modified_blocks;
651 m_env->getMap().transformLiquids(modified_blocks, m_env);
652
653 /*
654 Set the modified blocks unsent for all the clients
655 */
656 if (!modified_blocks.empty()) {
657 SetBlocksNotSent(modified_blocks);
658 }
659 }
660 m_clients.step(dtime);
661
662 // increase/decrease lag gauge gradually
663 if (m_lag_gauge->get() > dtime) {
664 m_lag_gauge->decrement(dtime/100);
665 } else {
666 m_lag_gauge->increment(dtime/100);
667 }
668 #if USE_CURL
669 // send masterserver announce
670 {
671 float &counter = m_masterserver_timer;
672 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
673 g_settings->getBool("server_announce")) {
674 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
675 ServerList::AA_START,
676 m_bind_addr.getPort(),
677 m_clients.getPlayerNames(),
678 m_uptime_counter->get(),
679 m_env->getGameTime(),
680 m_lag_gauge->get(),
681 m_gamespec.id,
682 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
683 m_modmgr->getMods(),
684 m_dedicated);
685 counter = 0.01;
686 }
687 counter += dtime;
688 }
689 #endif
690
691 /*
692 Check added and deleted active objects
693 */
694 {
695 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
696 MutexAutoLock envlock(m_env_mutex);
697
698 m_clients.lock();
699 const RemoteClientMap &clients = m_clients.getClientList();
700 ScopeProfiler sp(g_profiler, "Server: update objects within range");
701
702 m_player_gauge->set(clients.size());
703 for (const auto &client_it : clients) {
704 RemoteClient *client = client_it.second;
705
706 if (client->getState() < CS_DefinitionsSent)
707 continue;
708
709 // This can happen if the client times out somehow
710 if (!m_env->getPlayer(client->peer_id))
711 continue;
712
713 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
714 if (!playersao)
715 continue;
716
717 SendActiveObjectRemoveAdd(client, playersao);
718 }
719 m_clients.unlock();
720
721 // Save mod storages if modified
722 m_mod_storage_save_timer -= dtime;
723 if (m_mod_storage_save_timer <= 0.0f) {
724 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
725 int n = 0;
726 for (std::unordered_map<std::string, ModMetadata *>::const_iterator
727 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
728 if (it->second->isModified()) {
729 it->second->save(getModStoragePath());
730 n++;
731 }
732 }
733 if (n > 0)
734 infostream << "Saved " << n << " modified mod storages." << std::endl;
735 }
736 }
737
738 /*
739 Send object messages
740 */
741 {
742 MutexAutoLock envlock(m_env_mutex);
743 ScopeProfiler sp(g_profiler, "Server: send SAO messages");
744
745 // Key = object id
746 // Value = data sent by object
747 std::unordered_map<u16, std::vector<ActiveObjectMessage>*> buffered_messages;
748
749 // Get active object messages from environment
750 ActiveObjectMessage aom(0);
751 u32 aom_count = 0;
752 for(;;) {
753 if (!m_env->getActiveObjectMessage(&aom))
754 break;
755
756 std::vector<ActiveObjectMessage>* message_list = nullptr;
757 auto n = buffered_messages.find(aom.id);
758 if (n == buffered_messages.end()) {
759 message_list = new std::vector<ActiveObjectMessage>;
760 buffered_messages[aom.id] = message_list;
761 } else {
762 message_list = n->second;
763 }
764 message_list->push_back(std::move(aom));
765 aom_count++;
766 }
767
768 m_aom_buffer_counter->increment(aom_count);
769
770 m_clients.lock();
771 const RemoteClientMap &clients = m_clients.getClientList();
772 // Route data to every client
773 std::string reliable_data, unreliable_data;
774 for (const auto &client_it : clients) {
775 reliable_data.clear();
776 unreliable_data.clear();
777 RemoteClient *client = client_it.second;
778 PlayerSAO *player = getPlayerSAO(client->peer_id);
779 // Go through all objects in message buffer
780 for (const auto &buffered_message : buffered_messages) {
781 // If object does not exist or is not known by client, skip it
782 u16 id = buffered_message.first;
783 ServerActiveObject *sao = m_env->getActiveObject(id);
784 if (!sao || client->m_known_objects.find(id) == client->m_known_objects.end())
785 continue;
786
787 // Get message list of object
788 std::vector<ActiveObjectMessage>* list = buffered_message.second;
789 // Go through every message
790 for (const ActiveObjectMessage &aom : *list) {
791 // Send position updates to players who do not see the attachment
792 if (aom.datastring[0] == AO_CMD_UPDATE_POSITION) {
793 if (sao->getId() == player->getId())
794 continue;
795
796 // Do not send position updates for attached players
797 // as long the parent is known to the client
798 ServerActiveObject *parent = sao->getParent();
799 if (parent && client->m_known_objects.find(parent->getId()) !=
800 client->m_known_objects.end())
801 continue;
802 }
803
804 // Add full new data to appropriate buffer
805 std::string &buffer = aom.reliable ? reliable_data : unreliable_data;
806 char idbuf[2];
807 writeU16((u8*) idbuf, aom.id);
808 // u16 id
809 // std::string data
810 buffer.append(idbuf, sizeof(idbuf));
811 buffer.append(serializeString16(aom.datastring));
812 }
813 }
814 /*
815 reliable_data and unreliable_data are now ready.
816 Send them.
817 */
818 if (!reliable_data.empty()) {
819 SendActiveObjectMessages(client->peer_id, reliable_data);
820 }
821
822 if (!unreliable_data.empty()) {
823 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
824 }
825 }
826 m_clients.unlock();
827
828 // Clear buffered_messages
829 for (auto &buffered_message : buffered_messages) {
830 delete buffered_message.second;
831 }
832 }
833
834 /*
835 Send queued-for-sending map edit events.
836 */
837 {
838 // We will be accessing the environment
839 MutexAutoLock lock(m_env_mutex);
840
841 // Don't send too many at a time
842 //u32 count = 0;
843
844 // Single change sending is disabled if queue size is not small
845 bool disable_single_change_sending = false;
846 if(m_unsent_map_edit_queue.size() >= 4)
847 disable_single_change_sending = true;
848
849 int event_count = m_unsent_map_edit_queue.size();
850
851 // We'll log the amount of each
852 Profiler prof;
853
854 std::list<v3s16> node_meta_updates;
855
856 while (!m_unsent_map_edit_queue.empty()) {
857 MapEditEvent* event = m_unsent_map_edit_queue.front();
858 m_unsent_map_edit_queue.pop();
859
860 // Players far away from the change are stored here.
861 // Instead of sending the changes, MapBlocks are set not sent
862 // for them.
863 std::unordered_set<u16> far_players;
864
865 switch (event->type) {
866 case MEET_ADDNODE:
867 case MEET_SWAPNODE:
868 prof.add("MEET_ADDNODE", 1);
869 sendAddNode(event->p, event->n, &far_players,
870 disable_single_change_sending ? 5 : 30,
871 event->type == MEET_ADDNODE);
872 break;
873 case MEET_REMOVENODE:
874 prof.add("MEET_REMOVENODE", 1);
875 sendRemoveNode(event->p, &far_players,
876 disable_single_change_sending ? 5 : 30);
877 break;
878 case MEET_BLOCK_NODE_METADATA_CHANGED: {
879 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
880 if (!event->is_private_change) {
881 // Don't send the change yet. Collect them to eliminate dupes.
882 node_meta_updates.remove(event->p);
883 node_meta_updates.push_back(event->p);
884 }
885
886 if (MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(
887 getNodeBlockPos(event->p))) {
888 block->raiseModified(MOD_STATE_WRITE_NEEDED,
889 MOD_REASON_REPORT_META_CHANGE);
890 }
891 break;
892 }
893 case MEET_OTHER:
894 prof.add("MEET_OTHER", 1);
895 for (const v3s16 &modified_block : event->modified_blocks) {
896 m_clients.markBlockposAsNotSent(modified_block);
897 }
898 break;
899 default:
900 prof.add("unknown", 1);
901 warningstream << "Server: Unknown MapEditEvent "
902 << ((u32)event->type) << std::endl;
903 break;
904 }
905
906 /*
907 Set blocks not sent to far players
908 */
909 if (!far_players.empty()) {
910 // Convert list format to that wanted by SetBlocksNotSent
911 std::map<v3s16, MapBlock*> modified_blocks2;
912 for (const v3s16 &modified_block : event->modified_blocks) {
913 modified_blocks2[modified_block] =
914 m_env->getMap().getBlockNoCreateNoEx(modified_block);
915 }
916
917 // Set blocks not sent
918 for (const u16 far_player : far_players) {
919 if (RemoteClient *client = getClient(far_player))
920 client->SetBlocksNotSent(modified_blocks2);
921 }
922 }
923
924 delete event;
925 }
926
927 if (event_count >= 5) {
928 infostream << "Server: MapEditEvents:" << std::endl;
929 prof.print(infostream);
930 } else if (event_count != 0) {
931 verbosestream << "Server: MapEditEvents:" << std::endl;
932 prof.print(verbosestream);
933 }
934
935 // Send all metadata updates
936 if (node_meta_updates.size())
937 sendMetadataChanged(node_meta_updates);
938 }
939
940 /*
941 Trigger emergethread (it somehow gets to a non-triggered but
942 bysy state sometimes)
943 */
944 {
945 float &counter = m_emergethread_trigger_timer;
946 counter += dtime;
947 if (counter >= 2.0) {
948 counter = 0.0;
949
950 m_emerge->startThreads();
951 }
952 }
953
954 // Save map, players and auth stuff
955 {
956 float &counter = m_savemap_timer;
957 counter += dtime;
958 static thread_local const float save_interval =
959 g_settings->getFloat("server_map_save_interval");
960 if (counter >= save_interval) {
961 counter = 0.0;
962 MutexAutoLock lock(m_env_mutex);
963
964 ScopeProfiler sp(g_profiler, "Server: map saving (sum)");
965
966 // Save ban file
967 if (m_banmanager->isModified()) {
968 m_banmanager->save();
969 }
970
971 // Save changed parts of map
972 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
973
974 // Save players
975 m_env->saveLoadedPlayers();
976
977 // Save environment metadata
978 m_env->saveMeta();
979 }
980 }
981
982 m_shutdown_state.tick(dtime, this);
983 }
984
Receive()985 void Server::Receive()
986 {
987 NetworkPacket pkt;
988 session_t peer_id;
989 bool first = true;
990 for (;;) {
991 pkt.clear();
992 peer_id = 0;
993 try {
994 /*
995 In the first iteration *wait* for a packet, afterwards process
996 all packets that are immediately available (no waiting).
997 */
998 if (first) {
999 m_con->Receive(&pkt);
1000 first = false;
1001 } else {
1002 if (!m_con->TryReceive(&pkt))
1003 return;
1004 }
1005
1006 peer_id = pkt.getPeerId();
1007 m_packet_recv_counter->increment();
1008 ProcessData(&pkt);
1009 m_packet_recv_processed_counter->increment();
1010 } catch (const con::InvalidIncomingDataException &e) {
1011 infostream << "Server::Receive(): InvalidIncomingDataException: what()="
1012 << e.what() << std::endl;
1013 } catch (const SerializationError &e) {
1014 infostream << "Server::Receive(): SerializationError: what()="
1015 << e.what() << std::endl;
1016 } catch (const ClientStateError &e) {
1017 errorstream << "ProcessData: peer=" << peer_id << " what()="
1018 << e.what() << std::endl;
1019 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1020 L"Try reconnecting or updating your client");
1021 } catch (const con::PeerNotFoundException &e) {
1022 // Do nothing
1023 } catch (const con::NoIncomingDataException &e) {
1024 return;
1025 }
1026 }
1027 }
1028
StageTwoClientInit(session_t peer_id)1029 PlayerSAO* Server::StageTwoClientInit(session_t peer_id)
1030 {
1031 std::string playername;
1032 PlayerSAO *playersao = NULL;
1033 m_clients.lock();
1034 try {
1035 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1036 if (client) {
1037 playername = client->getName();
1038 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1039 }
1040 } catch (std::exception &e) {
1041 m_clients.unlock();
1042 throw;
1043 }
1044 m_clients.unlock();
1045
1046 RemotePlayer *player = m_env->getPlayer(playername.c_str());
1047
1048 // If failed, cancel
1049 if (!playersao || !player) {
1050 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
1051 actionstream << "Server: Failed to emerge player \"" << playername
1052 << "\" (player allocated to an another client)" << std::endl;
1053 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1054 L"name. If your client closed unexpectedly, try again in "
1055 L"a minute.");
1056 } else {
1057 errorstream << "Server: " << playername << ": Failed to emerge player"
1058 << std::endl;
1059 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1060 }
1061 return NULL;
1062 }
1063
1064 /*
1065 Send complete position information
1066 */
1067 SendMovePlayer(peer_id);
1068
1069 // Send privileges
1070 SendPlayerPrivileges(peer_id);
1071
1072 // Send inventory formspec
1073 SendPlayerInventoryFormspec(peer_id);
1074
1075 // Send inventory
1076 SendInventory(playersao, false);
1077
1078 // Send HP or death screen
1079 if (playersao->isDead())
1080 SendDeathscreen(peer_id, false, v3f(0,0,0));
1081 else
1082 SendPlayerHPOrDie(playersao,
1083 PlayerHPChangeReason(PlayerHPChangeReason::SET_HP));
1084
1085 // Send Breath
1086 SendPlayerBreath(playersao);
1087
1088 /*
1089 Print out action
1090 */
1091 {
1092 Address addr = getPeerAddress(player->getPeerId());
1093 std::string ip_str = addr.serializeString();
1094 const std::vector<std::string> &names = m_clients.getPlayerNames();
1095
1096 actionstream << player->getName() << " [" << ip_str << "] joins game. List of players: ";
1097
1098 for (const std::string &name : names) {
1099 actionstream << name << " ";
1100 }
1101
1102 actionstream << player->getName() <<std::endl;
1103 }
1104 return playersao;
1105 }
1106
handleCommand(NetworkPacket * pkt)1107 inline void Server::handleCommand(NetworkPacket *pkt)
1108 {
1109 const ToServerCommandHandler &opHandle = toServerCommandTable[pkt->getCommand()];
1110 (this->*opHandle.handler)(pkt);
1111 }
1112
ProcessData(NetworkPacket * pkt)1113 void Server::ProcessData(NetworkPacket *pkt)
1114 {
1115 // Environment is locked first.
1116 MutexAutoLock envlock(m_env_mutex);
1117
1118 ScopeProfiler sp(g_profiler, "Server: Process network packet (sum)");
1119 u32 peer_id = pkt->getPeerId();
1120
1121 try {
1122 Address address = getPeerAddress(peer_id);
1123 std::string addr_s = address.serializeString();
1124
1125 if(m_banmanager->isIpBanned(addr_s)) {
1126 std::string ban_name = m_banmanager->getBanName(addr_s);
1127 infostream << "Server: A banned client tried to connect from "
1128 << addr_s << "; banned name was "
1129 << ban_name << std::endl;
1130 // This actually doesn't seem to transfer to the client
1131 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1132 + utf8_to_wide(ban_name));
1133 return;
1134 }
1135 }
1136 catch(con::PeerNotFoundException &e) {
1137 /*
1138 * no peer for this packet found
1139 * most common reason is peer timeout, e.g. peer didn't
1140 * respond for some time, your server was overloaded or
1141 * things like that.
1142 */
1143 infostream << "Server::ProcessData(): Canceling: peer "
1144 << peer_id << " not found" << std::endl;
1145 return;
1146 }
1147
1148 try {
1149 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1150
1151 // Command must be handled into ToServerCommandHandler
1152 if (command >= TOSERVER_NUM_MSG_TYPES) {
1153 infostream << "Server: Ignoring unknown command "
1154 << command << std::endl;
1155 return;
1156 }
1157
1158 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1159 handleCommand(pkt);
1160 return;
1161 }
1162
1163 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1164
1165 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1166 errorstream << "Server::ProcessData(): Cancelling: Peer"
1167 " serialization format invalid or not initialized."
1168 " Skipping incoming command=" << command << std::endl;
1169 return;
1170 }
1171
1172 /* Handle commands related to client startup */
1173 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1174 handleCommand(pkt);
1175 return;
1176 }
1177
1178 if (m_clients.getClientState(peer_id) < CS_Active) {
1179 if (command == TOSERVER_PLAYERPOS) return;
1180
1181 errorstream << "Got packet command: " << command << " for peer id "
1182 << peer_id << " but client isn't active yet. Dropping packet "
1183 << std::endl;
1184 return;
1185 }
1186
1187 handleCommand(pkt);
1188 } catch (SendFailedException &e) {
1189 errorstream << "Server::ProcessData(): SendFailedException: "
1190 << "what=" << e.what()
1191 << std::endl;
1192 } catch (PacketError &e) {
1193 actionstream << "Server::ProcessData(): PacketError: "
1194 << "what=" << e.what()
1195 << std::endl;
1196 }
1197 }
1198
setTimeOfDay(u32 time)1199 void Server::setTimeOfDay(u32 time)
1200 {
1201 m_env->setTimeOfDay(time);
1202 m_time_of_day_send_timer = 0;
1203 }
1204
onMapEditEvent(const MapEditEvent & event)1205 void Server::onMapEditEvent(const MapEditEvent &event)
1206 {
1207 if (m_ignore_map_edit_events_area.contains(event.getArea()))
1208 return;
1209
1210 m_unsent_map_edit_queue.push(new MapEditEvent(event));
1211 }
1212
SetBlocksNotSent(std::map<v3s16,MapBlock * > & block)1213 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1214 {
1215 std::vector<session_t> clients = m_clients.getClientIDs();
1216 m_clients.lock();
1217 // Set the modified blocks unsent for all the clients
1218 for (const session_t client_id : clients) {
1219 if (RemoteClient *client = m_clients.lockedGetClientNoEx(client_id))
1220 client->SetBlocksNotSent(block);
1221 }
1222 m_clients.unlock();
1223 }
1224
peerAdded(con::Peer * peer)1225 void Server::peerAdded(con::Peer *peer)
1226 {
1227 verbosestream<<"Server::peerAdded(): peer->id="
1228 <<peer->id<<std::endl;
1229
1230 m_peer_change_queue.push(con::PeerChange(con::PEER_ADDED, peer->id, false));
1231 }
1232
deletingPeer(con::Peer * peer,bool timeout)1233 void Server::deletingPeer(con::Peer *peer, bool timeout)
1234 {
1235 verbosestream<<"Server::deletingPeer(): peer->id="
1236 <<peer->id<<", timeout="<<timeout<<std::endl;
1237
1238 m_clients.event(peer->id, CSE_Disconnect);
1239 m_peer_change_queue.push(con::PeerChange(con::PEER_REMOVED, peer->id, timeout));
1240 }
1241
getClientConInfo(session_t peer_id,con::rtt_stat_type type,float * retval)1242 bool Server::getClientConInfo(session_t peer_id, con::rtt_stat_type type, float* retval)
1243 {
1244 *retval = m_con->getPeerStat(peer_id,type);
1245 return *retval != -1;
1246 }
1247
getClientInfo(session_t peer_id,ClientInfo & ret)1248 bool Server::getClientInfo(session_t peer_id, ClientInfo &ret)
1249 {
1250 m_clients.lock();
1251 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1252
1253 if (!client) {
1254 m_clients.unlock();
1255 return false;
1256 }
1257
1258 ret.state = client->getState();
1259 ret.addr = client->getAddress();
1260 ret.uptime = client->uptime();
1261 ret.ser_vers = client->serialization_version;
1262 ret.prot_vers = client->net_proto_version;
1263
1264 ret.major = client->getMajor();
1265 ret.minor = client->getMinor();
1266 ret.patch = client->getPatch();
1267 ret.vers_string = client->getFullVer();
1268
1269 ret.lang_code = client->getLangCode();
1270
1271 m_clients.unlock();
1272
1273 return true;
1274 }
1275
handlePeerChanges()1276 void Server::handlePeerChanges()
1277 {
1278 while(!m_peer_change_queue.empty())
1279 {
1280 con::PeerChange c = m_peer_change_queue.front();
1281 m_peer_change_queue.pop();
1282
1283 verbosestream<<"Server: Handling peer change: "
1284 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1285 <<std::endl;
1286
1287 switch(c.type)
1288 {
1289 case con::PEER_ADDED:
1290 m_clients.CreateClient(c.peer_id);
1291 break;
1292
1293 case con::PEER_REMOVED:
1294 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1295 break;
1296
1297 default:
1298 FATAL_ERROR("Invalid peer change event received!");
1299 break;
1300 }
1301 }
1302 }
1303
printToConsoleOnly(const std::string & text)1304 void Server::printToConsoleOnly(const std::string &text)
1305 {
1306 if (m_admin_chat) {
1307 m_admin_chat->outgoing_queue.push_back(
1308 new ChatEventChat("", utf8_to_wide(text)));
1309 } else {
1310 std::cout << text << std::endl;
1311 }
1312 }
1313
Send(NetworkPacket * pkt)1314 void Server::Send(NetworkPacket *pkt)
1315 {
1316 Send(pkt->getPeerId(), pkt);
1317 }
1318
Send(session_t peer_id,NetworkPacket * pkt)1319 void Server::Send(session_t peer_id, NetworkPacket *pkt)
1320 {
1321 m_clients.send(peer_id,
1322 clientCommandFactoryTable[pkt->getCommand()].channel,
1323 pkt,
1324 clientCommandFactoryTable[pkt->getCommand()].reliable);
1325 }
1326
SendMovement(session_t peer_id)1327 void Server::SendMovement(session_t peer_id)
1328 {
1329 std::ostringstream os(std::ios_base::binary);
1330
1331 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1332
1333 pkt << g_settings->getFloat("movement_acceleration_default");
1334 pkt << g_settings->getFloat("movement_acceleration_air");
1335 pkt << g_settings->getFloat("movement_acceleration_fast");
1336 pkt << g_settings->getFloat("movement_speed_walk");
1337 pkt << g_settings->getFloat("movement_speed_crouch");
1338 pkt << g_settings->getFloat("movement_speed_fast");
1339 pkt << g_settings->getFloat("movement_speed_climb");
1340 pkt << g_settings->getFloat("movement_speed_jump");
1341 pkt << g_settings->getFloat("movement_liquid_fluidity");
1342 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1343 pkt << g_settings->getFloat("movement_liquid_sink");
1344 pkt << g_settings->getFloat("movement_gravity");
1345
1346 Send(&pkt);
1347 }
1348
SendPlayerHPOrDie(PlayerSAO * playersao,const PlayerHPChangeReason & reason)1349 void Server::SendPlayerHPOrDie(PlayerSAO *playersao, const PlayerHPChangeReason &reason)
1350 {
1351 if (playersao->isImmortal())
1352 return;
1353
1354 session_t peer_id = playersao->getPeerID();
1355 bool is_alive = !playersao->isDead();
1356
1357 if (is_alive)
1358 SendPlayerHP(peer_id);
1359 else
1360 DiePlayer(peer_id, reason);
1361 }
1362
SendHP(session_t peer_id,u16 hp)1363 void Server::SendHP(session_t peer_id, u16 hp)
1364 {
1365 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1366 pkt << hp;
1367 Send(&pkt);
1368 }
1369
SendBreath(session_t peer_id,u16 breath)1370 void Server::SendBreath(session_t peer_id, u16 breath)
1371 {
1372 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1373 pkt << (u16) breath;
1374 Send(&pkt);
1375 }
1376
SendAccessDenied(session_t peer_id,AccessDeniedCode reason,const std::string & custom_reason,bool reconnect)1377 void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason,
1378 const std::string &custom_reason, bool reconnect)
1379 {
1380 assert(reason < SERVER_ACCESSDENIED_MAX);
1381
1382 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1383 pkt << (u8)reason;
1384 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1385 pkt << custom_reason;
1386 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1387 reason == SERVER_ACCESSDENIED_CRASH)
1388 pkt << custom_reason << (u8)reconnect;
1389 Send(&pkt);
1390 }
1391
SendAccessDenied_Legacy(session_t peer_id,const std::wstring & reason)1392 void Server::SendAccessDenied_Legacy(session_t peer_id,const std::wstring &reason)
1393 {
1394 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1395 pkt << reason;
1396 Send(&pkt);
1397 }
1398
SendDeathscreen(session_t peer_id,bool set_camera_point_target,v3f camera_point_target)1399 void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target,
1400 v3f camera_point_target)
1401 {
1402 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1403 pkt << set_camera_point_target << camera_point_target;
1404 Send(&pkt);
1405 }
1406
SendItemDef(session_t peer_id,IItemDefManager * itemdef,u16 protocol_version)1407 void Server::SendItemDef(session_t peer_id,
1408 IItemDefManager *itemdef, u16 protocol_version)
1409 {
1410 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1411
1412 /*
1413 u16 command
1414 u32 length of the next item
1415 zlib-compressed serialized ItemDefManager
1416 */
1417 std::ostringstream tmp_os(std::ios::binary);
1418 itemdef->serialize(tmp_os, protocol_version);
1419 std::ostringstream tmp_os2(std::ios::binary);
1420 compressZlib(tmp_os.str(), tmp_os2);
1421 pkt.putLongString(tmp_os2.str());
1422
1423 // Make data buffer
1424 verbosestream << "Server: Sending item definitions to id(" << peer_id
1425 << "): size=" << pkt.getSize() << std::endl;
1426
1427 Send(&pkt);
1428 }
1429
SendNodeDef(session_t peer_id,const NodeDefManager * nodedef,u16 protocol_version)1430 void Server::SendNodeDef(session_t peer_id,
1431 const NodeDefManager *nodedef, u16 protocol_version)
1432 {
1433 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1434
1435 /*
1436 u16 command
1437 u32 length of the next item
1438 zlib-compressed serialized NodeDefManager
1439 */
1440 std::ostringstream tmp_os(std::ios::binary);
1441 nodedef->serialize(tmp_os, protocol_version);
1442 std::ostringstream tmp_os2(std::ios::binary);
1443 compressZlib(tmp_os.str(), tmp_os2);
1444
1445 pkt.putLongString(tmp_os2.str());
1446
1447 // Make data buffer
1448 verbosestream << "Server: Sending node definitions to id(" << peer_id
1449 << "): size=" << pkt.getSize() << std::endl;
1450
1451 Send(&pkt);
1452 }
1453
1454 /*
1455 Non-static send methods
1456 */
1457
SendInventory(PlayerSAO * sao,bool incremental)1458 void Server::SendInventory(PlayerSAO *sao, bool incremental)
1459 {
1460 RemotePlayer *player = sao->getPlayer();
1461
1462 // Do not send new format to old clients
1463 incremental &= player->protocol_version >= 38;
1464
1465 UpdateCrafting(player);
1466
1467 /*
1468 Serialize it
1469 */
1470
1471 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, sao->getPeerID());
1472
1473 std::ostringstream os(std::ios::binary);
1474 sao->getInventory()->serialize(os, incremental);
1475 sao->getInventory()->setModified(false);
1476 player->setModified(true);
1477
1478 const std::string &s = os.str();
1479 pkt.putRawString(s.c_str(), s.size());
1480 Send(&pkt);
1481 }
1482
SendChatMessage(session_t peer_id,const ChatMessage & message)1483 void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
1484 {
1485 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1486 u8 version = 1;
1487 u8 type = message.type;
1488 pkt << version << type << message.sender << message.message
1489 << static_cast<u64>(message.timestamp);
1490
1491 if (peer_id != PEER_ID_INEXISTENT) {
1492 RemotePlayer *player = m_env->getPlayer(peer_id);
1493 if (!player)
1494 return;
1495
1496 Send(&pkt);
1497 } else {
1498 m_clients.sendToAll(&pkt);
1499 }
1500 }
1501
SendShowFormspecMessage(session_t peer_id,const std::string & formspec,const std::string & formname)1502 void Server::SendShowFormspecMessage(session_t peer_id, const std::string &formspec,
1503 const std::string &formname)
1504 {
1505 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0, peer_id);
1506 if (formspec.empty()){
1507 //the client should close the formspec
1508 //but make sure there wasn't another one open in meantime
1509 const auto it = m_formspec_state_data.find(peer_id);
1510 if (it != m_formspec_state_data.end() && it->second == formname) {
1511 m_formspec_state_data.erase(peer_id);
1512 }
1513 pkt.putLongString("");
1514 } else {
1515 m_formspec_state_data[peer_id] = formname;
1516 pkt.putLongString(formspec);
1517 }
1518 pkt << formname;
1519
1520 Send(&pkt);
1521 }
1522
1523 // Spawns a particle on peer with peer_id
SendSpawnParticle(session_t peer_id,u16 protocol_version,const ParticleParameters & p)1524 void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
1525 const ParticleParameters &p)
1526 {
1527 static thread_local const float radius =
1528 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1529
1530 if (peer_id == PEER_ID_INEXISTENT) {
1531 std::vector<session_t> clients = m_clients.getClientIDs();
1532 const v3f pos = p.pos * BS;
1533 const float radius_sq = radius * radius;
1534
1535 for (const session_t client_id : clients) {
1536 RemotePlayer *player = m_env->getPlayer(client_id);
1537 if (!player)
1538 continue;
1539
1540 PlayerSAO *sao = player->getPlayerSAO();
1541 if (!sao)
1542 continue;
1543
1544 // Do not send to distant clients
1545 if (sao->getBasePosition().getDistanceFromSQ(pos) > radius_sq)
1546 continue;
1547
1548 SendSpawnParticle(client_id, player->protocol_version, p);
1549 }
1550 return;
1551 }
1552 assert(protocol_version != 0);
1553
1554 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1555
1556 {
1557 // NetworkPacket and iostreams are incompatible...
1558 std::ostringstream oss(std::ios_base::binary);
1559 p.serialize(oss, protocol_version);
1560 pkt.putRawString(oss.str());
1561 }
1562
1563 Send(&pkt);
1564 }
1565
1566 // Adds a ParticleSpawner on peer with peer_id
SendAddParticleSpawner(session_t peer_id,u16 protocol_version,const ParticleSpawnerParameters & p,u16 attached_id,u32 id)1567 void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
1568 const ParticleSpawnerParameters &p, u16 attached_id, u32 id)
1569 {
1570 static thread_local const float radius =
1571 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1572
1573 if (peer_id == PEER_ID_INEXISTENT) {
1574 std::vector<session_t> clients = m_clients.getClientIDs();
1575 const v3f pos = (p.minpos + p.maxpos) / 2.0f * BS;
1576 const float radius_sq = radius * radius;
1577 /* Don't send short-lived spawners to distant players.
1578 * This could be replaced with proper tracking at some point. */
1579 const bool distance_check = !attached_id && p.time <= 1.0f;
1580
1581 for (const session_t client_id : clients) {
1582 RemotePlayer *player = m_env->getPlayer(client_id);
1583 if (!player)
1584 continue;
1585
1586 if (distance_check) {
1587 PlayerSAO *sao = player->getPlayerSAO();
1588 if (!sao)
1589 continue;
1590 if (sao->getBasePosition().getDistanceFromSQ(pos) > radius_sq)
1591 continue;
1592 }
1593
1594 SendAddParticleSpawner(client_id, player->protocol_version,
1595 p, attached_id, id);
1596 }
1597 return;
1598 }
1599 assert(protocol_version != 0);
1600
1601 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 100, peer_id);
1602
1603 pkt << p.amount << p.time << p.minpos << p.maxpos << p.minvel
1604 << p.maxvel << p.minacc << p.maxacc << p.minexptime << p.maxexptime
1605 << p.minsize << p.maxsize << p.collisiondetection;
1606
1607 pkt.putLongString(p.texture);
1608
1609 pkt << id << p.vertical << p.collision_removal << attached_id;
1610 {
1611 std::ostringstream os(std::ios_base::binary);
1612 p.animation.serialize(os, protocol_version);
1613 pkt.putRawString(os.str());
1614 }
1615 pkt << p.glow << p.object_collision;
1616 pkt << p.node.param0 << p.node.param2 << p.node_tile;
1617
1618 Send(&pkt);
1619 }
1620
SendDeleteParticleSpawner(session_t peer_id,u32 id)1621 void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
1622 {
1623 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id);
1624
1625 pkt << id;
1626
1627 if (peer_id != PEER_ID_INEXISTENT)
1628 Send(&pkt);
1629 else
1630 m_clients.sendToAll(&pkt);
1631
1632 }
1633
SendHUDAdd(session_t peer_id,u32 id,HudElement * form)1634 void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form)
1635 {
1636 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1637
1638 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1639 << form->text << form->number << form->item << form->dir
1640 << form->align << form->offset << form->world_pos << form->size
1641 << form->z_index << form->text2;
1642
1643 Send(&pkt);
1644 }
1645
SendHUDRemove(session_t peer_id,u32 id)1646 void Server::SendHUDRemove(session_t peer_id, u32 id)
1647 {
1648 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1649 pkt << id;
1650 Send(&pkt);
1651 }
1652
SendHUDChange(session_t peer_id,u32 id,HudElementStat stat,void * value)1653 void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value)
1654 {
1655 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1656 pkt << id << (u8) stat;
1657
1658 switch (stat) {
1659 case HUD_STAT_POS:
1660 case HUD_STAT_SCALE:
1661 case HUD_STAT_ALIGN:
1662 case HUD_STAT_OFFSET:
1663 pkt << *(v2f *) value;
1664 break;
1665 case HUD_STAT_NAME:
1666 case HUD_STAT_TEXT:
1667 case HUD_STAT_TEXT2:
1668 pkt << *(std::string *) value;
1669 break;
1670 case HUD_STAT_WORLD_POS:
1671 pkt << *(v3f *) value;
1672 break;
1673 case HUD_STAT_SIZE:
1674 pkt << *(v2s32 *) value;
1675 break;
1676 case HUD_STAT_NUMBER:
1677 case HUD_STAT_ITEM:
1678 case HUD_STAT_DIR:
1679 default:
1680 pkt << *(u32 *) value;
1681 break;
1682 }
1683
1684 Send(&pkt);
1685 }
1686
SendHUDSetFlags(session_t peer_id,u32 flags,u32 mask)1687 void Server::SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask)
1688 {
1689 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1690
1691 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1692
1693 pkt << flags << mask;
1694
1695 Send(&pkt);
1696 }
1697
SendHUDSetParam(session_t peer_id,u16 param,const std::string & value)1698 void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &value)
1699 {
1700 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1701 pkt << param << value;
1702 Send(&pkt);
1703 }
1704
SendSetSky(session_t peer_id,const SkyboxParams & params)1705 void Server::SendSetSky(session_t peer_id, const SkyboxParams ¶ms)
1706 {
1707 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1708
1709 // Handle prior clients here
1710 if (m_clients.getProtocolVersion(peer_id) < 39) {
1711 pkt << params.bgcolor << params.type << (u16) params.textures.size();
1712
1713 for (const std::string& texture : params.textures)
1714 pkt << texture;
1715
1716 pkt << params.clouds;
1717 } else { // Handle current clients and future clients
1718 pkt << params.bgcolor << params.type
1719 << params.clouds << params.fog_sun_tint
1720 << params.fog_moon_tint << params.fog_tint_type;
1721
1722 if (params.type == "skybox") {
1723 pkt << (u16) params.textures.size();
1724 for (const std::string &texture : params.textures)
1725 pkt << texture;
1726 } else if (params.type == "regular") {
1727 pkt << params.sky_color.day_sky << params.sky_color.day_horizon
1728 << params.sky_color.dawn_sky << params.sky_color.dawn_horizon
1729 << params.sky_color.night_sky << params.sky_color.night_horizon
1730 << params.sky_color.indoors;
1731 }
1732 }
1733
1734 Send(&pkt);
1735 }
1736
SendSetSun(session_t peer_id,const SunParams & params)1737 void Server::SendSetSun(session_t peer_id, const SunParams ¶ms)
1738 {
1739 NetworkPacket pkt(TOCLIENT_SET_SUN, 0, peer_id);
1740 pkt << params.visible << params.texture
1741 << params.tonemap << params.sunrise
1742 << params.sunrise_visible << params.scale;
1743
1744 Send(&pkt);
1745 }
SendSetMoon(session_t peer_id,const MoonParams & params)1746 void Server::SendSetMoon(session_t peer_id, const MoonParams ¶ms)
1747 {
1748 NetworkPacket pkt(TOCLIENT_SET_MOON, 0, peer_id);
1749
1750 pkt << params.visible << params.texture
1751 << params.tonemap << params.scale;
1752
1753 Send(&pkt);
1754 }
SendSetStars(session_t peer_id,const StarParams & params)1755 void Server::SendSetStars(session_t peer_id, const StarParams ¶ms)
1756 {
1757 NetworkPacket pkt(TOCLIENT_SET_STARS, 0, peer_id);
1758
1759 pkt << params.visible << params.count
1760 << params.starcolor << params.scale;
1761
1762 Send(&pkt);
1763 }
1764
SendCloudParams(session_t peer_id,const CloudParams & params)1765 void Server::SendCloudParams(session_t peer_id, const CloudParams ¶ms)
1766 {
1767 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1768 pkt << params.density << params.color_bright << params.color_ambient
1769 << params.height << params.thickness << params.speed;
1770 Send(&pkt);
1771 }
1772
SendOverrideDayNightRatio(session_t peer_id,bool do_override,float ratio)1773 void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override,
1774 float ratio)
1775 {
1776 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1777 1 + 2, peer_id);
1778
1779 pkt << do_override << (u16) (ratio * 65535);
1780
1781 Send(&pkt);
1782 }
1783
SendTimeOfDay(session_t peer_id,u16 time,f32 time_speed)1784 void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
1785 {
1786 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1787 pkt << time << time_speed;
1788
1789 if (peer_id == PEER_ID_INEXISTENT) {
1790 m_clients.sendToAll(&pkt);
1791 }
1792 else {
1793 Send(&pkt);
1794 }
1795 }
1796
SendPlayerHP(session_t peer_id)1797 void Server::SendPlayerHP(session_t peer_id)
1798 {
1799 PlayerSAO *playersao = getPlayerSAO(peer_id);
1800 assert(playersao);
1801
1802 SendHP(peer_id, playersao->getHP());
1803 m_script->player_event(playersao,"health_changed");
1804
1805 // Send to other clients
1806 playersao->sendPunchCommand();
1807 }
1808
SendPlayerBreath(PlayerSAO * sao)1809 void Server::SendPlayerBreath(PlayerSAO *sao)
1810 {
1811 assert(sao);
1812
1813 m_script->player_event(sao, "breath_changed");
1814 SendBreath(sao->getPeerID(), sao->getBreath());
1815 }
1816
SendMovePlayer(session_t peer_id)1817 void Server::SendMovePlayer(session_t peer_id)
1818 {
1819 RemotePlayer *player = m_env->getPlayer(peer_id);
1820 assert(player);
1821 PlayerSAO *sao = player->getPlayerSAO();
1822 assert(sao);
1823
1824 // Send attachment updates instantly to the client prior updating position
1825 sao->sendOutdatedData();
1826
1827 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1828 pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
1829
1830 {
1831 v3f pos = sao->getBasePosition();
1832 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1833 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1834 << " pitch=" << sao->getLookPitch()
1835 << " yaw=" << sao->getRotation().Y
1836 << std::endl;
1837 }
1838
1839 Send(&pkt);
1840 }
1841
SendPlayerFov(session_t peer_id)1842 void Server::SendPlayerFov(session_t peer_id)
1843 {
1844 NetworkPacket pkt(TOCLIENT_FOV, 4 + 1 + 4, peer_id);
1845
1846 PlayerFovSpec fov_spec = m_env->getPlayer(peer_id)->getFov();
1847 pkt << fov_spec.fov << fov_spec.is_multiplier << fov_spec.transition_time;
1848
1849 Send(&pkt);
1850 }
1851
SendLocalPlayerAnimations(session_t peer_id,v2s32 animation_frames[4],f32 animation_speed)1852 void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
1853 f32 animation_speed)
1854 {
1855 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1856 peer_id);
1857
1858 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1859 << animation_frames[3] << animation_speed;
1860
1861 Send(&pkt);
1862 }
1863
SendEyeOffset(session_t peer_id,v3f first,v3f third)1864 void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
1865 {
1866 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1867 pkt << first << third;
1868 Send(&pkt);
1869 }
1870
SendPlayerPrivileges(session_t peer_id)1871 void Server::SendPlayerPrivileges(session_t peer_id)
1872 {
1873 RemotePlayer *player = m_env->getPlayer(peer_id);
1874 assert(player);
1875 if(player->getPeerId() == PEER_ID_INEXISTENT)
1876 return;
1877
1878 std::set<std::string> privs;
1879 m_script->getAuth(player->getName(), NULL, &privs);
1880
1881 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1882 pkt << (u16) privs.size();
1883
1884 for (const std::string &priv : privs) {
1885 pkt << priv;
1886 }
1887
1888 Send(&pkt);
1889 }
1890
SendPlayerInventoryFormspec(session_t peer_id)1891 void Server::SendPlayerInventoryFormspec(session_t peer_id)
1892 {
1893 RemotePlayer *player = m_env->getPlayer(peer_id);
1894 assert(player);
1895 if (player->getPeerId() == PEER_ID_INEXISTENT)
1896 return;
1897
1898 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1899 pkt.putLongString(player->inventory_formspec);
1900
1901 Send(&pkt);
1902 }
1903
SendPlayerFormspecPrepend(session_t peer_id)1904 void Server::SendPlayerFormspecPrepend(session_t peer_id)
1905 {
1906 RemotePlayer *player = m_env->getPlayer(peer_id);
1907 assert(player);
1908 if (player->getPeerId() == PEER_ID_INEXISTENT)
1909 return;
1910
1911 NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
1912 pkt << player->formspec_prepend;
1913 Send(&pkt);
1914 }
1915
SendActiveObjectRemoveAdd(RemoteClient * client,PlayerSAO * playersao)1916 void Server::SendActiveObjectRemoveAdd(RemoteClient *client, PlayerSAO *playersao)
1917 {
1918 // Radius inside which objects are active
1919 static thread_local const s16 radius =
1920 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
1921
1922 // Radius inside which players are active
1923 static thread_local const bool is_transfer_limited =
1924 g_settings->exists("unlimited_player_transfer_distance") &&
1925 !g_settings->getBool("unlimited_player_transfer_distance");
1926
1927 static thread_local const s16 player_transfer_dist =
1928 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
1929
1930 s16 player_radius = player_transfer_dist == 0 && is_transfer_limited ?
1931 radius : player_transfer_dist;
1932
1933 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
1934 if (my_radius <= 0)
1935 my_radius = radius;
1936
1937 std::queue<u16> removed_objects, added_objects;
1938 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
1939 client->m_known_objects, removed_objects);
1940 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
1941 client->m_known_objects, added_objects);
1942
1943 int removed_count = removed_objects.size();
1944 int added_count = added_objects.size();
1945
1946 if (removed_objects.empty() && added_objects.empty())
1947 return;
1948
1949 char buf[4];
1950 std::string data;
1951
1952 // Handle removed objects
1953 writeU16((u8*)buf, removed_objects.size());
1954 data.append(buf, 2);
1955 while (!removed_objects.empty()) {
1956 // Get object
1957 u16 id = removed_objects.front();
1958 ServerActiveObject* obj = m_env->getActiveObject(id);
1959
1960 // Add to data buffer for sending
1961 writeU16((u8*)buf, id);
1962 data.append(buf, 2);
1963
1964 // Remove from known objects
1965 client->m_known_objects.erase(id);
1966
1967 if (obj && obj->m_known_by_count > 0)
1968 obj->m_known_by_count--;
1969
1970 removed_objects.pop();
1971 }
1972
1973 // Handle added objects
1974 writeU16((u8*)buf, added_objects.size());
1975 data.append(buf, 2);
1976 while (!added_objects.empty()) {
1977 // Get object
1978 u16 id = added_objects.front();
1979 ServerActiveObject *obj = m_env->getActiveObject(id);
1980 added_objects.pop();
1981
1982 if (!obj) {
1983 warningstream << FUNCTION_NAME << ": NULL object id="
1984 << (int)id << std::endl;
1985 continue;
1986 }
1987
1988 // Get object type
1989 u8 type = obj->getSendType();
1990
1991 // Add to data buffer for sending
1992 writeU16((u8*)buf, id);
1993 data.append(buf, 2);
1994 writeU8((u8*)buf, type);
1995 data.append(buf, 1);
1996
1997 data.append(serializeString32(
1998 obj->getClientInitializationData(client->net_proto_version)));
1999
2000 // Add to known objects
2001 client->m_known_objects.insert(id);
2002
2003 obj->m_known_by_count++;
2004 }
2005
2006 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, data.size(), client->peer_id);
2007 pkt.putRawString(data.c_str(), data.size());
2008 Send(&pkt);
2009
2010 verbosestream << "Server::SendActiveObjectRemoveAdd: "
2011 << removed_count << " removed, " << added_count << " added, "
2012 << "packet size is " << pkt.getSize() << std::endl;
2013 }
2014
SendActiveObjectMessages(session_t peer_id,const std::string & datas,bool reliable)2015 void Server::SendActiveObjectMessages(session_t peer_id, const std::string &datas,
2016 bool reliable)
2017 {
2018 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
2019 datas.size(), peer_id);
2020
2021 pkt.putRawString(datas.c_str(), datas.size());
2022
2023 m_clients.send(pkt.getPeerId(),
2024 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
2025 &pkt, reliable);
2026 }
2027
SendCSMRestrictionFlags(session_t peer_id)2028 void Server::SendCSMRestrictionFlags(session_t peer_id)
2029 {
2030 NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS,
2031 sizeof(m_csm_restriction_flags) + sizeof(m_csm_restriction_noderange), peer_id);
2032 pkt << m_csm_restriction_flags << m_csm_restriction_noderange;
2033 Send(&pkt);
2034 }
2035
SendPlayerSpeed(session_t peer_id,const v3f & added_vel)2036 void Server::SendPlayerSpeed(session_t peer_id, const v3f &added_vel)
2037 {
2038 NetworkPacket pkt(TOCLIENT_PLAYER_SPEED, 0, peer_id);
2039 pkt << added_vel;
2040 Send(&pkt);
2041 }
2042
nextSoundId()2043 inline s32 Server::nextSoundId()
2044 {
2045 s32 ret = m_next_sound_id;
2046 if (m_next_sound_id == INT32_MAX)
2047 m_next_sound_id = 0; // signed overflow is undefined
2048 else
2049 m_next_sound_id++;
2050 return ret;
2051 }
2052
playSound(const SimpleSoundSpec & spec,const ServerSoundParams & params,bool ephemeral)2053 s32 Server::playSound(const SimpleSoundSpec &spec,
2054 const ServerSoundParams ¶ms, bool ephemeral)
2055 {
2056 // Find out initial position of sound
2057 bool pos_exists = false;
2058 v3f pos = params.getPos(m_env, &pos_exists);
2059 // If position is not found while it should be, cancel sound
2060 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
2061 return -1;
2062
2063 // Filter destination clients
2064 std::vector<session_t> dst_clients;
2065 if (!params.to_player.empty()) {
2066 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2067 if(!player){
2068 infostream<<"Server::playSound: Player \""<<params.to_player
2069 <<"\" not found"<<std::endl;
2070 return -1;
2071 }
2072 if (player->getPeerId() == PEER_ID_INEXISTENT) {
2073 infostream<<"Server::playSound: Player \""<<params.to_player
2074 <<"\" not connected"<<std::endl;
2075 return -1;
2076 }
2077 dst_clients.push_back(player->getPeerId());
2078 } else {
2079 std::vector<session_t> clients = m_clients.getClientIDs();
2080
2081 for (const session_t client_id : clients) {
2082 RemotePlayer *player = m_env->getPlayer(client_id);
2083 if (!player)
2084 continue;
2085 if (!params.exclude_player.empty() &&
2086 params.exclude_player == player->getName())
2087 continue;
2088
2089 PlayerSAO *sao = player->getPlayerSAO();
2090 if (!sao)
2091 continue;
2092
2093 if (pos_exists) {
2094 if(sao->getBasePosition().getDistanceFrom(pos) >
2095 params.max_hear_distance)
2096 continue;
2097 }
2098 dst_clients.push_back(client_id);
2099 }
2100 }
2101
2102 if(dst_clients.empty())
2103 return -1;
2104
2105 // Create the sound
2106 s32 id;
2107 ServerPlayingSound *psound = nullptr;
2108 if (ephemeral) {
2109 id = -1; // old clients will still use this, so pick a reserved ID
2110 } else {
2111 id = nextSoundId();
2112 // The sound will exist as a reference in m_playing_sounds
2113 m_playing_sounds[id] = ServerPlayingSound();
2114 psound = &m_playing_sounds[id];
2115 psound->params = params;
2116 psound->spec = spec;
2117 }
2118
2119 float gain = params.gain * spec.gain;
2120 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2121 pkt << id << spec.name << gain
2122 << (u8) params.type << pos << params.object
2123 << params.loop << params.fade << params.pitch
2124 << ephemeral;
2125
2126 bool as_reliable = !ephemeral;
2127
2128 for (const u16 dst_client : dst_clients) {
2129 if (psound)
2130 psound->clients.insert(dst_client);
2131 m_clients.send(dst_client, 0, &pkt, as_reliable);
2132 }
2133 return id;
2134 }
stopSound(s32 handle)2135 void Server::stopSound(s32 handle)
2136 {
2137 // Get sound reference
2138 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2139 m_playing_sounds.find(handle);
2140 if (i == m_playing_sounds.end())
2141 return;
2142 ServerPlayingSound &psound = i->second;
2143
2144 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2145 pkt << handle;
2146
2147 for (std::unordered_set<session_t>::const_iterator si = psound.clients.begin();
2148 si != psound.clients.end(); ++si) {
2149 // Send as reliable
2150 m_clients.send(*si, 0, &pkt, true);
2151 }
2152 // Remove sound reference
2153 m_playing_sounds.erase(i);
2154 }
2155
fadeSound(s32 handle,float step,float gain)2156 void Server::fadeSound(s32 handle, float step, float gain)
2157 {
2158 // Get sound reference
2159 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2160 m_playing_sounds.find(handle);
2161 if (i == m_playing_sounds.end())
2162 return;
2163
2164 ServerPlayingSound &psound = i->second;
2165 psound.params.gain = gain;
2166
2167 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2168 pkt << handle << step << gain;
2169
2170 // Backwards compability
2171 bool play_sound = gain > 0;
2172 ServerPlayingSound compat_psound = psound;
2173 compat_psound.clients.clear();
2174
2175 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2176 compat_pkt << handle;
2177
2178 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2179 it != psound.clients.end();) {
2180 if (m_clients.getProtocolVersion(*it) >= 32) {
2181 // Send as reliable
2182 m_clients.send(*it, 0, &pkt, true);
2183 ++it;
2184 } else {
2185 compat_psound.clients.insert(*it);
2186 // Stop old sound
2187 m_clients.send(*it, 0, &compat_pkt, true);
2188 psound.clients.erase(it++);
2189 }
2190 }
2191
2192 // Remove sound reference
2193 if (!play_sound || psound.clients.empty())
2194 m_playing_sounds.erase(i);
2195
2196 if (play_sound && !compat_psound.clients.empty()) {
2197 // Play new sound volume on older clients
2198 playSound(compat_psound.spec, compat_psound.params);
2199 }
2200 }
2201
sendRemoveNode(v3s16 p,std::unordered_set<u16> * far_players,float far_d_nodes)2202 void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
2203 float far_d_nodes)
2204 {
2205 float maxd = far_d_nodes * BS;
2206 v3f p_f = intToFloat(p, BS);
2207 v3s16 block_pos = getNodeBlockPos(p);
2208
2209 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2210 pkt << p;
2211
2212 std::vector<session_t> clients = m_clients.getClientIDs();
2213 m_clients.lock();
2214
2215 for (session_t client_id : clients) {
2216 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2217 if (!client)
2218 continue;
2219
2220 RemotePlayer *player = m_env->getPlayer(client_id);
2221 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2222
2223 // If player is far away, only set modified blocks not sent
2224 if (!client->isBlockSent(block_pos) || (sao &&
2225 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2226 if (far_players)
2227 far_players->emplace(client_id);
2228 else
2229 client->SetBlockNotSent(block_pos);
2230 continue;
2231 }
2232
2233 // Send as reliable
2234 m_clients.send(client_id, 0, &pkt, true);
2235 }
2236
2237 m_clients.unlock();
2238 }
2239
sendAddNode(v3s16 p,MapNode n,std::unordered_set<u16> * far_players,float far_d_nodes,bool remove_metadata)2240 void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
2241 float far_d_nodes, bool remove_metadata)
2242 {
2243 float maxd = far_d_nodes * BS;
2244 v3f p_f = intToFloat(p, BS);
2245 v3s16 block_pos = getNodeBlockPos(p);
2246
2247 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2248 pkt << p << n.param0 << n.param1 << n.param2
2249 << (u8) (remove_metadata ? 0 : 1);
2250
2251 std::vector<session_t> clients = m_clients.getClientIDs();
2252 m_clients.lock();
2253
2254 for (session_t client_id : clients) {
2255 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2256 if (!client)
2257 continue;
2258
2259 RemotePlayer *player = m_env->getPlayer(client_id);
2260 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2261
2262 // If player is far away, only set modified blocks not sent
2263 if (!client->isBlockSent(block_pos) || (sao &&
2264 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2265 if (far_players)
2266 far_players->emplace(client_id);
2267 else
2268 client->SetBlockNotSent(block_pos);
2269 continue;
2270 }
2271
2272 // Send as reliable
2273 m_clients.send(client_id, 0, &pkt, true);
2274 }
2275
2276 m_clients.unlock();
2277 }
2278
sendMetadataChanged(const std::list<v3s16> & meta_updates,float far_d_nodes)2279 void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far_d_nodes)
2280 {
2281 float maxd = far_d_nodes * BS;
2282 NodeMetadataList meta_updates_list(false);
2283 std::vector<session_t> clients = m_clients.getClientIDs();
2284
2285 m_clients.lock();
2286
2287 for (session_t i : clients) {
2288 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2289 if (!client)
2290 continue;
2291
2292 ServerActiveObject *player = m_env->getActiveObject(i);
2293 v3f player_pos = player ? player->getBasePosition() : v3f();
2294
2295 for (const v3s16 &pos : meta_updates) {
2296 NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos);
2297
2298 if (!meta)
2299 continue;
2300
2301 v3s16 block_pos = getNodeBlockPos(pos);
2302 if (!client->isBlockSent(block_pos) || (player &&
2303 player_pos.getDistanceFrom(intToFloat(pos, BS)) > maxd)) {
2304 client->SetBlockNotSent(block_pos);
2305 continue;
2306 }
2307
2308 // Add the change to send list
2309 meta_updates_list.set(pos, meta);
2310 }
2311 if (meta_updates_list.size() == 0)
2312 continue;
2313
2314 // Send the meta changes
2315 std::ostringstream os(std::ios::binary);
2316 meta_updates_list.serialize(os, client->net_proto_version, false, true);
2317 std::ostringstream oss(std::ios::binary);
2318 compressZlib(os.str(), oss);
2319
2320 NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0);
2321 pkt.putLongString(oss.str());
2322 m_clients.send(i, 0, &pkt, true);
2323
2324 meta_updates_list.clear();
2325 }
2326
2327 m_clients.unlock();
2328 }
2329
SendBlockNoLock(session_t peer_id,MapBlock * block,u8 ver,u16 net_proto_version)2330 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
2331 u16 net_proto_version)
2332 {
2333 /*
2334 Create a packet with the block in the right format
2335 */
2336 thread_local const int net_compression_level = rangelim(g_settings->getS16("map_compression_level_net"), -1, 9);
2337 std::ostringstream os(std::ios_base::binary);
2338 block->serialize(os, ver, false, net_compression_level);
2339 block->serializeNetworkSpecific(os);
2340 std::string s = os.str();
2341
2342 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + s.size(), peer_id);
2343
2344 pkt << block->getPos();
2345 pkt.putRawString(s.c_str(), s.size());
2346 Send(&pkt);
2347 }
2348
SendBlocks(float dtime)2349 void Server::SendBlocks(float dtime)
2350 {
2351 MutexAutoLock envlock(m_env_mutex);
2352 //TODO check if one big lock could be faster then multiple small ones
2353
2354 std::vector<PrioritySortedBlockTransfer> queue;
2355
2356 u32 total_sending = 0;
2357
2358 {
2359 ScopeProfiler sp2(g_profiler, "Server::SendBlocks(): Collect list");
2360
2361 std::vector<session_t> clients = m_clients.getClientIDs();
2362
2363 m_clients.lock();
2364 for (const session_t client_id : clients) {
2365 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2366
2367 if (!client)
2368 continue;
2369
2370 total_sending += client->getSendingCount();
2371 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2372 }
2373 m_clients.unlock();
2374 }
2375
2376 // Sort.
2377 // Lowest priority number comes first.
2378 // Lowest is most important.
2379 std::sort(queue.begin(), queue.end());
2380
2381 m_clients.lock();
2382
2383 // Maximal total count calculation
2384 // The per-client block sends is halved with the maximal online users
2385 u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2386 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2387
2388 ScopeProfiler sp(g_profiler, "Server::SendBlocks(): Send to clients");
2389 Map &map = m_env->getMap();
2390
2391 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2392 if (total_sending >= max_blocks_to_send)
2393 break;
2394
2395 MapBlock *block = map.getBlockNoCreateNoEx(block_to_send.pos);
2396 if (!block)
2397 continue;
2398
2399 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2400 CS_Active);
2401 if (!client)
2402 continue;
2403
2404 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2405 client->net_proto_version);
2406
2407 client->SentBlock(block_to_send.pos);
2408 total_sending++;
2409 }
2410 m_clients.unlock();
2411 }
2412
SendBlock(session_t peer_id,const v3s16 & blockpos)2413 bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos)
2414 {
2415 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2416 if (!block)
2417 return false;
2418
2419 m_clients.lock();
2420 RemoteClient *client = m_clients.lockedGetClientNoEx(peer_id, CS_Active);
2421 if (!client || client->isBlockSent(blockpos)) {
2422 m_clients.unlock();
2423 return false;
2424 }
2425 SendBlockNoLock(peer_id, block, client->serialization_version,
2426 client->net_proto_version);
2427 m_clients.unlock();
2428
2429 return true;
2430 }
2431
addMediaFile(const std::string & filename,const std::string & filepath,std::string * filedata_to,std::string * digest_to)2432 bool Server::addMediaFile(const std::string &filename,
2433 const std::string &filepath, std::string *filedata_to,
2434 std::string *digest_to)
2435 {
2436 // If name contains illegal characters, ignore the file
2437 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2438 infostream << "Server: ignoring illegal file name: \""
2439 << filename << "\"" << std::endl;
2440 return false;
2441 }
2442 // If name is not in a supported format, ignore it
2443 const char *supported_ext[] = {
2444 ".png", ".jpg", ".bmp", ".tga",
2445 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2446 ".ogg",
2447 ".x", ".b3d", ".md2", ".obj",
2448 // Custom translation file format
2449 ".tr",
2450 NULL
2451 };
2452 if (removeStringEnd(filename, supported_ext).empty()) {
2453 infostream << "Server: ignoring unsupported file extension: \""
2454 << filename << "\"" << std::endl;
2455 return false;
2456 }
2457 // Ok, attempt to load the file and add to cache
2458
2459 // Read data
2460 std::string filedata;
2461 if (!fs::ReadFile(filepath, filedata)) {
2462 errorstream << "Server::addMediaFile(): Failed to open \""
2463 << filename << "\" for reading" << std::endl;
2464 return false;
2465 }
2466
2467 if (filedata.empty()) {
2468 errorstream << "Server::addMediaFile(): Empty file \""
2469 << filepath << "\"" << std::endl;
2470 return false;
2471 }
2472
2473 SHA1 sha1;
2474 sha1.addBytes(filedata.c_str(), filedata.length());
2475
2476 unsigned char *digest = sha1.getDigest();
2477 std::string sha1_base64 = base64_encode(digest, 20);
2478 std::string sha1_hex = hex_encode((char*) digest, 20);
2479 if (digest_to)
2480 *digest_to = std::string((char*) digest, 20);
2481 free(digest);
2482
2483 // Put in list
2484 m_media[filename] = MediaInfo(filepath, sha1_base64);
2485 verbosestream << "Server: " << sha1_hex << " is " << filename
2486 << std::endl;
2487
2488 if (filedata_to)
2489 *filedata_to = std::move(filedata);
2490 return true;
2491 }
2492
fillMediaCache()2493 void Server::fillMediaCache()
2494 {
2495 infostream << "Server: Calculating media file checksums" << std::endl;
2496
2497 // Collect all media file paths
2498 std::vector<std::string> paths;
2499 // The paths are ordered in descending priority
2500 fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2501 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2502 m_modmgr->getModsMediaPaths(paths);
2503
2504 // Collect media file information from paths into cache
2505 for (const std::string &mediapath : paths) {
2506 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2507 for (const fs::DirListNode &dln : dirlist) {
2508 if (dln.dir) // Ignore dirs (already in paths)
2509 continue;
2510
2511 const std::string &filename = dln.name;
2512 if (m_media.find(filename) != m_media.end()) // Do not override
2513 continue;
2514
2515 std::string filepath = mediapath;
2516 filepath.append(DIR_DELIM).append(filename);
2517 addMediaFile(filename, filepath);
2518 }
2519 }
2520
2521 infostream << "Server: " << m_media.size() << " media files collected" << std::endl;
2522 }
2523
sendMediaAnnouncement(session_t peer_id,const std::string & lang_code)2524 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2525 {
2526 // Make packet
2527 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2528
2529 u16 media_sent = 0;
2530 std::string lang_suffix;
2531 lang_suffix.append(".").append(lang_code).append(".tr");
2532 for (const auto &i : m_media) {
2533 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2534 continue;
2535 media_sent++;
2536 }
2537
2538 pkt << media_sent;
2539
2540 for (const auto &i : m_media) {
2541 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2542 continue;
2543 pkt << i.first << i.second.sha1_digest;
2544 }
2545
2546 pkt << g_settings->get("remote_media");
2547 Send(&pkt);
2548
2549 verbosestream << "Server: Announcing files to id(" << peer_id
2550 << "): count=" << media_sent << " size=" << pkt.getSize() << std::endl;
2551 }
2552
2553 struct SendableMedia
2554 {
2555 std::string name;
2556 std::string path;
2557 std::string data;
2558
SendableMediaSendableMedia2559 SendableMedia(const std::string &name_="", const std::string &path_="",
2560 const std::string &data_=""):
2561 name(name_),
2562 path(path_),
2563 data(data_)
2564 {}
2565 };
2566
sendRequestedMedia(session_t peer_id,const std::vector<std::string> & tosend)2567 void Server::sendRequestedMedia(session_t peer_id,
2568 const std::vector<std::string> &tosend)
2569 {
2570 verbosestream<<"Server::sendRequestedMedia(): "
2571 <<"Sending files to client"<<std::endl;
2572
2573 /* Read files */
2574
2575 // Put 5kB in one bunch (this is not accurate)
2576 u32 bytes_per_bunch = 5000;
2577
2578 std::vector< std::vector<SendableMedia> > file_bunches;
2579 file_bunches.emplace_back();
2580
2581 u32 file_size_bunch_total = 0;
2582
2583 for (const std::string &name : tosend) {
2584 if (m_media.find(name) == m_media.end()) {
2585 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2586 <<"unknown file \""<<(name)<<"\""<<std::endl;
2587 continue;
2588 }
2589
2590 //TODO get path + name
2591 std::string tpath = m_media[name].path;
2592
2593 // Read data
2594 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2595 if(!fis.good()){
2596 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2597 <<tpath<<"\" for reading"<<std::endl;
2598 continue;
2599 }
2600 std::ostringstream tmp_os(std::ios_base::binary);
2601 bool bad = false;
2602 for(;;) {
2603 char buf[1024];
2604 fis.read(buf, 1024);
2605 std::streamsize len = fis.gcount();
2606 tmp_os.write(buf, len);
2607 file_size_bunch_total += len;
2608 if(fis.eof())
2609 break;
2610 if(!fis.good()) {
2611 bad = true;
2612 break;
2613 }
2614 }
2615 if (bad) {
2616 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2617 <<name<<"\""<<std::endl;
2618 continue;
2619 }
2620 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2621 <<tname<<"\""<<std::endl;*/
2622 // Put in list
2623 file_bunches[file_bunches.size()-1].emplace_back(name, tpath, tmp_os.str());
2624
2625 // Start next bunch if got enough data
2626 if(file_size_bunch_total >= bytes_per_bunch) {
2627 file_bunches.emplace_back();
2628 file_size_bunch_total = 0;
2629 }
2630
2631 }
2632
2633 /* Create and send packets */
2634
2635 u16 num_bunches = file_bunches.size();
2636 for (u16 i = 0; i < num_bunches; i++) {
2637 /*
2638 u16 command
2639 u16 total number of texture bunches
2640 u16 index of this bunch
2641 u32 number of files in this bunch
2642 for each file {
2643 u16 length of name
2644 string name
2645 u32 length of data
2646 data
2647 }
2648 */
2649
2650 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2651 pkt << num_bunches << i << (u32) file_bunches[i].size();
2652
2653 for (const SendableMedia &j : file_bunches[i]) {
2654 pkt << j.name;
2655 pkt.putLongString(j.data);
2656 }
2657
2658 verbosestream << "Server::sendRequestedMedia(): bunch "
2659 << i << "/" << num_bunches
2660 << " files=" << file_bunches[i].size()
2661 << " size=" << pkt.getSize() << std::endl;
2662 Send(&pkt);
2663 }
2664 }
2665
SendMinimapModes(session_t peer_id,std::vector<MinimapMode> & modes,size_t wanted_mode)2666 void Server::SendMinimapModes(session_t peer_id,
2667 std::vector<MinimapMode> &modes, size_t wanted_mode)
2668 {
2669 RemotePlayer *player = m_env->getPlayer(peer_id);
2670 assert(player);
2671 if (player->getPeerId() == PEER_ID_INEXISTENT)
2672 return;
2673
2674 NetworkPacket pkt(TOCLIENT_MINIMAP_MODES, 0, peer_id);
2675 pkt << (u16)modes.size() << (u16)wanted_mode;
2676
2677 for (auto &mode : modes)
2678 pkt << (u16)mode.type << mode.label << mode.size << mode.texture << mode.scale;
2679
2680 Send(&pkt);
2681 }
2682
sendDetachedInventory(Inventory * inventory,const std::string & name,session_t peer_id)2683 void Server::sendDetachedInventory(Inventory *inventory, const std::string &name, session_t peer_id)
2684 {
2685 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2686 pkt << name;
2687
2688 if (!inventory) {
2689 pkt << false; // Remove inventory
2690 } else {
2691 pkt << true; // Update inventory
2692
2693 // Serialization & NetworkPacket isn't a love story
2694 std::ostringstream os(std::ios_base::binary);
2695 inventory->serialize(os);
2696 inventory->setModified(false);
2697
2698 const std::string &os_str = os.str();
2699 pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
2700 pkt.putRawString(os_str);
2701 }
2702
2703 if (peer_id == PEER_ID_INEXISTENT)
2704 m_clients.sendToAll(&pkt);
2705 else
2706 Send(&pkt);
2707 }
2708
sendDetachedInventories(session_t peer_id,bool incremental)2709 void Server::sendDetachedInventories(session_t peer_id, bool incremental)
2710 {
2711 // Lookup player name, to filter detached inventories just after
2712 std::string peer_name;
2713 if (peer_id != PEER_ID_INEXISTENT) {
2714 peer_name = getClient(peer_id, CS_Created)->getName();
2715 }
2716
2717 auto send_cb = [this, peer_id](const std::string &name, Inventory *inv) {
2718 sendDetachedInventory(inv, name, peer_id);
2719 };
2720
2721 m_inventory_mgr->sendDetachedInventories(peer_name, incremental, send_cb);
2722 }
2723
2724 /*
2725 Something random
2726 */
2727
DiePlayer(session_t peer_id,const PlayerHPChangeReason & reason)2728 void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
2729 {
2730 PlayerSAO *playersao = getPlayerSAO(peer_id);
2731 assert(playersao);
2732
2733 infostream << "Server::DiePlayer(): Player "
2734 << playersao->getPlayer()->getName()
2735 << " dies" << std::endl;
2736
2737 playersao->setHP(0, reason);
2738 playersao->clearParentAttachment();
2739
2740 // Trigger scripted stuff
2741 m_script->on_dieplayer(playersao, reason);
2742
2743 SendPlayerHP(peer_id);
2744 SendDeathscreen(peer_id, false, v3f(0,0,0));
2745 }
2746
RespawnPlayer(session_t peer_id)2747 void Server::RespawnPlayer(session_t peer_id)
2748 {
2749 PlayerSAO *playersao = getPlayerSAO(peer_id);
2750 assert(playersao);
2751
2752 infostream << "Server::RespawnPlayer(): Player "
2753 << playersao->getPlayer()->getName()
2754 << " respawns" << std::endl;
2755
2756 playersao->setHP(playersao->accessObjectProperties()->hp_max,
2757 PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2758 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2759
2760 bool repositioned = m_script->on_respawnplayer(playersao);
2761 if (!repositioned) {
2762 // setPos will send the new position to client
2763 playersao->setPos(findSpawnPos());
2764 }
2765
2766 SendPlayerHP(peer_id);
2767 }
2768
2769
DenySudoAccess(session_t peer_id)2770 void Server::DenySudoAccess(session_t peer_id)
2771 {
2772 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2773 Send(&pkt);
2774 }
2775
2776
DenyAccessVerCompliant(session_t peer_id,u16 proto_ver,AccessDeniedCode reason,const std::string & str_reason,bool reconnect)2777 void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason,
2778 const std::string &str_reason, bool reconnect)
2779 {
2780 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2781
2782 m_clients.event(peer_id, CSE_SetDenied);
2783 DisconnectPeer(peer_id);
2784 }
2785
2786
DenyAccess(session_t peer_id,AccessDeniedCode reason,const std::string & custom_reason)2787 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2788 const std::string &custom_reason)
2789 {
2790 SendAccessDenied(peer_id, reason, custom_reason);
2791 m_clients.event(peer_id, CSE_SetDenied);
2792 DisconnectPeer(peer_id);
2793 }
2794
2795 // 13/03/15: remove this function when protocol version 25 will become
2796 // the minimum version for MT users, maybe in 1 year
DenyAccess_Legacy(session_t peer_id,const std::wstring & reason)2797 void Server::DenyAccess_Legacy(session_t peer_id, const std::wstring &reason)
2798 {
2799 SendAccessDenied_Legacy(peer_id, reason);
2800 m_clients.event(peer_id, CSE_SetDenied);
2801 DisconnectPeer(peer_id);
2802 }
2803
DisconnectPeer(session_t peer_id)2804 void Server::DisconnectPeer(session_t peer_id)
2805 {
2806 m_modchannel_mgr->leaveAllChannels(peer_id);
2807 m_con->DisconnectPeer(peer_id);
2808 }
2809
acceptAuth(session_t peer_id,bool forSudoMode)2810 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2811 {
2812 if (!forSudoMode) {
2813 RemoteClient* client = getClient(peer_id, CS_Invalid);
2814
2815 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2816
2817 // Right now, the auth mechs don't change between login and sudo mode.
2818 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2819 client->allowed_sudo_mechs = sudo_auth_mechs;
2820
2821 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2822 << g_settings->getFloat("dedicated_server_step")
2823 << sudo_auth_mechs;
2824
2825 Send(&resp_pkt);
2826 m_clients.event(peer_id, CSE_AuthAccept);
2827 } else {
2828 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2829
2830 // We only support SRP right now
2831 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2832
2833 resp_pkt << sudo_auth_mechs;
2834 Send(&resp_pkt);
2835 m_clients.event(peer_id, CSE_SudoSuccess);
2836 }
2837 }
2838
DeleteClient(session_t peer_id,ClientDeletionReason reason)2839 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2840 {
2841 std::wstring message;
2842 {
2843 /*
2844 Clear references to playing sounds
2845 */
2846 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2847 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2848 ServerPlayingSound &psound = i->second;
2849 psound.clients.erase(peer_id);
2850 if (psound.clients.empty())
2851 m_playing_sounds.erase(i++);
2852 else
2853 ++i;
2854 }
2855
2856 // clear formspec info so the next client can't abuse the current state
2857 m_formspec_state_data.erase(peer_id);
2858
2859 RemotePlayer *player = m_env->getPlayer(peer_id);
2860
2861 /* Run scripts and remove from environment */
2862 if (player) {
2863 PlayerSAO *playersao = player->getPlayerSAO();
2864 assert(playersao);
2865
2866 playersao->clearChildAttachments();
2867 playersao->clearParentAttachment();
2868
2869 // inform connected clients
2870 const std::string &player_name = player->getName();
2871 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2872 // (u16) 1 + std::string represents a vector serialization representation
2873 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << player_name;
2874 m_clients.sendToAll(¬ice);
2875 // run scripts
2876 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2877
2878 playersao->disconnected();
2879 }
2880
2881 /*
2882 Print out action
2883 */
2884 {
2885 if (player && reason != CDR_DENY) {
2886 std::ostringstream os(std::ios_base::binary);
2887 std::vector<session_t> clients = m_clients.getClientIDs();
2888
2889 for (const session_t client_id : clients) {
2890 // Get player
2891 RemotePlayer *player = m_env->getPlayer(client_id);
2892 if (!player)
2893 continue;
2894
2895 // Get name of player
2896 os << player->getName() << " ";
2897 }
2898
2899 std::string name = player->getName();
2900 actionstream << name << " "
2901 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2902 << " List of players: " << os.str() << std::endl;
2903 if (m_admin_chat)
2904 m_admin_chat->outgoing_queue.push_back(
2905 new ChatEventNick(CET_NICK_REMOVE, name));
2906 }
2907 }
2908 {
2909 MutexAutoLock env_lock(m_env_mutex);
2910 m_clients.DeleteClient(peer_id);
2911 }
2912 }
2913
2914 // Send leave chat message to all remaining clients
2915 if (!message.empty()) {
2916 SendChatMessage(PEER_ID_INEXISTENT,
2917 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2918 }
2919 }
2920
UpdateCrafting(RemotePlayer * player)2921 void Server::UpdateCrafting(RemotePlayer *player)
2922 {
2923 InventoryList *clist = player->inventory.getList("craft");
2924 if (!clist || clist->getSize() == 0)
2925 return;
2926
2927 if (!clist->checkModified())
2928 return;
2929
2930 // Get a preview for crafting
2931 ItemStack preview;
2932 InventoryLocation loc;
2933 loc.setPlayer(player->getName());
2934 std::vector<ItemStack> output_replacements;
2935 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2936 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2937 clist, loc);
2938
2939 InventoryList *plist = player->inventory.getList("craftpreview");
2940 if (plist && plist->getSize() >= 1) {
2941 // Put the new preview in
2942 plist->changeItem(0, preview);
2943 }
2944 }
2945
handleChatInterfaceEvent(ChatEvent * evt)2946 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2947 {
2948 if (evt->type == CET_NICK_ADD) {
2949 // The terminal informed us of its nick choice
2950 m_admin_nick = ((ChatEventNick *)evt)->nick;
2951 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2952 errorstream << "You haven't set up an account." << std::endl
2953 << "Please log in using the client as '"
2954 << m_admin_nick << "' with a secure password." << std::endl
2955 << "Until then, you can't execute admin tasks via the console," << std::endl
2956 << "and everybody can claim the user account instead of you," << std::endl
2957 << "giving them full control over this server." << std::endl;
2958 }
2959 } else {
2960 assert(evt->type == CET_CHAT);
2961 handleAdminChat((ChatEventChat *)evt);
2962 }
2963 }
2964
handleChat(const std::string & name,std::wstring wmessage,bool check_shout_priv,RemotePlayer * player)2965 std::wstring Server::handleChat(const std::string &name,
2966 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2967 {
2968 // If something goes wrong, this player is to blame
2969 RollbackScopeActor rollback_scope(m_rollback,
2970 std::string("player:") + name);
2971
2972 if (g_settings->getBool("strip_color_codes"))
2973 wmessage = unescape_enriched(wmessage);
2974
2975 if (player) {
2976 switch (player->canSendChatMessage()) {
2977 case RPLAYER_CHATRESULT_FLOODING: {
2978 std::wstringstream ws;
2979 ws << L"You cannot send more messages. You are limited to "
2980 << g_settings->getFloat("chat_message_limit_per_10sec")
2981 << L" messages per 10 seconds.";
2982 return ws.str();
2983 }
2984 case RPLAYER_CHATRESULT_KICK:
2985 DenyAccess_Legacy(player->getPeerId(),
2986 L"You have been kicked due to message flooding.");
2987 return L"";
2988 case RPLAYER_CHATRESULT_OK:
2989 break;
2990 default:
2991 FATAL_ERROR("Unhandled chat filtering result found.");
2992 }
2993 }
2994
2995 if (m_max_chatmessage_length > 0
2996 && wmessage.length() > m_max_chatmessage_length) {
2997 return L"Your message exceed the maximum chat message limit set on the server. "
2998 L"It was refused. Send a shorter message";
2999 }
3000
3001 auto message = trim(wide_to_utf8(wmessage));
3002 if (message.find_first_of("\n\r") != std::wstring::npos) {
3003 return L"Newlines are not permitted in chat messages";
3004 }
3005
3006 // Run script hook, exit if script ate the chat message
3007 if (m_script->on_chat_message(name, message))
3008 return L"";
3009
3010 // Line to send
3011 std::wstring line;
3012 // Whether to send line to the player that sent the message, or to all players
3013 bool broadcast_line = true;
3014
3015 if (check_shout_priv && !checkPriv(name, "shout")) {
3016 line += L"-!- You don't have permission to shout.";
3017 broadcast_line = false;
3018 } else {
3019 /*
3020 Workaround for fixing chat on Android. Lua doesn't handle
3021 the Cyrillic alphabet and some characters on older Android devices
3022 */
3023 #ifdef __ANDROID__
3024 line += L"<" + utf8_to_wide(name) + L"> " + wmessage;
3025 #else
3026 line += utf8_to_wide(m_script->formatChatMessage(name,
3027 wide_to_utf8(wmessage)));
3028 #endif
3029 }
3030
3031 /*
3032 Tell calling method to send the message to sender
3033 */
3034 if (!broadcast_line)
3035 return line;
3036
3037 /*
3038 Send the message to others
3039 */
3040 actionstream << "CHAT: " << wide_to_utf8(unescape_enriched(line)) << std::endl;
3041
3042 ChatMessage chatmsg(line);
3043
3044 std::vector<session_t> clients = m_clients.getClientIDs();
3045 for (u16 cid : clients)
3046 SendChatMessage(cid, chatmsg);
3047
3048 return L"";
3049 }
3050
handleAdminChat(const ChatEventChat * evt)3051 void Server::handleAdminChat(const ChatEventChat *evt)
3052 {
3053 std::string name = evt->nick;
3054 std::wstring wmessage = evt->evt_msg;
3055
3056 std::wstring answer = handleChat(name, wmessage);
3057
3058 // If asked to send answer to sender
3059 if (!answer.empty()) {
3060 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
3061 }
3062 }
3063
getClient(session_t peer_id,ClientState state_min)3064 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
3065 {
3066 RemoteClient *client = getClientNoEx(peer_id,state_min);
3067 if(!client)
3068 throw ClientNotFoundException("Client not found");
3069
3070 return client;
3071 }
getClientNoEx(session_t peer_id,ClientState state_min)3072 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
3073 {
3074 return m_clients.getClientNoEx(peer_id, state_min);
3075 }
3076
getPlayerName(session_t peer_id)3077 std::string Server::getPlayerName(session_t peer_id)
3078 {
3079 RemotePlayer *player = m_env->getPlayer(peer_id);
3080 if (!player)
3081 return "[id="+itos(peer_id)+"]";
3082 return player->getName();
3083 }
3084
getPlayerSAO(session_t peer_id)3085 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
3086 {
3087 RemotePlayer *player = m_env->getPlayer(peer_id);
3088 if (!player)
3089 return NULL;
3090 return player->getPlayerSAO();
3091 }
3092
getStatusString()3093 std::string Server::getStatusString()
3094 {
3095 std::ostringstream os(std::ios_base::binary);
3096 os << "# Server: ";
3097 // Version
3098 os << "version=" << g_version_string;
3099 // Uptime
3100 os << ", uptime=" << m_uptime_counter->get();
3101 // Max lag estimate
3102 os << ", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
3103
3104 // Information about clients
3105 bool first = true;
3106 os << ", clients={";
3107 if (m_env) {
3108 std::vector<session_t> clients = m_clients.getClientIDs();
3109 for (session_t client_id : clients) {
3110 RemotePlayer *player = m_env->getPlayer(client_id);
3111
3112 // Get name of player
3113 const char *name = player ? player->getName() : "<unknown>";
3114
3115 // Add name to information string
3116 if (!first)
3117 os << ", ";
3118 else
3119 first = false;
3120 os << name;
3121 }
3122 }
3123 os << "}";
3124
3125 if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3126 os << std::endl << "# Server: " << " WARNING: Map saving is disabled.";
3127
3128 if (!g_settings->get("motd").empty())
3129 os << std::endl << "# Server: " << g_settings->get("motd");
3130
3131 return os.str();
3132 }
3133
getPlayerEffectivePrivs(const std::string & name)3134 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3135 {
3136 std::set<std::string> privs;
3137 m_script->getAuth(name, NULL, &privs);
3138 return privs;
3139 }
3140
checkPriv(const std::string & name,const std::string & priv)3141 bool Server::checkPriv(const std::string &name, const std::string &priv)
3142 {
3143 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3144 return (privs.count(priv) != 0);
3145 }
3146
reportPrivsModified(const std::string & name)3147 void Server::reportPrivsModified(const std::string &name)
3148 {
3149 if (name.empty()) {
3150 std::vector<session_t> clients = m_clients.getClientIDs();
3151 for (const session_t client_id : clients) {
3152 RemotePlayer *player = m_env->getPlayer(client_id);
3153 reportPrivsModified(player->getName());
3154 }
3155 } else {
3156 RemotePlayer *player = m_env->getPlayer(name.c_str());
3157 if (!player)
3158 return;
3159 SendPlayerPrivileges(player->getPeerId());
3160 PlayerSAO *sao = player->getPlayerSAO();
3161 if(!sao)
3162 return;
3163 sao->updatePrivileges(
3164 getPlayerEffectivePrivs(name),
3165 isSingleplayer());
3166 }
3167 }
3168
reportInventoryFormspecModified(const std::string & name)3169 void Server::reportInventoryFormspecModified(const std::string &name)
3170 {
3171 RemotePlayer *player = m_env->getPlayer(name.c_str());
3172 if (!player)
3173 return;
3174 SendPlayerInventoryFormspec(player->getPeerId());
3175 }
3176
reportFormspecPrependModified(const std::string & name)3177 void Server::reportFormspecPrependModified(const std::string &name)
3178 {
3179 RemotePlayer *player = m_env->getPlayer(name.c_str());
3180 if (!player)
3181 return;
3182 SendPlayerFormspecPrepend(player->getPeerId());
3183 }
3184
setIpBanned(const std::string & ip,const std::string & name)3185 void Server::setIpBanned(const std::string &ip, const std::string &name)
3186 {
3187 m_banmanager->add(ip, name);
3188 }
3189
unsetIpBanned(const std::string & ip_or_name)3190 void Server::unsetIpBanned(const std::string &ip_or_name)
3191 {
3192 m_banmanager->remove(ip_or_name);
3193 }
3194
getBanDescription(const std::string & ip_or_name)3195 std::string Server::getBanDescription(const std::string &ip_or_name)
3196 {
3197 return m_banmanager->getBanDescription(ip_or_name);
3198 }
3199
notifyPlayer(const char * name,const std::wstring & msg)3200 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3201 {
3202 // m_env will be NULL if the server is initializing
3203 if (!m_env)
3204 return;
3205
3206 if (m_admin_nick == name && !m_admin_nick.empty()) {
3207 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3208 }
3209
3210 RemotePlayer *player = m_env->getPlayer(name);
3211 if (!player) {
3212 return;
3213 }
3214
3215 if (player->getPeerId() == PEER_ID_INEXISTENT)
3216 return;
3217
3218 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3219 }
3220
showFormspec(const char * playername,const std::string & formspec,const std::string & formname)3221 bool Server::showFormspec(const char *playername, const std::string &formspec,
3222 const std::string &formname)
3223 {
3224 // m_env will be NULL if the server is initializing
3225 if (!m_env)
3226 return false;
3227
3228 RemotePlayer *player = m_env->getPlayer(playername);
3229 if (!player)
3230 return false;
3231
3232 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3233 return true;
3234 }
3235
hudAdd(RemotePlayer * player,HudElement * form)3236 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3237 {
3238 if (!player)
3239 return -1;
3240
3241 u32 id = player->addHud(form);
3242
3243 SendHUDAdd(player->getPeerId(), id, form);
3244
3245 return id;
3246 }
3247
hudRemove(RemotePlayer * player,u32 id)3248 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3249 if (!player)
3250 return false;
3251
3252 HudElement* todel = player->removeHud(id);
3253
3254 if (!todel)
3255 return false;
3256
3257 delete todel;
3258
3259 SendHUDRemove(player->getPeerId(), id);
3260 return true;
3261 }
3262
hudChange(RemotePlayer * player,u32 id,HudElementStat stat,void * data)3263 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3264 {
3265 if (!player)
3266 return false;
3267
3268 SendHUDChange(player->getPeerId(), id, stat, data);
3269 return true;
3270 }
3271
hudSetFlags(RemotePlayer * player,u32 flags,u32 mask)3272 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3273 {
3274 if (!player)
3275 return false;
3276
3277 SendHUDSetFlags(player->getPeerId(), flags, mask);
3278 player->hud_flags &= ~mask;
3279 player->hud_flags |= flags;
3280
3281 PlayerSAO* playersao = player->getPlayerSAO();
3282
3283 if (!playersao)
3284 return false;
3285
3286 m_script->player_event(playersao, "hud_changed");
3287 return true;
3288 }
3289
hudSetHotbarItemcount(RemotePlayer * player,s32 hotbar_itemcount)3290 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3291 {
3292 if (!player)
3293 return false;
3294
3295 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3296 return false;
3297
3298 player->setHotbarItemcount(hotbar_itemcount);
3299 std::ostringstream os(std::ios::binary);
3300 writeS32(os, hotbar_itemcount);
3301 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3302 return true;
3303 }
3304
hudSetHotbarImage(RemotePlayer * player,const std::string & name)3305 void Server::hudSetHotbarImage(RemotePlayer *player, const std::string &name)
3306 {
3307 if (!player)
3308 return;
3309
3310 player->setHotbarImage(name);
3311 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3312 }
3313
hudSetHotbarSelectedImage(RemotePlayer * player,const std::string & name)3314 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, const std::string &name)
3315 {
3316 if (!player)
3317 return;
3318
3319 player->setHotbarSelectedImage(name);
3320 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3321 }
3322
getPeerAddress(session_t peer_id)3323 Address Server::getPeerAddress(session_t peer_id)
3324 {
3325 // Note that this is only set after Init was received in Server::handleCommand_Init
3326 return getClient(peer_id, CS_Invalid)->getAddress();
3327 }
3328
setLocalPlayerAnimations(RemotePlayer * player,v2s32 animation_frames[4],f32 frame_speed)3329 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3330 v2s32 animation_frames[4], f32 frame_speed)
3331 {
3332 sanity_check(player);
3333 player->setLocalAnimations(animation_frames, frame_speed);
3334 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3335 }
3336
setPlayerEyeOffset(RemotePlayer * player,const v3f & first,const v3f & third)3337 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3338 {
3339 sanity_check(player);
3340 player->eye_offset_first = first;
3341 player->eye_offset_third = third;
3342 SendEyeOffset(player->getPeerId(), first, third);
3343 }
3344
setSky(RemotePlayer * player,const SkyboxParams & params)3345 void Server::setSky(RemotePlayer *player, const SkyboxParams ¶ms)
3346 {
3347 sanity_check(player);
3348 player->setSky(params);
3349 SendSetSky(player->getPeerId(), params);
3350 }
3351
setSun(RemotePlayer * player,const SunParams & params)3352 void Server::setSun(RemotePlayer *player, const SunParams ¶ms)
3353 {
3354 sanity_check(player);
3355 player->setSun(params);
3356 SendSetSun(player->getPeerId(), params);
3357 }
3358
setMoon(RemotePlayer * player,const MoonParams & params)3359 void Server::setMoon(RemotePlayer *player, const MoonParams ¶ms)
3360 {
3361 sanity_check(player);
3362 player->setMoon(params);
3363 SendSetMoon(player->getPeerId(), params);
3364 }
3365
setStars(RemotePlayer * player,const StarParams & params)3366 void Server::setStars(RemotePlayer *player, const StarParams ¶ms)
3367 {
3368 sanity_check(player);
3369 player->setStars(params);
3370 SendSetStars(player->getPeerId(), params);
3371 }
3372
setClouds(RemotePlayer * player,const CloudParams & params)3373 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3374 {
3375 sanity_check(player);
3376 player->setCloudParams(params);
3377 SendCloudParams(player->getPeerId(), params);
3378 }
3379
overrideDayNightRatio(RemotePlayer * player,bool do_override,float ratio)3380 void Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3381 float ratio)
3382 {
3383 sanity_check(player);
3384 player->overrideDayNightRatio(do_override, ratio);
3385 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3386 }
3387
notifyPlayers(const std::wstring & msg)3388 void Server::notifyPlayers(const std::wstring &msg)
3389 {
3390 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3391 }
3392
spawnParticle(const std::string & playername,const ParticleParameters & p)3393 void Server::spawnParticle(const std::string &playername,
3394 const ParticleParameters &p)
3395 {
3396 // m_env will be NULL if the server is initializing
3397 if (!m_env)
3398 return;
3399
3400 session_t peer_id = PEER_ID_INEXISTENT;
3401 u16 proto_ver = 0;
3402 if (!playername.empty()) {
3403 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3404 if (!player)
3405 return;
3406 peer_id = player->getPeerId();
3407 proto_ver = player->protocol_version;
3408 }
3409
3410 SendSpawnParticle(peer_id, proto_ver, p);
3411 }
3412
addParticleSpawner(const ParticleSpawnerParameters & p,ServerActiveObject * attached,const std::string & playername)3413 u32 Server::addParticleSpawner(const ParticleSpawnerParameters &p,
3414 ServerActiveObject *attached, const std::string &playername)
3415 {
3416 // m_env will be NULL if the server is initializing
3417 if (!m_env)
3418 return -1;
3419
3420 session_t peer_id = PEER_ID_INEXISTENT;
3421 u16 proto_ver = 0;
3422 if (!playername.empty()) {
3423 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3424 if (!player)
3425 return -1;
3426 peer_id = player->getPeerId();
3427 proto_ver = player->protocol_version;
3428 }
3429
3430 u16 attached_id = attached ? attached->getId() : 0;
3431
3432 u32 id;
3433 if (attached_id == 0)
3434 id = m_env->addParticleSpawner(p.time);
3435 else
3436 id = m_env->addParticleSpawner(p.time, attached_id);
3437
3438 SendAddParticleSpawner(peer_id, proto_ver, p, attached_id, id);
3439 return id;
3440 }
3441
deleteParticleSpawner(const std::string & playername,u32 id)3442 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3443 {
3444 // m_env will be NULL if the server is initializing
3445 if (!m_env)
3446 throw ServerError("Can't delete particle spawners during initialisation!");
3447
3448 session_t peer_id = PEER_ID_INEXISTENT;
3449 if (!playername.empty()) {
3450 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3451 if (!player)
3452 return;
3453 peer_id = player->getPeerId();
3454 }
3455
3456 m_env->deleteParticleSpawner(id);
3457 SendDeleteParticleSpawner(peer_id, id);
3458 }
3459
dynamicAddMedia(const std::string & filepath,std::vector<RemotePlayer * > & sent_to)3460 bool Server::dynamicAddMedia(const std::string &filepath,
3461 std::vector<RemotePlayer*> &sent_to)
3462 {
3463 std::string filename = fs::GetFilenameFromPath(filepath.c_str());
3464 if (m_media.find(filename) != m_media.end()) {
3465 errorstream << "Server::dynamicAddMedia(): file \"" << filename
3466 << "\" already exists in media cache" << std::endl;
3467 return false;
3468 }
3469
3470 // Load the file and add it to our media cache
3471 std::string filedata, raw_hash;
3472 bool ok = addMediaFile(filename, filepath, &filedata, &raw_hash);
3473 if (!ok)
3474 return false;
3475
3476 // Push file to existing clients
3477 NetworkPacket pkt(TOCLIENT_MEDIA_PUSH, 0);
3478 pkt << raw_hash << filename << (bool) true;
3479 pkt.putLongString(filedata);
3480
3481 m_clients.lock();
3482 for (auto &pair : m_clients.getClientList()) {
3483 if (pair.second->getState() < CS_DefinitionsSent)
3484 continue;
3485 if (pair.second->net_proto_version < 39)
3486 continue;
3487
3488 if (auto player = m_env->getPlayer(pair.second->peer_id))
3489 sent_to.emplace_back(player);
3490 /*
3491 FIXME: this is a very awful hack
3492 The network layer only guarantees ordered delivery inside a channel.
3493 Since the very next packet could be one that uses the media, we have
3494 to push the media over ALL channels to ensure it is processed before
3495 it is used.
3496 In practice this means we have to send it twice:
3497 - channel 1 (HUD)
3498 - channel 0 (everything else: e.g. play_sound, object messages)
3499 */
3500 m_clients.send(pair.second->peer_id, 1, &pkt, true);
3501 m_clients.send(pair.second->peer_id, 0, &pkt, true);
3502 }
3503 m_clients.unlock();
3504
3505 return true;
3506 }
3507
3508 // actions: time-reversed list
3509 // Return value: success/failure
rollbackRevertActions(const std::list<RollbackAction> & actions,std::list<std::string> * log)3510 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3511 std::list<std::string> *log)
3512 {
3513 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3514 ServerMap *map = (ServerMap*)(&m_env->getMap());
3515
3516 // Fail if no actions to handle
3517 if (actions.empty()) {
3518 assert(log);
3519 log->push_back("Nothing to do.");
3520 return false;
3521 }
3522
3523 int num_tried = 0;
3524 int num_failed = 0;
3525
3526 for (const RollbackAction &action : actions) {
3527 num_tried++;
3528 bool success = action.applyRevert(map, m_inventory_mgr.get(), this);
3529 if(!success){
3530 num_failed++;
3531 std::ostringstream os;
3532 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3533 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3534 if (log)
3535 log->push_back(os.str());
3536 }else{
3537 std::ostringstream os;
3538 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3539 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3540 if (log)
3541 log->push_back(os.str());
3542 }
3543 }
3544
3545 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3546 <<" failed"<<std::endl;
3547
3548 // Call it done if less than half failed
3549 return num_failed <= num_tried/2;
3550 }
3551
3552 // IGameDef interface
3553 // Under envlock
getItemDefManager()3554 IItemDefManager *Server::getItemDefManager()
3555 {
3556 return m_itemdef;
3557 }
3558
getNodeDefManager()3559 const NodeDefManager *Server::getNodeDefManager()
3560 {
3561 return m_nodedef;
3562 }
3563
getCraftDefManager()3564 ICraftDefManager *Server::getCraftDefManager()
3565 {
3566 return m_craftdef;
3567 }
3568
allocateUnknownNodeId(const std::string & name)3569 u16 Server::allocateUnknownNodeId(const std::string &name)
3570 {
3571 return m_nodedef->allocateDummy(name);
3572 }
3573
getWritableItemDefManager()3574 IWritableItemDefManager *Server::getWritableItemDefManager()
3575 {
3576 return m_itemdef;
3577 }
3578
getWritableNodeDefManager()3579 NodeDefManager *Server::getWritableNodeDefManager()
3580 {
3581 return m_nodedef;
3582 }
3583
getWritableCraftDefManager()3584 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3585 {
3586 return m_craftdef;
3587 }
3588
getMods() const3589 const std::vector<ModSpec> & Server::getMods() const
3590 {
3591 return m_modmgr->getMods();
3592 }
3593
getModSpec(const std::string & modname) const3594 const ModSpec *Server::getModSpec(const std::string &modname) const
3595 {
3596 return m_modmgr->getModSpec(modname);
3597 }
3598
getModNames(std::vector<std::string> & modlist)3599 void Server::getModNames(std::vector<std::string> &modlist)
3600 {
3601 m_modmgr->getModNames(modlist);
3602 }
3603
getBuiltinLuaPath()3604 std::string Server::getBuiltinLuaPath()
3605 {
3606 return porting::path_share + DIR_DELIM + "builtin";
3607 }
3608
getModStoragePath() const3609 std::string Server::getModStoragePath() const
3610 {
3611 return m_path_world + DIR_DELIM + "mod_storage";
3612 }
3613
findSpawnPos()3614 v3f Server::findSpawnPos()
3615 {
3616 ServerMap &map = m_env->getServerMap();
3617 v3f nodeposf;
3618 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf))
3619 return nodeposf * BS;
3620
3621 bool is_good = false;
3622 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3623 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3624
3625 // Try to find a good place a few times
3626 for (s32 i = 0; i < 4000 && !is_good; i++) {
3627 s32 range = MYMIN(1 + i, range_max);
3628 // We're going to try to throw the player to this position
3629 v2s16 nodepos2d = v2s16(
3630 -range + (myrand() % (range * 2)),
3631 -range + (myrand() % (range * 2)));
3632 // Get spawn level at point
3633 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3634 // Continue if MAX_MAP_GENERATION_LIMIT was returned by the mapgen to
3635 // signify an unsuitable spawn position, or if outside limits.
3636 if (spawn_level >= MAX_MAP_GENERATION_LIMIT ||
3637 spawn_level <= -MAX_MAP_GENERATION_LIMIT)
3638 continue;
3639
3640 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3641 // Consecutive empty nodes
3642 s32 air_count = 0;
3643
3644 // Search upwards from 'spawn level' for 2 consecutive empty nodes, to
3645 // avoid obstructions in already-generated mapblocks.
3646 // In ungenerated mapblocks consisting of 'ignore' nodes, there will be
3647 // no obstructions, but mapgen decorations are generated after spawn so
3648 // the player may end up inside one.
3649 for (s32 i = 0; i < 8; i++) {
3650 v3s16 blockpos = getNodeBlockPos(nodepos);
3651 map.emergeBlock(blockpos, true);
3652 content_t c = map.getNode(nodepos).getContent();
3653
3654 // In generated mapblocks allow spawn in all 'airlike' drawtype nodes.
3655 // In ungenerated mapblocks allow spawn in 'ignore' nodes.
3656 if (m_nodedef->get(c).drawtype == NDT_AIRLIKE || c == CONTENT_IGNORE) {
3657 air_count++;
3658 if (air_count >= 2) {
3659 // Spawn in lower empty node
3660 nodepos.Y--;
3661 nodeposf = intToFloat(nodepos, BS);
3662 // Don't spawn the player outside map boundaries
3663 if (objectpos_over_limit(nodeposf))
3664 // Exit this loop, positions above are probably over limit
3665 break;
3666
3667 // Good position found, cause an exit from main loop
3668 is_good = true;
3669 break;
3670 }
3671 } else {
3672 air_count = 0;
3673 }
3674 nodepos.Y++;
3675 }
3676 }
3677
3678 if (is_good)
3679 return nodeposf;
3680
3681 // No suitable spawn point found, return fallback 0,0,0
3682 return v3f(0.0f, 0.0f, 0.0f);
3683 }
3684
requestShutdown(const std::string & msg,bool reconnect,float delay)3685 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3686 {
3687 if (delay == 0.0f) {
3688 // No delay, shutdown immediately
3689 m_shutdown_state.is_requested = true;
3690 // only print to the infostream, a chat message saying
3691 // "Server Shutting Down" is sent when the server destructs.
3692 infostream << "*** Immediate Server shutdown requested." << std::endl;
3693 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3694 // Negative delay, cancel shutdown if requested
3695 m_shutdown_state.reset();
3696 std::wstringstream ws;
3697
3698 ws << L"*** Server shutdown canceled.";
3699
3700 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3701 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3702 // m_shutdown_* are already handled, skip.
3703 return;
3704 } else if (delay > 0.0f) {
3705 // Positive delay, tell the clients when the server will shut down
3706 std::wstringstream ws;
3707
3708 ws << L"*** Server shutting down in "
3709 << duration_to_string(myround(delay)).c_str()
3710 << ".";
3711
3712 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3713 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3714 }
3715
3716 m_shutdown_state.trigger(delay, msg, reconnect);
3717 }
3718
emergePlayer(const char * name,session_t peer_id,u16 proto_version)3719 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3720 {
3721 /*
3722 Try to get an existing player
3723 */
3724 RemotePlayer *player = m_env->getPlayer(name);
3725
3726 // If player is already connected, cancel
3727 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3728 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3729 return NULL;
3730 }
3731
3732 /*
3733 If player with the wanted peer_id already exists, cancel.
3734 */
3735 if (m_env->getPlayer(peer_id)) {
3736 infostream<<"emergePlayer(): Player with wrong name but same"
3737 " peer_id already exists"<<std::endl;
3738 return NULL;
3739 }
3740
3741 if (!player) {
3742 player = new RemotePlayer(name, idef());
3743 }
3744
3745 bool newplayer = false;
3746
3747 // Load player
3748 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3749
3750 // Complete init with server parts
3751 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3752 player->protocol_version = proto_version;
3753
3754 /* Run scripts */
3755 if (newplayer) {
3756 m_script->on_newplayer(playersao);
3757 }
3758
3759 return playersao;
3760 }
3761
registerModStorage(ModMetadata * storage)3762 bool Server::registerModStorage(ModMetadata *storage)
3763 {
3764 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3765 errorstream << "Unable to register same mod storage twice. Storage name: "
3766 << storage->getModName() << std::endl;
3767 return false;
3768 }
3769
3770 m_mod_storages[storage->getModName()] = storage;
3771 return true;
3772 }
3773
unregisterModStorage(const std::string & name)3774 void Server::unregisterModStorage(const std::string &name)
3775 {
3776 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3777 if (it != m_mod_storages.end()) {
3778 // Save unconditionaly on unregistration
3779 it->second->save(getModStoragePath());
3780 m_mod_storages.erase(name);
3781 }
3782 }
3783
dedicated_server_loop(Server & server,bool & kill)3784 void dedicated_server_loop(Server &server, bool &kill)
3785 {
3786 verbosestream<<"dedicated_server_loop()"<<std::endl;
3787
3788 IntervalLimiter m_profiler_interval;
3789
3790 static thread_local const float steplen =
3791 g_settings->getFloat("dedicated_server_step");
3792 static thread_local const float profiler_print_interval =
3793 g_settings->getFloat("profiler_print_interval");
3794
3795 /*
3796 * The dedicated server loop only does time-keeping (in Server::step) and
3797 * provides a way to main.cpp to kill the server externally (bool &kill).
3798 */
3799
3800 for(;;) {
3801 // This is kind of a hack but can be done like this
3802 // because server.step() is very light
3803 sleep_ms((int)(steplen*1000.0));
3804 server.step(steplen);
3805
3806 if (server.isShutdownRequested() || kill)
3807 break;
3808
3809 /*
3810 Profiler
3811 */
3812 if (profiler_print_interval != 0) {
3813 if(m_profiler_interval.step(steplen, profiler_print_interval))
3814 {
3815 infostream<<"Profiler:"<<std::endl;
3816 g_profiler->print(infostream);
3817 g_profiler->clear();
3818 }
3819 }
3820 }
3821
3822 infostream << "Dedicated server quitting" << std::endl;
3823 #if USE_CURL
3824 if (g_settings->getBool("server_announce"))
3825 ServerList::sendAnnounce(ServerList::AA_DELETE,
3826 server.m_bind_addr.getPort());
3827 #endif
3828 }
3829
3830 /*
3831 * Mod channels
3832 */
3833
3834
joinModChannel(const std::string & channel)3835 bool Server::joinModChannel(const std::string &channel)
3836 {
3837 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3838 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3839 }
3840
leaveModChannel(const std::string & channel)3841 bool Server::leaveModChannel(const std::string &channel)
3842 {
3843 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3844 }
3845
sendModChannelMessage(const std::string & channel,const std::string & message)3846 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3847 {
3848 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3849 return false;
3850
3851 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3852 return true;
3853 }
3854
getModChannel(const std::string & channel)3855 ModChannel* Server::getModChannel(const std::string &channel)
3856 {
3857 return m_modchannel_mgr->getModChannel(channel);
3858 }
3859
broadcastModChannelMessage(const std::string & channel,const std::string & message,session_t from_peer)3860 void Server::broadcastModChannelMessage(const std::string &channel,
3861 const std::string &message, session_t from_peer)
3862 {
3863 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3864 if (peers.empty())
3865 return;
3866
3867 if (message.size() > STRING_MAX_LEN) {
3868 warningstream << "ModChannel message too long, dropping before sending "
3869 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3870 << channel << ")" << std::endl;
3871 return;
3872 }
3873
3874 std::string sender;
3875 if (from_peer != PEER_ID_SERVER) {
3876 sender = getPlayerName(from_peer);
3877 }
3878
3879 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3880 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3881 resp_pkt << channel << sender << message;
3882 for (session_t peer_id : peers) {
3883 // Ignore sender
3884 if (peer_id == from_peer)
3885 continue;
3886
3887 Send(peer_id, &resp_pkt);
3888 }
3889
3890 if (from_peer != PEER_ID_SERVER) {
3891 m_script->on_modchannel_message(channel, sender, message);
3892 }
3893 }
3894
getTranslationLanguage(const std::string & lang_code)3895 Translations *Server::getTranslationLanguage(const std::string &lang_code)
3896 {
3897 if (lang_code.empty())
3898 return nullptr;
3899
3900 auto it = server_translations.find(lang_code);
3901 if (it != server_translations.end())
3902 return &it->second; // Already loaded
3903
3904 // [] will create an entry
3905 auto *translations = &server_translations[lang_code];
3906
3907 std::string suffix = "." + lang_code + ".tr";
3908 for (const auto &i : m_media) {
3909 if (str_ends_with(i.first, suffix)) {
3910 std::string data;
3911 if (fs::ReadFile(i.second.path, data)) {
3912 translations->loadTranslation(data);
3913 }
3914 }
3915 }
3916
3917 return translations;
3918 }
3919