1 /*
2 server.cpp
3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4 */
5
6 /*
7 This file is part of Freeminer.
8
9 Freeminer is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 Freeminer is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with Freeminer. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "server.h"
24 #include <iostream>
25 #include <queue>
26 #include <algorithm>
27 #include "clientserver.h"
28 #include "ban.h"
29 #include "environment.h"
30 #include "map.h"
31 #include "jthread/jmutexautolock.h"
32 #include "main.h"
33 #include "constants.h"
34 #include "voxel.h"
35 #include "config.h"
36 #include "version.h"
37 #include "filesys.h"
38 #include "mapblock.h"
39 #include "serverobject.h"
40 #include "genericobject.h"
41 #include "settings.h"
42 #include "profiler.h"
43 #include "log.h"
44 #include "scripting_game.h"
45 #include "nodedef.h"
46 #include "itemdef.h"
47 #include "craftdef.h"
48 #include "emerge.h"
49 #include "mapgen.h"
50 #include "mg_biome.h"
51 #include "content_mapnode.h"
52 #include "content_nodemeta.h"
53 #include "content_abm.h"
54 #include "content_sao.h"
55 #include "mods.h"
56 #include "sha1.h"
57 #include "base64.h"
58 #include "tool.h"
59 #include "sound.h" // dummySoundManager
60 #include "event_manager.h"
61 #include "hex.h"
62 #include "serverlist.h"
63 #include "util/string.h"
64 #include "util/pointedthing.h"
65 #include "util/mathconstants.h"
66 #include "rollback.h"
67 #include "util/serialize.h"
68 #include "util/thread.h"
69 #include "defaultsettings.h"
70 #include "circuit.h"
71 //#include "stat.h"
72
73 #include <chrono>
74 #include "util/thread_pool.h"
75 #include "key_value_storage.h"
76 #include "database.h"
77
78
79 class ClientNotFoundException : public BaseException
80 {
81 public:
ClientNotFoundException(const char * s)82 ClientNotFoundException(const char *s):
83 BaseException(s)
84 {}
85 };
86
87 class MapThread : public thread_pool
88 {
89 Server *m_server;
90 public:
91
MapThread(Server * server)92 MapThread(Server *server):
93 m_server(server)
94 {}
95
Thread()96 void * Thread() {
97 log_register_thread("MapThread");
98
99 DSTACK(__FUNCTION_NAME);
100 BEGIN_DEBUG_EXCEPTION_HANDLER
101 ThreadStarted();
102
103 porting::setThreadName("Map");
104 porting::setThreadPriority(15);
105 auto time = porting::getTimeMs();
106 while(!StopRequested()) {
107 auto time_now = porting::getTimeMs();
108 try {
109 if (!m_server->AsyncRunMapStep((time_now - time)/1000.0f))
110 std::this_thread::sleep_for(std::chrono::milliseconds(100));
111 else
112 std::this_thread::sleep_for(std::chrono::milliseconds(10));
113 #ifdef NDEBUG
114 } catch (BaseException &e) {
115 errorstream<<"MapThread: exception: "<<e.what()<<std::endl;
116 } catch(std::exception &e) {
117 errorstream<<"MapThread: exception: "<<e.what()<<std::endl;
118 } catch (...) {
119 errorstream<<"MapThread: Ooops..."<<std::endl;
120 #else
121 } catch (int) { //nothing
122 #endif
123 }
124 time = time_now;
125 }
126 END_DEBUG_EXCEPTION_HANDLER(errorstream)
127 return nullptr;
128 }
129 };
130
131 class SendBlocksThread : public thread_pool
132 {
133 Server *m_server;
134 public:
135
SendBlocksThread(Server * server)136 SendBlocksThread(Server *server):
137 m_server(server)
138 {}
139
Thread()140 void * Thread() {
141 log_register_thread("SendBlocksThread");
142
143 DSTACK(__FUNCTION_NAME);
144 BEGIN_DEBUG_EXCEPTION_HANDLER
145
146 ThreadStarted();
147
148 porting::setThreadName("SendBlocksThread");
149 porting::setThreadPriority(30);
150 auto time = porting::getTimeMs();
151 while(!StopRequested()) {
152 //infostream<<"S run d="<<m_server->m_step_dtime<< " myt="<<(porting::getTimeMs() - time)/1000.0f<<std::endl;
153 try {
154 auto time_now = porting::getTimeMs();
155 auto sent = m_server->SendBlocks((time_now - time)/1000.0f);
156 time = time_now;
157 std::this_thread::sleep_for(std::chrono::milliseconds(sent ? 5 : 100));
158 #ifdef NDEBUG
159 } catch (BaseException &e) {
160 errorstream<<"SendBlocksThread: exception: "<<e.what()<<std::endl;
161 } catch(std::exception &e) {
162 errorstream<<"SendBlocksThread: exception: "<<e.what()<<std::endl;
163 } catch (...) {
164 errorstream<<"SendBlocksThread: Ooops..."<<std::endl;
165 #else
166 } catch (int) { //nothing
167 #endif
168 }
169 }
170 END_DEBUG_EXCEPTION_HANDLER(errorstream)
171 return nullptr;
172 }
173 };
174
175
176 class LiquidThread : public thread_pool
177 {
178 Server *m_server;
179 public:
180
LiquidThread(Server * server)181 LiquidThread(Server *server):
182 m_server(server)
183 {}
184
Thread()185 void * Thread() {
186 log_register_thread("Liquid");
187
188 DSTACK(__FUNCTION_NAME);
189 BEGIN_DEBUG_EXCEPTION_HANDLER
190
191 ThreadStarted();
192
193 porting::setThreadName("Liquid");
194 porting::setThreadPriority(4);
195 int max_cycle_ms = 1000;
196 while(!StopRequested()) {
197 try {
198 //shared_map<v3POS, MapBlock*> modified_blocks; //not used
199 int res = m_server->getEnv().getMap().transformLiquids(m_server, max_cycle_ms);
200 std::this_thread::sleep_for(std::chrono::milliseconds(std::max(300-res,1)));
201 #ifdef NDEBUG
202 } catch (BaseException &e) {
203 errorstream<<"Liquid: exception: "<<e.what()<<std::endl;
204 } catch(std::exception &e) {
205 errorstream<<"Liquid: exception: "<<e.what()<<std::endl;
206 } catch (...) {
207 errorstream<<"Liquid: Ooops..."<<std::endl;
208 #else
209 } catch (int) { //nothing
210 #endif
211 }
212 }
213 END_DEBUG_EXCEPTION_HANDLER(errorstream)
214 return nullptr;
215 }
216 };
217
218 class EnvThread : public thread_pool
219 {
220 Server *m_server;
221 public:
222
EnvThread(Server * server)223 EnvThread(Server *server):
224 m_server(server)
225 {}
226
Thread()227 void * Thread() {
228 log_register_thread("Env");
229
230 DSTACK(__FUNCTION_NAME);
231 BEGIN_DEBUG_EXCEPTION_HANDLER
232
233 ThreadStarted();
234
235 porting::setThreadName("Env");
236 porting::setThreadPriority(20);
237 unsigned int max_cycle_ms = 1000;
238 unsigned int time = porting::getTimeMs();
239 while(!StopRequested()) {
240 try {
241 auto ctime = porting::getTimeMs();
242 unsigned int dtimems = ctime - time;
243 time = ctime;
244 m_server->getEnv().step(dtimems/1000.0f, m_server->m_uptime.get(), max_cycle_ms);
245 std::this_thread::sleep_for(std::chrono::milliseconds(dtimems > 100 ? 1 : 100 - dtimems));
246 #ifdef NDEBUG
247 } catch (BaseException &e) {
248 errorstream<<"Env: exception: "<<e.what()<<std::endl;
249 } catch(std::exception &e) {
250 errorstream<<"Env: exception: "<<e.what()<<std::endl;
251 } catch (...) {
252 errorstream<<"Env: Ooops..."<<std::endl;
253 #else
254 } catch (int) { //nothing
255 #endif
256 }
257 }
258 END_DEBUG_EXCEPTION_HANDLER(errorstream)
259 return nullptr;
260 }
261 };
262
263 class ServerThread : public thread_pool
264 {
265 Server *m_server;
266
267 public:
268
ServerThread(Server * server)269 ServerThread(Server *server):
270 m_server(server)
271 {
272 }
273
274 void * Thread();
275 };
276
Thread()277 void * ServerThread::Thread()
278 {
279 log_register_thread("ServerThread");
280
281 DSTACK(__FUNCTION_NAME);
282 BEGIN_DEBUG_EXCEPTION_HANDLER
283
284 f32 dedicated_server_step = g_settings->getFloat("dedicated_server_step");
285 m_server->AsyncRunStep(0.1, true);
286
287 ThreadStarted();
288
289 porting::setThreadName("ServerThread");
290 porting::setThreadPriority(40);
291
292 auto time = porting::getTimeMs();
293 while(!StopRequested())
294 {
295 try{
296 //TimeTaker timer("AsyncRunStep() + Receive()");
297 auto time_now = porting::getTimeMs();
298 m_server->AsyncRunStep((time_now - time)/1000.0f);
299 time = time_now;
300
301 // Loop used only when 100% cpu load or on old slow hardware.
302 // usually only one packet recieved here
303 u32 end_ms = porting::getTimeMs() + u32(1000 * dedicated_server_step);
304 for (u16 i = 0; i < 1000; ++i)
305 if (!m_server->Receive() || porting::getTimeMs() > end_ms)
306 break;
307 }
308 catch(con::NoIncomingDataException &e)
309 {
310 }
311 catch(con::PeerNotFoundException &e)
312 {
313 infostream<<"Server: PeerNotFoundException"<<std::endl;
314 }
315 catch(ClientNotFoundException &e)
316 {
317 }
318 catch(con::ConnectionBindFailed &e)
319 {
320 m_server->setAsyncFatalError(e.what());
321 }
322 catch(LuaError &e)
323 {
324 m_server->setAsyncFatalError(e.what());
325 #ifdef NDEBUG
326 } catch(std::exception &e) {
327 errorstream<<"ServerThread: exception: "<<e.what()<<std::endl;
328 } catch (...) {
329 errorstream<<"ServerThread: Ooops..."<<std::endl;
330 #endif
331 }
332 }
333
334 END_DEBUG_EXCEPTION_HANDLER(errorstream)
335
336 return NULL;
337 }
338
getPos(ServerEnvironment * env,bool * pos_exists) const339 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
340 {
341 if(pos_exists) *pos_exists = false;
342 switch(type){
343 case SSP_LOCAL:
344 return v3f(0,0,0);
345 case SSP_POSITIONAL:
346 if(pos_exists) *pos_exists = true;
347 return pos;
348 case SSP_OBJECT: {
349 if(object == 0)
350 return v3f(0,0,0);
351 ServerActiveObject *sao = env->getActiveObject(object);
352 if(!sao)
353 return v3f(0,0,0);
354 if(pos_exists) *pos_exists = true;
355 return sao->getBasePosition(); }
356 }
357 return v3f(0,0,0);
358 }
359
360 /*
361 Server
362 */
363
Server(const std::string & path_world,const SubgameSpec & gamespec,bool simple_singleplayer_mode,bool ipv6)364 Server::Server(
365 const std::string &path_world,
366 const SubgameSpec &gamespec,
367 bool simple_singleplayer_mode,
368 bool ipv6
369 ):
370 m_path_world(path_world),
371 m_gamespec(gamespec),
372 m_simple_singleplayer_mode(simple_singleplayer_mode),
373 m_async_fatal_error(""),
374 m_env(NULL),
375 m_con(PROTOCOL_ID,
376 simple_singleplayer_mode ? MAX_PACKET_SIZE_SINGLEPLAYER : MAX_PACKET_SIZE,
377 CONNECTION_TIMEOUT,
378 ipv6,
379 this),
380 m_banmanager(NULL),
381 m_rollback(NULL),
382 m_enable_rollback_recording(false),
383 m_emerge(NULL),
384 m_script(NULL),
385 m_circuit(NULL),
386 stat(path_world),
387 m_itemdef(createItemDefManager()),
388 m_nodedef(createNodeDefManager()),
389 m_craftdef(createCraftDefManager()),
390 m_event(new EventManager()),
391 m_thread(NULL),
392 m_map_thread(nullptr),
393 m_sendblocks(nullptr),
394 m_liquid(nullptr),
395 m_envthread(nullptr),
396 m_time_of_day_send_timer(0),
397 m_uptime(0),
398 m_clients(&m_con),
399 m_shutdown_requested(false),
400 m_ignore_map_edit_events(false),
401 m_ignore_map_edit_events_peer_id(0)
402
403 {
404 m_liquid_transform_timer = 0.0;
405 m_liquid_transform_interval = 1.0;
406 m_liquid_send_timer = 0.0;
407 m_liquid_send_interval = 1.0;
408 maintenance_status = 0;
409 m_print_info_timer = 0.0;
410 m_masterserver_timer = 0.0;
411 m_objectdata_timer = 0.0;
412 m_emergethread_trigger_timer = 0.0;
413 m_savemap_timer = 0.0;
414
415 m_step_dtime = 0.0;
416 m_lag = g_settings->getFloat("dedicated_server_step");
417 #if CMAKE_THREADS
418 more_threads = g_settings->getBool("more_threads");
419 #else
420 more_threads = 0;
421 #endif
422
423 if(path_world == "")
424 throw ServerError("Supplied empty world path");
425
426 if(!gamespec.isValid())
427 throw ServerError("Supplied invalid gamespec");
428
429 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
430 if(m_simple_singleplayer_mode)
431 infostream<<" in simple singleplayer mode"<<std::endl;
432 else
433 infostream<<std::endl;
434 infostream<<"- world: "<<m_path_world<<std::endl;
435 infostream<<"- game: "<<m_gamespec.path<<std::endl;
436
437 // Initialize default settings and override defaults with those provided
438 // by the game
439 set_default_settings(g_settings);
440 Settings gamedefaults;
441 getGameMinetestConfig(gamespec.path, gamedefaults);
442 override_default_settings(g_settings, &gamedefaults);
443
444 // Create server thread
445 m_thread = new ServerThread(this);
446
447 // Create emerge manager
448 m_emerge = new EmergeManager(this);
449
450 if (more_threads) {
451 m_map_thread = new MapThread(this);
452 m_sendblocks = new SendBlocksThread(this);
453 m_liquid = new LiquidThread(this);
454 m_envthread = new EnvThread(this);
455 }
456
457 // Create world if it doesn't exist
458 if(!initializeWorld(m_path_world, m_gamespec.id))
459 throw ServerError("Failed to initialize world");
460
461 // Create ban manager
462 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
463 m_banmanager = new BanManager(ban_path);
464
465 // Create rollback manager
466 m_rollback = new RollbackManager(m_path_world, this);
467
468 ModConfiguration modconf(m_path_world);
469 m_mods = modconf.getMods();
470 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
471 // complain about mods with unsatisfied dependencies
472 if(!modconf.isConsistent())
473 {
474 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
475 it != unsatisfied_mods.end(); ++it)
476 {
477 ModSpec mod = *it;
478 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
479 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
480 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
481 errorstream << " \"" << *dep_it << "\"";
482 errorstream << std::endl;
483 }
484 }
485
486 Settings worldmt_settings;
487 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
488 worldmt_settings.readConfigFile(worldmt.c_str());
489 std::vector<std::string> names = worldmt_settings.getNames();
490 std::set<std::string> load_mod_names;
491 for(std::vector<std::string>::iterator it = names.begin();
492 it != names.end(); ++it)
493 {
494 std::string name = *it;
495 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
496 load_mod_names.insert(name.substr(9));
497 }
498 // complain about mods declared to be loaded, but not found
499 for(std::vector<ModSpec>::iterator it = m_mods.begin();
500 it != m_mods.end(); ++it)
501 load_mod_names.erase((*it).name);
502 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
503 it != unsatisfied_mods.end(); ++it)
504 load_mod_names.erase((*it).name);
505 if(!load_mod_names.empty())
506 {
507 errorstream << "The following mods could not be found:";
508 for(std::set<std::string>::iterator it = load_mod_names.begin();
509 it != load_mod_names.end(); ++it)
510 errorstream << " \"" << (*it) << "\"";
511 errorstream << std::endl;
512 }
513
514 // Lock environment
515 //JMutexAutoLock envlock(m_env_mutex);
516
517 // Initialize scripting
518 infostream<<"Server: Initializing Lua"<<std::endl;
519
520 m_script = new GameScripting(this);
521
522 std::string scriptpath = getBuiltinLuaPath() + DIR_DELIM "init.lua";
523
524 if (!m_script->loadScript(scriptpath)) {
525 throw ModError("Failed to load and run " + scriptpath);
526 }
527
528
529 // Print 'em
530 infostream<<"Server: Loading mods: ";
531 for(std::vector<ModSpec>::iterator i = m_mods.begin();
532 i != m_mods.end(); i++){
533 const ModSpec &mod = *i;
534 infostream<<mod.name<<" ";
535 }
536 infostream<<std::endl;
537 // Load and run "mod" scripts
538 for(std::vector<ModSpec>::iterator i = m_mods.begin();
539 i != m_mods.end(); i++){
540 const ModSpec &mod = *i;
541 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
542 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
543 <<scriptpath<<"\"]"<<std::endl;
544 bool success = m_script->loadMod(scriptpath, mod.name);
545 if(!success){
546 errorstream<<"Server: Failed to load and run "
547 <<scriptpath<<std::endl;
548 throw ModError("Failed to load and run "+scriptpath);
549 }
550 }
551
552 // Read Textures and calculate sha1 sums
553 fillMediaCache();
554
555 // Apply item aliases in the node definition manager
556 m_nodedef->updateAliases(m_itemdef);
557 m_nodedef->updateTextures(this);
558
559 // Perform pending node name resolutions
560 m_nodedef->getResolver()->resolveNodes();
561
562 // Load the mapgen params from global settings now after any
563 // initial overrides have been set by the mods
564 m_emerge->loadMapgenParams();
565
566 // Initialize Environment
567 ServerMap *servermap = new ServerMap(path_world, this, m_emerge, m_circuit);
568 m_circuit = new Circuit(m_script, servermap, ndef(), path_world);
569 m_env = new ServerEnvironment(servermap, m_script, m_circuit, this, m_path_world);
570 m_emerge->env = m_env;
571
572 m_clients.setEnv(m_env);
573
574 // Run some callbacks after the MG params have been set up but before activation
575 m_script->environment_OnMapgenInit(&m_emerge->params);
576
577 // Initialize mapgens
578 m_emerge->initMapgens();
579
580 // Give environment reference to scripting api
581 m_script->initializeEnvironment(m_env);
582
583 // Register us to receive map edit events
584 servermap->addEventReceiver(this);
585
586 // If file exists, load environment metadata
587 if(fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt"))
588 {
589 infostream<<"Server: Loading environment metadata"<<std::endl;
590 m_env->loadMeta();
591 }
592
593 // Add some test ActiveBlockModifiers to environment
594 add_legacy_abms(m_env, m_nodedef);
595
596 m_liquid_transform_interval = g_settings->getFloat("liquid_update");
597 m_liquid_send_interval = g_settings->getFloat("liquid_send");
598 }
599
~Server()600 Server::~Server()
601 {
602 infostream<<"Server destructing"<<std::endl;
603
604 // Send shutdown message
605 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
606
607 {
608 //JMutexAutoLock envlock(m_env_mutex);
609
610 // Execute script shutdown hooks
611 m_script->on_shutdown();
612
613 infostream<<"Server: Saving players"<<std::endl;
614 m_env->saveLoadedPlayers();
615
616 infostream<<"Server: Saving environment metadata"<<std::endl;
617 m_env->saveMeta();
618 }
619
620 // Stop threads
621 stop();
622 delete m_thread;
623
624 if (m_liquid)
625 delete m_liquid;
626 if (m_sendblocks)
627 delete m_sendblocks;
628 if (m_map_thread)
629 delete m_map_thread;
630 if(m_envthread)
631 delete m_envthread;
632
633 // stop all emerge threads before deleting players that may have
634 // requested blocks to be emerged
635 m_emerge->stopThreads();
636
637 // Delete things in the reverse order of creation
638 delete m_env;
639
640 // N.B. the EmergeManager should be deleted after the Environment since Map
641 // depends on EmergeManager to write its current params to the map meta
642 delete m_emerge;
643 delete m_rollback;
644 delete m_banmanager;
645 delete m_event;
646 delete m_itemdef;
647 delete m_nodedef;
648 delete m_craftdef;
649 delete m_circuit;
650
651 // Deinitialize scripting
652 infostream<<"Server: Deinitializing scripting"<<std::endl;
653 delete m_script;
654
655 // Delete detached inventories
656 for (std::map<std::string, Inventory*>::iterator
657 i = m_detached_inventories.begin();
658 i != m_detached_inventories.end(); i++) {
659 delete i->second;
660 }
661 }
662
start(Address bind_addr)663 void Server::start(Address bind_addr)
664 {
665 DSTACK(__FUNCTION_NAME);
666 infostream<<"Starting server on "
667 << bind_addr.serializeString() <<"..."<<std::endl;
668
669 // Initialize connection
670 m_con.SetTimeoutMs(30);
671 m_con.Serve(bind_addr);
672
673 // Start thread
674 m_thread->restart();
675 if (m_map_thread)
676 m_map_thread->restart();
677 if (m_sendblocks)
678 m_sendblocks->restart();
679 if (m_liquid)
680 m_liquid->restart();
681 if(m_envthread)
682 m_envthread->restart();
683
684 actionstream << "\033[1mfree\033[1;33mminer \033[1;36mv" << minetest_version_hash << "\033[0m \t"
685 #if CMAKE_THREADS
686 << " THREADS \t"
687 #endif
688 #ifndef NDEBUG
689 << " DEBUG \t"
690 #endif
691 << " cpp="<<__cplusplus<<" \t"
692 << " cores="<< porting::getNumberOfProcessors()
693 << std::endl;
694 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
695 actionstream<<"Server for gameid=\""<<m_gamespec.id
696 <<"\" mapgen=\""<<m_emerge->params.mg_name
697 <<"\" listening on "<<bind_addr.serializeString()<<":"
698 <<bind_addr.getPort() << "."<<std::endl;
699 }
700
stop()701 void Server::stop()
702 {
703 DSTACK(__FUNCTION_NAME);
704
705 infostream<<"Server: Stopping and waiting threads"<<std::endl;
706
707 // Stop threads (set run=false first so both start stopping)
708 //m_emergethread.setRun(false);
709 m_thread->join();
710 //m_emergethread.stop();
711 if (m_liquid)
712 m_liquid->join();
713 if (m_sendblocks)
714 m_sendblocks->join();
715 if (m_map_thread)
716 m_map_thread->join();
717 if(m_envthread)
718 m_envthread->join();
719
720 infostream<<"Server: Threads stopped"<<std::endl;
721 }
722
step(float dtime)723 void Server::step(float dtime)
724 {
725 DSTACK(__FUNCTION_NAME);
726 // Limit a bit
727 if(dtime > 2.0)
728 dtime = 2.0;
729 {
730 JMutexAutoLock lock(m_step_dtime_mutex);
731 m_step_dtime += dtime;
732 }
733 // Throw if fatal error occurred in thread
734 std::string async_err = m_async_fatal_error.get();
735 if(async_err != ""){
736 throw ServerError(async_err);
737 }
738 }
739
AsyncRunStep(float dtime,bool initial_step)740 void Server::AsyncRunStep(float dtime, bool initial_step)
741 {
742 DSTACK(__FUNCTION_NAME);
743
744 TimeTaker timer_step("Server step");
745 g_profiler->add("Server::AsyncRunStep (num)", 1);
746
747 /*
748 float dtime;
749 {
750 JMutexAutoLock lock1(m_step_dtime_mutex);
751 dtime = m_step_dtime;
752 }
753 */
754
755 if (!more_threads)
756 {
757 TimeTaker timer_step("Server step: SendBlocks");
758 // Send blocks to clients
759 SendBlocks(dtime);
760 }
761
762 if((dtime < 0.001) && (initial_step == false))
763 return;
764
765 /*
766 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
767 */
768 ScopeProfiler sp(g_profiler, "Server::AsyncRunStep, avg", SPT_AVG);
769 //infostream<<"Server steps "<<dtime<<std::endl;
770 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
771
772 /*
773 {
774 TimeTaker timer_step("Server step: SendBlocks");
775 JMutexAutoLock lock1(m_step_dtime_mutex);
776 m_step_dtime -= dtime;
777 }
778 */
779
780 /*
781 Update uptime
782 */
783 {
784 m_uptime.set(m_uptime.get() + dtime);
785 }
786
787 f32 dedicated_server_step = g_settings->getFloat("dedicated_server_step");
788 //u32 max_cycle_ms = 1000 * (m_lag > dedicated_server_step ? dedicated_server_step/(m_lag/dedicated_server_step) : dedicated_server_step);
789 u32 max_cycle_ms = 1000 * (dedicated_server_step/(m_lag/dedicated_server_step));
790 if (max_cycle_ms < 40)
791 max_cycle_ms = 40;
792
793 {
794 TimeTaker timer_step("Server step: handlePeerChanges");
795 // This has to be called so that the client list gets synced
796 // with the peer list of the connection
797 handlePeerChanges();
798 }
799
800 /*
801 Update time of day and overall game time
802 */
803 {
804 TimeTaker timer_step("Server step: pdate time of day and overall game time");
805 //JMutexAutoLock envlock(m_env_mutex);
806
807 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
808
809 /*
810 Send to clients at constant intervals
811 */
812
813 m_time_of_day_send_timer -= dtime;
814 if(m_time_of_day_send_timer < 0.0)
815 {
816 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
817 u16 time = m_env->getTimeOfDay();
818 float time_speed = g_settings->getFloat("time_speed");
819 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
820 }
821 }
822
823 {
824 //TimeTaker timer_step("Server step: m_env->step");
825 //JMutexAutoLock lock(m_env_mutex);
826 // Figure out and report maximum lag to environment
827 float max_lag = m_env->getMaxLagEstimate();
828 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
829 if(dtime > max_lag){
830 if(dtime > dedicated_server_step && dtime > max_lag * 2.0)
831 infostream<<"Server: Maximum lag peaked to "<<dtime
832 <<" s"<<std::endl;
833 max_lag = dtime;
834 }
835 m_env->reportMaxLagEstimate(max_lag);
836 // Step environment
837 ScopeProfiler sp(g_profiler, "SEnv step");
838 if (!more_threads)
839 m_env->step(dtime, m_uptime.get(), max_cycle_ms);
840 }
841
842 /*
843 Do background stuff
844 */
845
846 /*
847 Handle players
848 */
849 {
850 //TimeTaker timer_step("Server step: Handle players");
851 //JMutexAutoLock lock(m_env_mutex);
852
853 std::list<u16> clientids = m_clients.getClientIDs();
854
855 //ScopeProfiler sp(g_profiler, "Server: handle players");
856
857 for(std::list<u16>::iterator
858 i = clientids.begin();
859 i != clientids.end(); ++i)
860 {
861 PlayerSAO *playersao = getPlayerSAO(*i);
862 if(playersao == NULL)
863 continue;
864
865 /*
866 Handle player HPs (die if hp=0)
867 */
868 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
869 {
870 if(playersao->getHP() == 0)
871 DiePlayer(*i);
872 else
873 SendPlayerHP(*i);
874 }
875
876 /*
877 Send player breath if changed
878 */
879 if(playersao->m_breath_not_sent) {
880 SendPlayerBreath(*i);
881 }
882
883 /*
884 Send player inventories if necessary
885 */
886 if(playersao->m_moved){
887 SendMovePlayer(*i);
888 playersao->m_moved = false;
889 }
890 if(playersao->m_inventory_not_sent){
891 UpdateCrafting(*i);
892 SendInventory(*i);
893 }
894 }
895 }
896
897 if (!more_threads)
898 AsyncRunMapStep(dtime, false);
899
900 m_clients.step(dtime);
901
902 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
903 #if USE_CURL
904 // send masterserver announce
905 {
906 float &counter = m_masterserver_timer;
907 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
908 g_settings->getBool("server_announce"))
909 {
910 ServerList::sendAnnounce(counter ? "update" : "start",
911 m_clients.getPlayerNames(),
912 m_uptime.get(),
913 m_env->getGameTime(),
914 m_lag,
915 m_gamespec.id,
916 m_emerge->params.mg_name,
917 m_mods);
918 counter = 0.01;
919 }
920 counter += dtime;
921 }
922 #endif
923
924 /*
925 Check added and deleted active objects
926 */
927 {
928 TimeTaker timer_step("Server step: Check added and deleted active objects");
929 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
930 //JMutexAutoLock envlock(m_env_mutex);
931
932 auto clients = m_clients.getClientList();
933 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
934
935 // Radius inside which objects are active
936 s16 radius = g_settings->getS16("active_object_send_range_blocks");
937 s16 player_radius = g_settings->getS16("player_transfer_distance");
938
939 if (player_radius == 0 && g_settings->exists("unlimited_player_transfer_distance") &&
940 !g_settings->getBool("unlimited_player_transfer_distance"))
941 player_radius = radius;
942
943 radius *= MAP_BLOCKSIZE;
944 s16 radius_deactivate = radius*3;
945 player_radius *= MAP_BLOCKSIZE;
946
947 for(auto & client : clients)
948 {
949 // If definitions and textures have not been sent, don't
950 // send objects either
951 if (client->getState() < CS_DefinitionsSent)
952 continue;
953
954 Player *player = m_env->getPlayer(client->peer_id);
955 if(player==NULL)
956 {
957 // This can happen if the client timeouts somehow
958 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
959 <<client->peer_id
960 <<" has no associated player"<<std::endl;*/
961 continue;
962 }
963 v3s16 pos = floatToInt(player->getPosition(), BS);
964
965 std::set<u16> removed_objects;
966 std::set<u16> added_objects;
967 m_env->getRemovedActiveObjects(pos, radius_deactivate, player_radius,
968 client->m_known_objects, removed_objects);
969 m_env->getAddedActiveObjects(pos, radius, player_radius,
970 client->m_known_objects, added_objects);
971
972 // Ignore if nothing happened
973 if(removed_objects.size() == 0 && added_objects.size() == 0)
974 {
975 //infostream<<"active objects: none changed"<<std::endl;
976 continue;
977 }
978
979 std::string data_buffer;
980
981 char buf[4];
982
983 // Handle removed objects
984 writeU16((u8*)buf, removed_objects.size());
985 data_buffer.append(buf, 2);
986 for(std::set<u16>::iterator
987 i = removed_objects.begin();
988 i != removed_objects.end(); ++i)
989 {
990 // Get object
991 u16 id = *i;
992 ServerActiveObject* obj = m_env->getActiveObject(id);
993
994 // Add to data buffer for sending
995 writeU16((u8*)buf, id);
996 data_buffer.append(buf, 2);
997
998 // Remove from known objects
999 client->m_known_objects.erase(id);
1000
1001 if(obj && obj->m_known_by_count > 0)
1002 obj->m_known_by_count--;
1003 }
1004
1005 // Handle added objects
1006 writeU16((u8*)buf, added_objects.size());
1007 data_buffer.append(buf, 2);
1008 for(std::set<u16>::iterator
1009 i = added_objects.begin();
1010 i != added_objects.end(); ++i)
1011 {
1012 // Get object
1013 u16 id = *i;
1014 ServerActiveObject* obj = m_env->getActiveObject(id);
1015
1016 // Get object type
1017 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1018 if(obj == NULL)
1019 infostream<<"WARNING: "<<__FUNCTION_NAME
1020 <<": NULL object"<<std::endl;
1021 else
1022 type = obj->getSendType();
1023
1024 // Add to data buffer for sending
1025 writeU16((u8*)buf, id);
1026 data_buffer.append(buf, 2);
1027 writeU8((u8*)buf, type);
1028 data_buffer.append(buf, 1);
1029
1030 if(obj)
1031 data_buffer.append(serializeLongString(
1032 obj->getClientInitializationData(client->net_proto_version)));
1033 else
1034 data_buffer.append(serializeLongString(""));
1035
1036 // Add to known objects
1037 client->m_known_objects.set(id, true);
1038
1039 if(obj)
1040 obj->m_known_by_count++;
1041 }
1042
1043 // Send packet
1044 SharedBuffer<u8> reply(2 + data_buffer.size());
1045 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1046 memcpy((char*)&reply[2], data_buffer.c_str(),
1047 data_buffer.size());
1048 // Send as reliable
1049 m_clients.send(client->peer_id, 0, reply, true);
1050
1051 /*
1052 verbosestream<<"Server: Sent object remove/add: "
1053 <<removed_objects.size()<<" removed, "
1054 <<added_objects.size()<<" added, "
1055 <<"packet size is "<<reply.getSize()<<std::endl;
1056 */
1057 }
1058 #if 0
1059 /*
1060 Collect a list of all the objects known by the clients
1061 and report it back to the environment.
1062 */
1063
1064 core::map<u16, bool> all_known_objects;
1065
1066 for(core::map<u16, RemoteClient*>::Iterator
1067 i = m_clients.getIterator();
1068 i.atEnd() == false; i++)
1069 {
1070 RemoteClient *client = i.getNode()->getValue();
1071 // Go through all known objects of client
1072 for(core::map<u16, bool>::Iterator
1073 i = client->m_known_objects.getIterator();
1074 i.atEnd()==false; i++)
1075 {
1076 u16 id = i.getNode()->getKey();
1077 all_known_objects[id] = true;
1078 }
1079 }
1080
1081 m_env->setKnownActiveObjects(whatever);
1082 #endif
1083
1084 }
1085
1086 /*
1087 Send object messages
1088 */
1089 {
1090 TimeTaker timer_step("Server step: Send object messages");
1091 //JMutexAutoLock envlock(m_env_mutex);
1092 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1093
1094 // Key = object id
1095 // Value = data sent by object
1096 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
1097
1098 // Get active object messages from environment
1099 for(;;)
1100 {
1101 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1102 if(aom.id == 0)
1103 break;
1104
1105 std::list<ActiveObjectMessage>* message_list = NULL;
1106 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
1107 n = buffered_messages.find(aom.id);
1108 if(n == buffered_messages.end())
1109 {
1110 message_list = new std::list<ActiveObjectMessage>;
1111 buffered_messages[aom.id] = message_list;
1112 }
1113 else
1114 {
1115 message_list = n->second;
1116 }
1117 message_list->push_back(aom);
1118 }
1119
1120
1121
1122
1123
1124 auto clients = m_clients.getClientList();
1125 {
1126 // Route data to every client
1127 for(auto & client : clients)
1128 {
1129 std::string reliable_data;
1130 std::string unreliable_data;
1131 // Go through all objects in message buffer
1132 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1133 j = buffered_messages.begin();
1134 j != buffered_messages.end(); ++j)
1135 {
1136 // If object is not known by client, skip it
1137 u16 id = j->first;
1138 if(client->m_known_objects.find(id) == client->m_known_objects.end())
1139 continue;
1140 // Get message list of object
1141 std::list<ActiveObjectMessage>* list = j->second;
1142 // Go through every message
1143 for(std::list<ActiveObjectMessage>::iterator
1144 k = list->begin(); k != list->end(); ++k)
1145 {
1146 // Compose the full new data with header
1147 ActiveObjectMessage aom = *k;
1148 std::string new_data;
1149 // Add object id
1150 char buf[2];
1151 writeU16((u8*)&buf[0], aom.id);
1152 new_data.append(buf, 2);
1153 // Add data
1154 new_data += serializeString(aom.datastring);
1155 // Add data to buffer
1156 if(aom.reliable)
1157 reliable_data += new_data;
1158 else
1159 unreliable_data += new_data;
1160 }
1161 }
1162 /*
1163 reliable_data and unreliable_data are now ready.
1164 Send them.
1165 */
1166 if(reliable_data.size() > 0)
1167 {
1168 SharedBuffer<u8> reply(2 + reliable_data.size());
1169 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1170 memcpy((char*)&reply[2], reliable_data.c_str(),
1171 reliable_data.size());
1172 // Send as reliable
1173 m_clients.send(client->peer_id, 0, reply, true);
1174 }
1175 if(unreliable_data.size() > 0)
1176 {
1177 SharedBuffer<u8> reply(2 + unreliable_data.size());
1178 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1179 memcpy((char*)&reply[2], unreliable_data.c_str(),
1180 unreliable_data.size());
1181 // Send as unreliable
1182 m_clients.send(client->peer_id, 1, reply, false);
1183 }
1184
1185 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1186 {
1187 infostream<<"Server: Size of object message data: "
1188 <<"reliable: "<<reliable_data.size()
1189 <<", unreliable: "<<unreliable_data.size()
1190 <<std::endl;
1191 }*/
1192 }
1193 }
1194 // Clear buffered_messages
1195 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1196 i = buffered_messages.begin();
1197 i != buffered_messages.end(); ++i)
1198 {
1199 delete i->second;
1200 }
1201 }
1202
1203 /*
1204 Send queued-for-sending map edit events.
1205 */
1206 {
1207 TimeTaker timer_step("Server step: Send queued-for-sending map edit events.");
1208 ScopeProfiler sp(g_profiler, "Server: Map events process");
1209 // We will be accessing the environment
1210 //JMutexAutoLock lock(m_env_mutex);
1211
1212 // Don't send too many at a time
1213 u32 count = 0;
1214
1215 // Single change sending is disabled if queue size is not small
1216 bool disable_single_change_sending = false;
1217 if(m_unsent_map_edit_queue.size() >= 4)
1218 disable_single_change_sending = true;
1219
1220 //int event_count = m_unsent_map_edit_queue.size();
1221
1222 // We'll log the amount of each
1223 Profiler prof;
1224
1225 u32 end_ms = porting::getTimeMs() + max_cycle_ms;
1226 while(m_unsent_map_edit_queue.size() != 0)
1227 {
1228 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1229
1230 // Players far away from the change are stored here.
1231 // Instead of sending the changes, MapBlocks are set not sent
1232 // for them.
1233 std::list<u16> far_players;
1234
1235 if(event->type == MEET_ADDNODE || event->type == MEET_SWAPNODE)
1236 {
1237 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1238 prof.add("MEET_ADDNODE", 1);
1239 if(disable_single_change_sending)
1240 sendAddNode(event->p, event->n, event->already_known_by_peer,
1241 &far_players, 5, event->type == MEET_ADDNODE);
1242 else
1243 sendAddNode(event->p, event->n, event->already_known_by_peer,
1244 &far_players, 30, event->type == MEET_ADDNODE);
1245 }
1246 else if(event->type == MEET_REMOVENODE)
1247 {
1248 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1249 prof.add("MEET_REMOVENODE", 1);
1250 if(disable_single_change_sending)
1251 sendRemoveNode(event->p, event->already_known_by_peer,
1252 &far_players, 5);
1253 else
1254 sendRemoveNode(event->p, event->already_known_by_peer,
1255 &far_players, 30);
1256 }
1257 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1258 {
1259 /*
1260 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1261 */
1262 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1263 setBlockNotSent(event->p);
1264 }
1265 else if(event->type == MEET_OTHER)
1266 {
1267 /*
1268 infostream<<"Server: MEET_OTHER"<<std::endl;
1269 */
1270 prof.add("MEET_OTHER", 1);
1271 for(std::set<v3s16>::iterator
1272 i = event->modified_blocks.begin();
1273 i != event->modified_blocks.end(); ++i)
1274 {
1275 setBlockNotSent(*i);
1276 }
1277 }
1278 else
1279 {
1280 prof.add("unknown", 1);
1281 infostream<<"WARNING: Server: Unknown MapEditEvent "
1282 <<((u32)event->type)<<std::endl;
1283 }
1284
1285 /*
1286 Set blocks not sent to far players
1287 */
1288 if(far_players.size() > 0)
1289 {
1290 // Convert list format to that wanted by SetBlocksNotSent
1291 std::map<v3s16, MapBlock*> modified_blocks2;
1292 for(std::set<v3s16>::iterator
1293 i = event->modified_blocks.begin();
1294 i != event->modified_blocks.end(); ++i)
1295 {
1296 modified_blocks2[*i] =
1297 m_env->getMap().getBlockNoCreateNoEx(*i);
1298 }
1299 // Set blocks not sent
1300 for(std::list<u16>::iterator
1301 i = far_players.begin();
1302 i != far_players.end(); ++i)
1303 {
1304 u16 peer_id = *i;
1305 RemoteClient *client = getClient(peer_id);
1306 if(client==NULL)
1307 continue;
1308 client->SetBlocksNotSent(modified_blocks2);
1309 }
1310 }
1311
1312 delete event;
1313
1314 ++count;
1315 /*// Don't send too many at a time
1316 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1317 break;*/
1318 if (porting::getTimeMs() > end_ms)
1319 break;
1320 }
1321
1322 /*
1323 if(event_count >= 10){
1324 infostream<<"Server: MapEditEvents count="<<count<<"/"<<event_count<<" :"<<std::endl;
1325 prof.print(infostream);
1326 } else if(event_count != 0){
1327 verbosestream<<"Server: MapEditEvents count="<<count<<"/"<<event_count<<" :"<<std::endl;
1328 prof.print(verbosestream);
1329 }
1330 */
1331
1332 }
1333
1334 /*
1335 Trigger emergethread (it somehow gets to a non-triggered but
1336 bysy state sometimes)
1337 */
1338 if (!maintenance_status)
1339 {
1340 TimeTaker timer_step("Server step: Trigger emergethread");
1341 float &counter = m_emergethread_trigger_timer;
1342 counter += dtime;
1343 if(counter >= 2.0)
1344 {
1345 counter = 0.0;
1346
1347 m_emerge->startThreads();
1348
1349 // Update m_enable_rollback_recording here too
1350 m_enable_rollback_recording =
1351 g_settings->getBool("enable_rollback_recording");
1352 }
1353 }
1354
1355 {
1356 if (porting::g_sighup) {
1357 porting::g_sighup = false;
1358 if(!maintenance_status) {
1359 maintenance_status = 1;
1360 maintenance_start();
1361 maintenance_status = 2;
1362 } else if(maintenance_status == 2) {
1363 maintenance_status = 3;
1364 maintenance_end();
1365 maintenance_status = 0;
1366 }
1367 }
1368 if (porting::g_siginfo) {
1369 // todo: add here more info
1370 porting::g_siginfo = false;
1371 infostream<<"uptime="<< (int)m_uptime.get()<<std::endl;
1372 m_clients.UpdatePlayerList(); //print list
1373 g_profiler->print(infostream);
1374 g_profiler->clear();
1375 }
1376 }
1377 }
1378
AsyncRunMapStep(float dtime,bool async)1379 int Server::AsyncRunMapStep(float dtime, bool async) {
1380 DSTACK(__FUNCTION_NAME);
1381
1382 TimeTaker timer_step("Server map step");
1383 g_profiler->add("Server::AsyncRunMapStep (num)", 1);
1384
1385 int ret = 0;
1386
1387 /*
1388 float dtime;
1389 {
1390 JMutexAutoLock lock1(m_step_dtime_mutex);
1391 dtime = m_step_dtime;
1392 }
1393 */
1394
1395 u32 max_cycle_ms = async ? 2000 : 300;
1396
1397 const float map_timer_and_unload_dtime = 10.92;
1398 if(!maintenance_status && m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1399 {
1400 TimeTaker timer_step("Server step: Run Map's timers and unload unused data");
1401 //JMutexAutoLock lock(m_env_mutex);
1402 // Run Map's timers and unload unused data
1403 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1404 if(m_env->getMap().timerUpdate(m_uptime.get(), g_settings->getFloat("server_unload_unused_data_timeout"), max_cycle_ms)) {
1405 m_map_timer_and_unload_interval.run_next(map_timer_and_unload_dtime);
1406 ++ret;
1407 }
1408 }
1409
1410 /* Transform liquids */
1411 m_liquid_transform_timer += dtime;
1412 if(!more_threads && m_liquid_transform_timer >= m_liquid_transform_interval)
1413 {
1414 TimeTaker timer_step("Server step: liquid transform");
1415 m_liquid_transform_timer -= m_liquid_transform_interval;
1416 if (m_liquid_transform_timer > m_liquid_transform_interval * 2)
1417 m_liquid_transform_timer = 0;
1418
1419 //JMutexAutoLock lock(m_env_mutex);
1420
1421 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1422
1423 // not all liquid was processed per step, forcing on next step
1424 //shared_map<v3POS, MapBlock*> modified_blocks; //not used
1425 if (m_env->getMap().transformLiquids(this, max_cycle_ms) > 0) {
1426 m_liquid_transform_timer = m_liquid_transform_interval /* *0.8 */;
1427 ++ret;
1428 }
1429 }
1430
1431 /*
1432 Set the modified blocks unsent for all the clients
1433 */
1434
1435 m_liquid_send_timer += dtime;
1436 if(m_liquid_send_timer >= m_liquid_send_interval)
1437 {
1438 TimeTaker timer_step("Server step: set the modified blocks unsent for all the clients");
1439 m_liquid_send_timer -= m_liquid_send_interval;
1440 if (m_liquid_send_timer > m_liquid_send_interval * 2)
1441 m_liquid_send_timer = 0;
1442
1443 shared_map<v3POS, MapBlock*> modified_blocks; //not used
1444
1445 if (m_env->getMap().updateLighting(m_env->getMap().lighting_modified_blocks, modified_blocks, max_cycle_ms)) {
1446 m_liquid_send_timer = m_liquid_send_interval;
1447 ++ret;
1448 goto no_send;
1449 }
1450
1451 auto clients = m_clients.getClientList();
1452 for (auto & client : clients)
1453 if (client->m_nearest_unsent_nearest) {
1454 client->m_nearest_unsent_d = 0;
1455 client->m_nearest_unsent_nearest = 0;
1456 }
1457
1458 //JMutexAutoLock lock(m_env_mutex);
1459 //JMutexAutoLock lock2(m_con_mutex);
1460
1461 /*
1462 if(m_modified_blocks.size() > 0)
1463 {
1464 SetBlocksNotSent(m_modified_blocks);
1465 }
1466 m_modified_blocks.clear();
1467 */
1468 }
1469 no_send:
1470
1471 ret += save(dtime, true);
1472
1473 return ret;
1474 }
1475
save(float dtime,bool breakable)1476 int Server::save(float dtime, bool breakable) {
1477 // Save map, players and auth stuff
1478 int ret = 0;
1479 float &counter = m_savemap_timer;
1480 counter += dtime;
1481 if(counter >= g_settings->getFloat("server_map_save_interval"))
1482 {
1483 counter = 0.0;
1484 TimeTaker timer_step("Server step: Save map, players and auth stuff");
1485 //JMutexAutoLock lock(m_env_mutex);
1486
1487 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1488
1489 // Save changed parts of map
1490 if(m_env->getMap().save(MOD_STATE_WRITE_NEEDED, breakable)) {
1491 // partial save, will continue on next step
1492 counter = g_settings->getFloat("server_map_save_interval");
1493 ++ret;
1494 if (breakable)
1495 goto save_break;
1496 }
1497
1498 // Save ban file
1499 if (m_banmanager->isModified()) {
1500 m_banmanager->save();
1501 }
1502
1503 // Save players
1504 m_env->saveLoadedPlayers();
1505
1506 // Save environment metadata
1507 m_env->saveMeta();
1508
1509 stat.save();
1510 }
1511 save_break:;
1512
1513 return ret;
1514 }
1515
Receive()1516 u16 Server::Receive()
1517 {
1518 DSTACK(__FUNCTION_NAME);
1519 SharedBuffer<u8> data;
1520 u16 peer_id;
1521 u32 datasize;
1522 u16 received = 0;
1523 try{
1524 datasize = m_con.Receive(peer_id,data);
1525 ProcessData(*data, datasize, peer_id);
1526 ++received;
1527 }
1528 catch(con::InvalidIncomingDataException &e)
1529 {
1530 infostream<<"Server::Receive(): "
1531 "InvalidIncomingDataException: what()="
1532 <<e.what()<<std::endl;
1533 }
1534 catch(SerializationError &e) {
1535 infostream<<"Server::Receive(): "
1536 "SerializationError: what()="
1537 <<e.what()<<std::endl;
1538 }
1539 catch(ClientStateError &e)
1540 {
1541 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1542 DenyAccess(peer_id, L"Your client sent something server didn't expect."
1543 L"Try reconnecting or updating your client");
1544 }
1545 catch(con::PeerNotFoundException &e)
1546 {
1547 // Do nothing
1548 }
1549 return received;
1550 }
1551
StageTwoClientInit(u16 peer_id)1552 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1553 {
1554 std::string playername = "";
1555 PlayerSAO *playersao = NULL;
1556 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1557 if (client != NULL) {
1558 playername = client->getName();
1559 playersao = emergePlayer(playername.c_str(), peer_id);
1560 }
1561
1562 RemotePlayer *player =
1563 static_cast<RemotePlayer*>(m_env->getPlayer(playername));
1564
1565 // If failed, cancel
1566 if((playersao == NULL) || (player == NULL))
1567 {
1568 if(player && player->peer_id != 0){
1569 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1570 <<" (player allocated to an another client)"<<std::endl;
1571 DenyAccess(peer_id, L"Another client is connected with this "
1572 L"name. If your client closed unexpectedly, try again in "
1573 L"a minute.");
1574 } else {
1575 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1576 <<std::endl;
1577 DenyAccess(peer_id, L"Could not allocate player.");
1578 }
1579 return NULL;
1580 }
1581
1582 /*
1583 Send complete position information
1584 */
1585 SendMovePlayer(peer_id);
1586
1587 // Send privileges
1588 SendPlayerPrivileges(peer_id);
1589
1590 // Send inventory formspec
1591 SendPlayerInventoryFormspec(peer_id);
1592
1593 // Send inventory
1594 UpdateCrafting(peer_id);
1595 SendInventory(peer_id);
1596
1597 // Send HP
1598 if(g_settings->getBool("enable_damage"))
1599 SendPlayerHP(peer_id);
1600
1601 // Send Breath
1602 SendPlayerBreath(peer_id);
1603
1604 // Show death screen if necessary
1605 if(player->hp == 0)
1606 SendDeathscreen(peer_id, false, v3f(0,0,0));
1607
1608 // Note things in chat if not in simple singleplayer mode
1609 if(!m_simple_singleplayer_mode)
1610 {
1611 // Send information about server to player in chat
1612 SendChatMessage(peer_id, getStatusString());
1613
1614 // Send information about joining in chat
1615 if (0)
1616 {
1617 std::wstring name = L"unknown";
1618 Player *player = m_env->getPlayer(peer_id);
1619 if(player != NULL)
1620 name = narrow_to_wide(player->getName());
1621
1622 std::wstring message;
1623 message += L"*** ";
1624 message += name;
1625 message += L" joined the game.";
1626 SendChatMessage(PEER_ID_INEXISTENT,message);
1627 }
1628 }
1629
1630 /*
1631 Address addr = getPeerAddress(player->peer_id);
1632 std::string ip_str = addr.serializeString();
1633 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1634 */
1635 /*
1636 Print out action
1637 */
1638 {
1639 std::vector<std::string> names = m_clients.getPlayerNames();
1640
1641 actionstream<<player->getName() << " ["<<getPeerAddress(player->peer_id).serializeString()<<"] "<<
1642 " joins game. List of players: ";
1643
1644 for (std::vector<std::string>::iterator i = names.begin();
1645 i != names.end(); i++)
1646 {
1647 actionstream << *i << " ";
1648 }
1649
1650 actionstream << player->getName() <<std::endl;
1651 }
1652 return playersao;
1653 }
1654
ProcessData(u8 * data,u32 datasize,u16 peer_id)1655 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1656 {
1657 DSTACK(__FUNCTION_NAME);
1658 // Environment is locked first.
1659 //JMutexAutoLock envlock(m_env_mutex);
1660
1661 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1662
1663 std::string addr_s;
1664 try{
1665 Address address = getPeerAddress(peer_id);
1666 addr_s = address.serializeString();
1667
1668 // drop player if is ip is banned
1669 if(m_banmanager->isIpBanned(addr_s)){
1670 std::string ban_name = m_banmanager->getBanName(addr_s);
1671 infostream<<"Server: A banned client tried to connect from "
1672 <<addr_s<<"; banned name was "
1673 <<ban_name<<std::endl;
1674 // This actually doesn't seem to transfer to the client
1675 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1676 +narrow_to_wide(ban_name));
1677 return;
1678 }
1679 }
1680 catch(con::PeerNotFoundException &e)
1681 {
1682 /*
1683 * no peer for this packet found
1684 * most common reason is peer timeout, e.g. peer didn't
1685 * respond for some time, your server was overloaded or
1686 * things like that.
1687 */
1688 verbosestream<<"Server::ProcessData(): Cancelling: peer "
1689 <<peer_id<<" not found"<<std::endl;
1690 return;
1691 }
1692
1693 try
1694 {
1695
1696 if(datasize < 2)
1697 return;
1698
1699 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1700
1701 if(command == TOSERVER_INIT)
1702 {
1703 // [0] u16 TOSERVER_INIT
1704 // [2] u8 SER_FMT_VER_HIGHEST_READ
1705 // [3] u8[20] player_name
1706 // [23] u8[28] password <--- can be sent without this, from old versions
1707
1708 if(datasize < 2+1+PLAYERNAME_SIZE)
1709 return;
1710
1711 RemoteClient* client = getClient(peer_id, CS_Created);
1712
1713 // If net_proto_version is set, this client has already been handled
1714 if(client->getState() > CS_Created)
1715 {
1716 verbosestream<<"Server: Ignoring multiple TOSERVER_INITs from "
1717 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1718 return;
1719 }
1720
1721 verbosestream<<"Server: Got TOSERVER_INIT from "<<addr_s<<" (peer_id="
1722 <<peer_id<<")"<<std::endl;
1723
1724 // Do not allow multiple players in simple singleplayer mode.
1725 // This isn't a perfect way to do it, but will suffice for now
1726 if(m_simple_singleplayer_mode && m_clients.getClientIDs().size() > 1){
1727 infostream<<"Server: Not allowing another client ("<<addr_s
1728 <<") to connect in simple singleplayer mode"<<std::endl;
1729 DenyAccess(peer_id, L"Running in simple singleplayer mode.");
1730 return;
1731 }
1732
1733 // First byte after command is maximum supported
1734 // serialization version
1735 u8 client_max = data[2];
1736 u8 our_max = SER_FMT_VER_HIGHEST_READ;
1737 // Use the highest version supported by both
1738 u8 deployed = std::min(client_max, our_max);
1739 // If it's lower than the lowest supported, give up.
1740 if(deployed < SER_FMT_VER_LOWEST)
1741 deployed = SER_FMT_VER_INVALID;
1742
1743 if(deployed == SER_FMT_VER_INVALID)
1744 {
1745 actionstream<<"Server: A mismatched client tried to connect from "
1746 <<addr_s<<std::endl;
1747 infostream<<"Server: Cannot negotiate serialization version with "
1748 <<addr_s<<std::endl;
1749 DenyAccess(peer_id, std::wstring(
1750 L"Your client's version is not supported.\n"
1751 L"Server version is ")
1752 + narrow_to_wide(minetest_version_simple) + L"."
1753 );
1754 return;
1755 }
1756
1757 client->setPendingSerializationVersion(deployed);
1758
1759 /*
1760 Read and check network protocol version
1761 */
1762
1763 u16 min_net_proto_version = 0;
1764 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1765 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1766
1767 // Use same version as minimum and maximum if maximum version field
1768 // doesn't exist (backwards compatibility)
1769 u16 max_net_proto_version = min_net_proto_version;
1770 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1771 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1772
1773 // Start with client's maximum version
1774 u16 net_proto_version = max_net_proto_version;
1775
1776 // Figure out a working version if it is possible at all
1777 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1778 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1779 {
1780 // If maximum is larger than our maximum, go with our maximum
1781 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1782 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1783 // Else go with client's maximum
1784 else
1785 net_proto_version = max_net_proto_version;
1786 }
1787
1788 verbosestream<<"Server: "<<addr_s<<": Protocol version: min: "
1789 <<min_net_proto_version<<", max: "<<max_net_proto_version
1790 <<", chosen: "<<net_proto_version<<std::endl;
1791
1792 client->net_proto_version = net_proto_version;
1793
1794 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1795 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1796 {
1797 actionstream<<"Server: A mismatched client tried to connect from "
1798 <<addr_s<<std::endl;
1799 DenyAccess(peer_id, std::wstring(
1800 L"Your client's version is not supported.\n"
1801 L"Server version is ")
1802 + narrow_to_wide(minetest_version_simple) + L",\n"
1803 + L"server's PROTOCOL_VERSION is "
1804 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1805 + L"..."
1806 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1807 + L", client's PROTOCOL_VERSION is "
1808 + narrow_to_wide(itos(min_net_proto_version))
1809 + L"..."
1810 + narrow_to_wide(itos(max_net_proto_version))
1811 );
1812 return;
1813 }
1814
1815 if(g_settings->getBool("strict_protocol_version_checking"))
1816 {
1817 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1818 {
1819 actionstream<<"Server: A mismatched (strict) client tried to "
1820 <<"connect from "<<addr_s<<std::endl;
1821 DenyAccess(peer_id, std::wstring(
1822 L"Your client's version is not supported.\n"
1823 L"Server version is ")
1824 + narrow_to_wide(minetest_version_simple) + L",\n"
1825 + L"server's PROTOCOL_VERSION (strict) is "
1826 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1827 + L", client's PROTOCOL_VERSION is "
1828 + narrow_to_wide(itos(min_net_proto_version))
1829 + L"..."
1830 + narrow_to_wide(itos(max_net_proto_version))
1831 );
1832 return;
1833 }
1834 }
1835
1836 /*
1837 Set up player
1838 */
1839 char playername[PLAYERNAME_SIZE];
1840 unsigned int playername_length = 0;
1841 for (; playername_length < PLAYERNAME_SIZE; playername_length++ ) {
1842 playername[playername_length] = data[3+playername_length];
1843 if (data[3+playername_length] == 0)
1844 break;
1845 }
1846
1847 if (playername_length == PLAYERNAME_SIZE) {
1848 actionstream<<"Server: Player with name exceeding max length "
1849 <<"tried to connect from "<<addr_s<<std::endl;
1850 DenyAccess(peer_id, L"Name too long");
1851 return;
1852 }
1853
1854
1855 if(playername[0]=='\0')
1856 {
1857 actionstream<<"Server: Player with an empty name "
1858 <<"tried to connect from "<<addr_s<<std::endl;
1859 DenyAccess(peer_id, L"Empty name");
1860 return;
1861 }
1862
1863 if(!g_settings->getBool("enable_any_name") && string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1864 {
1865 actionstream<<"Server: Player with an invalid name ["<<playername
1866 <<"] tried to connect from "<<addr_s<<std::endl;
1867 DenyAccess(peer_id, L"Name contains unallowed characters");
1868 return;
1869 }
1870
1871 if(!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0)
1872 {
1873 actionstream<<"Server: Player with the name \"singleplayer\" "
1874 <<"tried to connect from "<<addr_s<<std::endl;
1875 DenyAccess(peer_id, L"Name is not allowed");
1876 return;
1877 }
1878
1879 {
1880 std::string reason;
1881 if(m_script->on_prejoinplayer(playername, addr_s, reason))
1882 {
1883 actionstream<<"Server: Player with the name \""<<playername<<"\" "
1884 <<"tried to connect from "<<addr_s<<" "
1885 <<"but it was disallowed for the following reason: "
1886 <<reason<<std::endl;
1887 DenyAccess(peer_id, narrow_to_wide(reason.c_str()));
1888 return;
1889 }
1890 }
1891
1892 infostream<<"Server: New connection: \""<<playername<<"\" from "
1893 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1894
1895 // Get password
1896 char given_password[PASSWORD_SIZE];
1897 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1898 {
1899 // old version - assume blank password
1900 given_password[0] = 0;
1901 }
1902 else
1903 {
1904 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1905 {
1906 given_password[i] = data[23+i];
1907 }
1908 given_password[PASSWORD_SIZE-1] = 0;
1909 }
1910
1911 if(!base64_is_valid(given_password)){
1912 actionstream<<"Server: "<<playername
1913 <<" supplied invalid password hash"<<std::endl;
1914 DenyAccess(peer_id, L"Invalid password hash");
1915 return;
1916 }
1917
1918 // Enforce user limit.
1919 // Don't enforce for users that have some admin right
1920 if(m_clients.getClientIDs(CS_Created).size() >= g_settings->getU16("max_users") &&
1921 !checkPriv(playername, "server") &&
1922 !checkPriv(playername, "ban") &&
1923 !checkPriv(playername, "privs") &&
1924 !checkPriv(playername, "password") &&
1925 playername != g_settings->get("name"))
1926 {
1927 actionstream<<"Server: "<<playername<<" tried to join, but there"
1928 <<" are already max_users="
1929 <<g_settings->getU16("max_users")<<" players."<<std::endl;
1930 DenyAccess(peer_id, L"Too many users.");
1931 return;
1932 }
1933
1934 std::string checkpwd; // Password hash to check against
1935 bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1936
1937 // If no authentication info exists for user, create it
1938 if(!has_auth){
1939 if(!isSingleplayer() &&
1940 g_settings->getBool("disallow_empty_password") &&
1941 std::string(given_password) == ""){
1942 actionstream<<"Server: "<<playername
1943 <<" supplied empty password"<<std::endl;
1944 DenyAccess(peer_id, L"Empty passwords are "
1945 L"disallowed. Set a password and try again.");
1946 return;
1947 }
1948 std::wstring raw_default_password =
1949 narrow_to_wide(g_settings->get("default_password"));
1950 std::string initial_password =
1951 translatePassword(playername, raw_default_password);
1952
1953 // If default_password is empty, allow any initial password
1954 if (raw_default_password.length() == 0)
1955 initial_password = given_password;
1956
1957 m_script->createAuth(playername, initial_password);
1958 }
1959
1960 has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1961
1962 if(!has_auth){
1963 actionstream<<"Server: "<<playername<<" cannot be authenticated"
1964 <<" (auth handler does not work?)"<<std::endl;
1965 DenyAccess(peer_id, L"Not allowed to login");
1966 return;
1967 }
1968
1969 if(given_password != checkpwd){
1970 actionstream<<"Server: "<<playername<<" supplied wrong password"
1971 <<std::endl;
1972 DenyAccess(peer_id, L"Wrong password");
1973 return;
1974 }
1975
1976 RemotePlayer *player =
1977 static_cast<RemotePlayer*>(m_env->getPlayer(playername));
1978
1979 if(player && player->peer_id != 0){
1980 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1981 <<" (player allocated to an another client)"<<std::endl;
1982 DenyAccess(peer_id, L"Another client is connected with this "
1983 L"name. If your client closed unexpectedly, try again in "
1984 L"a minute.");
1985 }
1986
1987 m_clients.setPlayerName(peer_id,playername);
1988
1989 /*
1990 Answer with a TOCLIENT_INIT
1991 */
1992 {
1993 SharedBuffer<u8> reply(2+1+6+8+4);
1994 writeU16(&reply[0], TOCLIENT_INIT);
1995 writeU8(&reply[2], deployed);
1996 //send dummy pos for legacy reasons only
1997 writeV3S16(&reply[2+1], floatToInt(v3f(0,0,0), BS));
1998 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
1999 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
2000
2001 // Send as reliable
2002 m_clients.send(peer_id, 0, reply, true);
2003 m_clients.event(peer_id, CSE_Init);
2004 }
2005
2006 return;
2007 }
2008
2009 if(command == TOSERVER_INIT2)
2010 {
2011
2012 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2013 <<peer_id<<std::endl;
2014
2015 m_clients.event(peer_id, CSE_GotInit2);
2016 u16 protocol_version = m_clients.getProtocolVersion(peer_id);
2017
2018
2019 ///// begin compatibility code
2020 PlayerSAO* playersao = NULL;
2021 if (protocol_version <= 22) {
2022 playersao = StageTwoClientInit(peer_id);
2023
2024 if (playersao == NULL) {
2025 errorstream
2026 << "TOSERVER_INIT2 stage 2 client init failed for peer "
2027 << peer_id << std::endl;
2028 return;
2029 }
2030 }
2031 ///// end compatibility code
2032
2033 /*
2034 Send some initialization data
2035 */
2036
2037 infostream<<"Server: Sending content to "
2038 <<getPlayerName(peer_id)<<std::endl;
2039
2040 // Send player movement settings
2041 SendMovement(peer_id);
2042
2043 // Send item definitions
2044 SendItemDef(peer_id, m_itemdef, protocol_version);
2045
2046 // Send node definitions
2047 SendNodeDef(peer_id, m_nodedef, protocol_version);
2048
2049 m_clients.event(peer_id, CSE_SetDefinitionsSent);
2050
2051 // Send media announcement
2052 sendMediaAnnouncement(peer_id);
2053
2054 // Send detached inventories
2055 sendDetachedInventories(peer_id);
2056
2057 // Send time of day
2058 u16 time = m_env->getTimeOfDay();
2059 float time_speed = g_settings->getFloat("time_speed");
2060 SendTimeOfDay(peer_id, time, time_speed);
2061
2062 ///// begin compatibility code
2063 if (protocol_version <= 22) {
2064 m_clients.event(peer_id, CSE_SetClientReady);
2065 m_script->on_joinplayer(playersao);
2066 }
2067 ///// end compatibility code
2068
2069 // Warnings about protocol version can be issued here
2070 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
2071 {
2072 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
2073 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
2074 }
2075
2076 return;
2077 }
2078
2079 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
2080 u16 peer_proto_ver = getClient(peer_id, CS_InitDone)->net_proto_version;
2081
2082 if(peer_ser_ver == SER_FMT_VER_INVALID)
2083 {
2084 errorstream<<"Server::ProcessData(): Cancelling: Peer"
2085 " serialization format invalid or not initialized."
2086 " Skipping incoming command="<<command<<std::endl;
2087 return;
2088 }
2089
2090 /* Handle commands relate to client startup */
2091 if(command == TOSERVER_REQUEST_MEDIA) {
2092 std::string datastring((char*)&data[2], datasize-2);
2093 std::istringstream is(datastring, std::ios_base::binary);
2094
2095 std::list<std::string> tosend;
2096 u16 numfiles = readU16(is);
2097
2098 infostream<<"Sending "<<numfiles<<" files to "
2099 <<getPlayerName(peer_id)<<std::endl;
2100 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2101
2102 for(int i = 0; i < numfiles; i++) {
2103 std::string name = deSerializeString(is);
2104 tosend.push_back(name);
2105 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2106 <<name<<std::endl;
2107 }
2108
2109 sendRequestedMedia(peer_id, tosend);
2110 return;
2111 }
2112 else if(command == TOSERVER_RECEIVED_MEDIA) {
2113 return;
2114 }
2115 else if(command == TOSERVER_CLIENT_READY) {
2116 // clients <= protocol version 22 did not send ready message,
2117 // they're already initialized
2118 if (peer_proto_ver <= 22) {
2119 infostream << "Client sent message not expected by a "
2120 << "client using protocol version <= 22,"
2121 << "disconnecing peer_id: " << peer_id << std::endl;
2122 m_con.DisconnectPeer(peer_id);
2123 return;
2124 }
2125
2126 PlayerSAO* playersao = StageTwoClientInit(peer_id);
2127
2128 if (playersao == NULL) {
2129 errorstream
2130 << "TOSERVER_CLIENT_READY stage 2 client init failed for peer_id: "
2131 << peer_id << std::endl;
2132 m_con.DisconnectPeer(peer_id);
2133 return;
2134 }
2135
2136 if(datasize < 2+8) {
2137 errorstream
2138 << "TOSERVER_CLIENT_READY client sent inconsistent data, disconnecting peer_id: "
2139 << peer_id << std::endl;
2140 m_con.DisconnectPeer(peer_id);
2141 return;
2142 }
2143
2144 m_clients.setClientVersion(
2145 peer_id,
2146 data[2], data[3], data[4],
2147 std::string((char*) &data[8],(u16) data[6]));
2148
2149 m_clients.event(peer_id, CSE_SetClientReady);
2150 m_script->on_joinplayer(playersao);
2151
2152 stat.add("join", playersao->getPlayer()->getName());
2153 }
2154 else if(command == TOSERVER_GOTBLOCKS) // TODO: REMOVE IN NEXT, move wanted_range to new packet
2155 {
2156 if(datasize < 2+1)
2157 return;
2158
2159 /*
2160 [0] u16 command
2161 [2] u8 count
2162 [3] v3s16 pos_0
2163 [3+6] v3s16 pos_1
2164 [9] wanted range
2165 ...
2166 */
2167
2168 u16 count = data[2];
2169 RemoteClient *client = getClient(peer_id);
2170 for(u16 i=0; i<count; i++)
2171 {
2172 if((s16)datasize < 2+1+(i+1)*6)
2173 throw con::InvalidIncomingDataException
2174 ("GOTBLOCKS length is too short");
2175 readV3S16(&data[2+1+i*6]);
2176 /*infostream<<"Server: GOTBLOCKS ("
2177 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2178 }
2179 if((s16)datasize > 2+1+(count)*6) // only freeminer client
2180 client->wanted_range = readU16(&data[2+1+(count*6)]);
2181 return;
2182 }
2183
2184 if (m_clients.getClientState(peer_id) < CS_Active)
2185 {
2186 if (command == TOSERVER_PLAYERPOS) return;
2187
2188 errorstream<<"Got packet command: " << command << " for peer id "
2189 << peer_id << " but client isn't active yet. Dropping packet "
2190 <<std::endl;
2191 return;
2192 }
2193
2194 Player *player = m_env->getPlayer(peer_id);
2195 if(player == NULL) {
2196 /*
2197 verbosestream<<"Server::ProcessData(): Cancelling: "
2198 "No player for peer_id="<<peer_id
2199 << " disconnecting peer!" <<std::endl;
2200 */
2201 m_con.DisconnectPeer(peer_id);
2202 return;
2203 }
2204
2205 PlayerSAO *playersao = player->getPlayerSAO();
2206 if(playersao == NULL) {
2207 errorstream<<"Server::ProcessData(): Cancelling: "
2208 "No player object for peer_id="<<peer_id
2209 << " disconnecting peer!" <<std::endl;
2210 m_con.DisconnectPeer(peer_id);
2211 return;
2212 }
2213
2214 if(command == TOSERVER_PLAYERPOS)
2215 {
2216 if(datasize < 2+12+12+4+4)
2217 return;
2218
2219 u32 start = 0;
2220 v3s32 ps = readV3S32(&data[start+2]);
2221 v3s32 ss = readV3S32(&data[start+2+12]);
2222 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2223 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2224 u32 keyPressed = 0;
2225 if(datasize >= 2+12+12+4+4+4)
2226 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
2227 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2228 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2229 pitch = wrapDegrees(pitch);
2230 yaw = wrapDegrees(yaw);
2231
2232 player->setPosition(position);
2233 player->setSpeed(speed);
2234 player->setPitch(pitch);
2235 player->setYaw(yaw);
2236 player->keyPressed=keyPressed;
2237 player->control.up = (bool)(keyPressed&1);
2238 player->control.down = (bool)(keyPressed&2);
2239 player->control.left = (bool)(keyPressed&4);
2240 player->control.right = (bool)(keyPressed&8);
2241 player->control.jump = (bool)(keyPressed&16);
2242 player->control.aux1 = (bool)(keyPressed&32);
2243 player->control.sneak = (bool)(keyPressed&64);
2244 player->control.LMB = (bool)(keyPressed&128);
2245 player->control.RMB = (bool)(keyPressed&256);
2246
2247 auto old_pos = playersao->m_last_good_position;
2248 bool cheated = playersao->checkMovementCheat();
2249 if(cheated){
2250 // Call callbacks
2251 m_script->on_cheat(playersao, "moved_too_fast");
2252 }
2253 else {
2254 auto dist = (old_pos/BS).getDistanceFrom(playersao->m_last_good_position/BS);
2255 if (dist)
2256 stat.add("move", playersao->getPlayer()->getName(), dist);
2257 }
2258
2259 auto obj = playersao; // copypasted from server step:
2260 auto uptime = m_uptime.get();
2261 if (!obj->m_uptime_last) // not very good place, but minimum modifications
2262 obj->m_uptime_last = uptime - 0.1;
2263 obj->step(uptime - obj->m_uptime_last, true); //todo: maybe limit count per time
2264 obj->m_uptime_last = uptime;
2265
2266 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2267 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2268 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2269 }
2270 else if(command == TOSERVER_DELETEDBLOCKS)
2271 {
2272 if(datasize < 2+1)
2273 return;
2274
2275 /*
2276 [0] u16 command
2277 [2] u8 count
2278 [3] v3s16 pos_0
2279 [3+6] v3s16 pos_1
2280 ...
2281 */
2282
2283 u16 count = data[2];
2284 for(u16 i=0; i<count; i++)
2285 {
2286 if((s16)datasize < 2+1+(i+1)*6)
2287 throw con::InvalidIncomingDataException
2288 ("DELETEDBLOCKS length is too short");
2289 v3s16 p = readV3S16(&data[2+1+i*6]);
2290 /*infostream<<"Server: DELETEDBLOCKS ("
2291 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2292 RemoteClient *client = getClient(peer_id);
2293 client->SetBlockDeleted(p);
2294 }
2295 }
2296 else if(command == TOSERVER_CLICK_OBJECT)
2297 {
2298 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2299 return;
2300 }
2301 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2302 {
2303 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2304 return;
2305 }
2306 else if(command == TOSERVER_GROUND_ACTION)
2307 {
2308 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2309 return;
2310
2311 }
2312 else if(command == TOSERVER_RELEASE)
2313 {
2314 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2315 return;
2316 }
2317 else if(command == TOSERVER_SIGNTEXT)
2318 {
2319 infostream<<"Server: SIGNTEXT not supported anymore"
2320 <<std::endl;
2321 return;
2322 }
2323 else if(command == TOSERVER_SIGNNODETEXT)
2324 {
2325 infostream<<"Server: SIGNNODETEXT not supported anymore"
2326 <<std::endl;
2327 return;
2328 }
2329 else if(command == TOSERVER_INVENTORY_ACTION)
2330 {
2331 // Strip command and create a stream
2332 std::string datastring((char*)&data[2], datasize-2);
2333 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2334 std::istringstream is(datastring, std::ios_base::binary);
2335 // Create an action
2336 InventoryAction *a = InventoryAction::deSerialize(is);
2337 if(a == NULL)
2338 {
2339 infostream<<"TOSERVER_INVENTORY_ACTION: "
2340 <<"InventoryAction::deSerialize() returned NULL"
2341 <<std::endl;
2342 return;
2343 }
2344
2345 // If something goes wrong, this player is to blame
2346 RollbackScopeActor rollback_scope(m_rollback,
2347 std::string("player:")+player->getName());
2348
2349 /*
2350 Note: Always set inventory not sent, to repair cases
2351 where the client made a bad prediction.
2352 */
2353
2354 /*
2355 Handle restrictions and special cases of the move action
2356 */
2357 if(a->getType() == IACTION_MOVE)
2358 {
2359 IMoveAction *ma = (IMoveAction*)a;
2360
2361 ma->from_inv.applyCurrentPlayer(player->getName());
2362 ma->to_inv.applyCurrentPlayer(player->getName());
2363
2364 setInventoryModified(ma->from_inv);
2365 setInventoryModified(ma->to_inv);
2366
2367 bool from_inv_is_current_player =
2368 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2369 (ma->from_inv.name == player->getName());
2370
2371 bool to_inv_is_current_player =
2372 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2373 (ma->to_inv.name == player->getName());
2374
2375 /*
2376 Disable moving items out of craftpreview
2377 */
2378 if(ma->from_list == "craftpreview")
2379 {
2380 infostream<<"Ignoring IMoveAction from "
2381 <<(ma->from_inv.dump())<<":"<<ma->from_list
2382 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2383 <<" because src is "<<ma->from_list<<std::endl;
2384 delete a;
2385 return;
2386 }
2387
2388 /*
2389 Disable moving items into craftresult and craftpreview
2390 */
2391 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2392 {
2393 infostream<<"Ignoring IMoveAction from "
2394 <<(ma->from_inv.dump())<<":"<<ma->from_list
2395 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2396 <<" because dst is "<<ma->to_list<<std::endl;
2397 delete a;
2398 return;
2399 }
2400
2401 // Disallow moving items in elsewhere than player's inventory
2402 // if not allowed to interact
2403 if(!checkPriv(player->getName(), "interact") &&
2404 (!from_inv_is_current_player ||
2405 !to_inv_is_current_player))
2406 {
2407 infostream<<"Cannot move outside of player's inventory: "
2408 <<"No interact privilege"<<std::endl;
2409 delete a;
2410 return;
2411 }
2412 }
2413 /*
2414 Handle restrictions and special cases of the drop action
2415 */
2416 else if(a->getType() == IACTION_DROP)
2417 {
2418 IDropAction *da = (IDropAction*)a;
2419
2420 da->from_inv.applyCurrentPlayer(player->getName());
2421
2422 setInventoryModified(da->from_inv);
2423
2424 /*
2425 Disable dropping items out of craftpreview
2426 */
2427 if(da->from_list == "craftpreview")
2428 {
2429 infostream<<"Ignoring IDropAction from "
2430 <<(da->from_inv.dump())<<":"<<da->from_list
2431 <<" because src is "<<da->from_list<<std::endl;
2432 delete a;
2433 return;
2434 }
2435
2436 // Disallow dropping items if not allowed to interact
2437 if(!checkPriv(player->getName(), "interact"))
2438 {
2439 delete a;
2440 return;
2441 }
2442 stat.add("drop", player->getName());
2443 }
2444 /*
2445 Handle restrictions and special cases of the craft action
2446 */
2447 else if(a->getType() == IACTION_CRAFT)
2448 {
2449 ICraftAction *ca = (ICraftAction*)a;
2450
2451 ca->craft_inv.applyCurrentPlayer(player->getName());
2452
2453 setInventoryModified(ca->craft_inv);
2454
2455 //bool craft_inv_is_current_player =
2456 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2457 // (ca->craft_inv.name == player->getName());
2458
2459 // Disallow crafting if not allowed to interact
2460 if(!checkPriv(player->getName(), "interact"))
2461 {
2462 infostream<<"Cannot craft: "
2463 <<"No interact privilege"<<std::endl;
2464 delete a;
2465 return;
2466 }
2467 stat.add("craft", player->getName());
2468 }
2469
2470 // Do the action
2471 a->apply(this, playersao, this);
2472 // Eat the action
2473 delete a;
2474 }
2475 else if(command == TOSERVER_CHAT_MESSAGE)
2476 {
2477 /*
2478 u16 command
2479 u16 length
2480 wstring message
2481 */
2482 u8 buf[6];
2483 std::string datastring((char*)&data[2], datasize-2);
2484 std::istringstream is(datastring, std::ios_base::binary);
2485
2486 // Read stuff
2487 is.read((char*)buf, 2);
2488 u16 len = readU16(buf);
2489
2490 std::wstring message;
2491 for(u16 i=0; i<len; i++)
2492 {
2493 is.read((char*)buf, 2);
2494 message += (wchar_t)readU16(buf);
2495 }
2496
2497 // If something goes wrong, this player is to blame
2498 RollbackScopeActor rollback_scope(m_rollback,
2499 std::string("player:")+player->getName());
2500
2501 // Get player name of this client
2502 std::wstring name = narrow_to_wide(player->getName());
2503
2504 // Run script hook
2505 bool ate = m_script->on_chat_message(player->getName(),
2506 wide_to_narrow(message));
2507 // If script ate the message, don't proceed
2508 if(ate)
2509 return;
2510
2511 // Line to send to players
2512 std::wstring line;
2513 // Whether to send to the player that sent the line
2514 bool send_to_sender_only = false;
2515
2516 // Commands are implemented in Lua, so only catch invalid
2517 // commands that were not "eaten" and send an error back
2518 if(message[0] == L'/')
2519 {
2520 message = message.substr(1);
2521 send_to_sender_only = true;
2522 if(message.length() == 0)
2523 line += L"-!- Empty command";
2524 else
2525 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2526 }
2527 else
2528 {
2529 if(checkPriv(player->getName(), "shout")){
2530 line += L"<";
2531 line += name;
2532 line += L"> ";
2533 line += message;
2534 stat.add("chat", player->getName());
2535 } else {
2536 line += L"-!- You don't have permission to shout.";
2537 send_to_sender_only = true;
2538 }
2539 }
2540
2541 if(line != L"")
2542 {
2543 /*
2544 Send the message to sender
2545 */
2546 if (send_to_sender_only)
2547 {
2548 SendChatMessage(peer_id, line);
2549 }
2550 /*
2551 Send the message to others
2552 */
2553 else
2554 {
2555 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2556
2557 std::list<u16> clients = m_clients.getClientIDs();
2558
2559 for(std::list<u16>::iterator
2560 i = clients.begin();
2561 i != clients.end(); ++i)
2562 {
2563 if (*i != peer_id)
2564 SendChatMessage(*i, line);
2565 }
2566 }
2567 }
2568 }
2569 else if(command == TOSERVER_DAMAGE)
2570 {
2571 std::string datastring((char*)&data[2], datasize-2);
2572 std::istringstream is(datastring, std::ios_base::binary);
2573 u8 damage = readU8(is);
2574
2575 if(g_settings->getBool("enable_damage"))
2576 {
2577 actionstream<<player->getName()<<" damaged by "
2578 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2579 <<std::endl;
2580
2581 playersao->setHP(playersao->getHP() - damage);
2582
2583 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2584 DiePlayer(peer_id);
2585
2586 if(playersao->m_hp_not_sent)
2587 SendPlayerHP(peer_id);
2588 stat.add("damage", player->getName(), damage);
2589 }
2590 }
2591 else if(command == TOSERVER_BREATH)
2592 {
2593 std::string datastring((char*)&data[2], datasize-2);
2594 std::istringstream is(datastring, std::ios_base::binary);
2595 u16 breath = readU16(is);
2596 playersao->setBreath(breath);
2597 m_script->player_event(playersao,"breath_changed");
2598 }
2599 else if(command == TOSERVER_PASSWORD)
2600 {
2601 /*
2602 [0] u16 TOSERVER_PASSWORD
2603 [2] u8[28] old password
2604 [30] u8[28] new password
2605 */
2606
2607 if(datasize != 2+PASSWORD_SIZE*2)
2608 return;
2609 /*char password[PASSWORD_SIZE];
2610 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2611 password[i] = data[2+i];
2612 password[PASSWORD_SIZE-1] = 0;*/
2613 std::string oldpwd;
2614 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2615 {
2616 char c = data[2+i];
2617 if(c == 0)
2618 break;
2619 oldpwd += c;
2620 }
2621 std::string newpwd;
2622 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2623 {
2624 char c = data[2+PASSWORD_SIZE+i];
2625 if(c == 0)
2626 break;
2627 newpwd += c;
2628 }
2629
2630 if(!base64_is_valid(newpwd)){
2631 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2632 // Wrong old password supplied!!
2633 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2634 return;
2635 }
2636
2637 infostream<<"Server: Client requests a password change from "
2638 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2639
2640 std::string playername = player->getName();
2641
2642 std::string checkpwd;
2643 m_script->getAuth(playername, &checkpwd, NULL);
2644
2645 if(oldpwd != checkpwd)
2646 {
2647 infostream<<"Server: invalid old password"<<std::endl;
2648 // Wrong old password supplied!!
2649 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2650 return;
2651 }
2652
2653 bool success = m_script->setPassword(playername, newpwd);
2654 if(success){
2655 actionstream<<player->getName()<<" changes password"<<std::endl;
2656 SendChatMessage(peer_id, L"Password change successful.");
2657 } else {
2658 actionstream<<player->getName()<<" tries to change password but "
2659 <<"it fails"<<std::endl;
2660 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2661 }
2662 }
2663 else if(command == TOSERVER_PLAYERITEM)
2664 {
2665 if (datasize < 2+2)
2666 return;
2667
2668 u16 item = readU16(&data[2]);
2669 playersao->setWieldIndex(item);
2670 }
2671 else if(command == TOSERVER_RESPAWN)
2672 {
2673 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2674 return;
2675
2676 RespawnPlayer(peer_id);
2677
2678 actionstream<<player->getName()<<" respawns at "
2679 <<PP(player->getPosition()/BS)<<std::endl;
2680
2681 // ActiveObject is added to environment in AsyncRunStep after
2682 // the previous addition has been succesfully removed
2683 }
2684 else if(command == TOSERVER_INTERACT)
2685 {
2686 std::string datastring((char*)&data[2], datasize-2);
2687 std::istringstream is(datastring, std::ios_base::binary);
2688
2689 /*
2690 [0] u16 command
2691 [2] u8 action
2692 [3] u16 item
2693 [5] u32 length of the next item
2694 [9] serialized PointedThing
2695 actions:
2696 0: start digging (from undersurface) or use
2697 1: stop digging (all parameters ignored)
2698 2: digging completed
2699 3: place block or item (to abovesurface)
2700 4: use item
2701 */
2702 u8 action = readU8(is);
2703 u16 item_i = readU16(is);
2704 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2705 PointedThing pointed;
2706 pointed.deSerialize(tmp_is);
2707
2708 /*
2709 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2710 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2711 */
2712
2713 if(player->hp == 0)
2714 {
2715 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2716 <<" tried to interact, but is dead!"<<std::endl;
2717 return;
2718 }
2719
2720 v3f player_pos = playersao->getLastGoodPosition();
2721
2722 // Update wielded item
2723 playersao->setWieldIndex(item_i);
2724
2725 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2726 v3s16 p_under = pointed.node_undersurface;
2727 v3s16 p_above = pointed.node_abovesurface;
2728
2729 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2730 ServerActiveObject *pointed_object = NULL;
2731 if(pointed.type == POINTEDTHING_OBJECT)
2732 {
2733 pointed_object = m_env->getActiveObject(pointed.object_id);
2734 if(pointed_object == NULL)
2735 {
2736 verbosestream<<"TOSERVER_INTERACT: "
2737 "pointed object is NULL"<<std::endl;
2738 return;
2739 }
2740
2741 }
2742
2743 v3f pointed_pos_under = player_pos;
2744 v3f pointed_pos_above = player_pos;
2745 if(pointed.type == POINTEDTHING_NODE)
2746 {
2747 pointed_pos_under = intToFloat(p_under, BS);
2748 pointed_pos_above = intToFloat(p_above, BS);
2749 }
2750 else if(pointed.type == POINTEDTHING_OBJECT)
2751 {
2752 pointed_pos_under = pointed_object->getBasePosition();
2753 pointed_pos_above = pointed_pos_under;
2754 }
2755
2756 /*
2757 Check that target is reasonably close
2758 (only when digging or placing things)
2759 */
2760 if(action == 0 || action == 2 || action == 3)
2761 {
2762 float d = player_pos.getDistanceFrom(pointed_pos_under);
2763 float max_d = BS * 14; // Just some large enough value
2764 if(d > max_d){
2765 actionstream<<"Player "<<player->getName()
2766 <<" tried to access "<<pointed.dump()
2767 <<" from too far: "
2768 <<"d="<<d<<", max_d="<<max_d
2769 <<". ignoring."<<std::endl;
2770 // Re-send block to revert change on client-side
2771 RemoteClient *client = getClient(peer_id);
2772 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2773 client->SetBlockNotSent(blockpos);
2774 // Call callbacks
2775 m_script->on_cheat(playersao, "interacted_too_far");
2776 // Do nothing else
2777 return;
2778 }
2779 }
2780
2781 /*
2782 Make sure the player is allowed to do it
2783 */
2784 if(!checkPriv(player->getName(), "interact"))
2785 {
2786 actionstream<<player->getName()<<" attempted to interact with "
2787 <<pointed.dump()<<" without 'interact' privilege"
2788 <<std::endl;
2789 // Re-send block to revert change on client-side
2790 RemoteClient *client = getClient(peer_id);
2791 // Digging completed -> under
2792 if(action == 2){
2793 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2794 client->SetBlockNotSent(blockpos);
2795 }
2796 // Placement -> above
2797 if(action == 3){
2798 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2799 client->SetBlockNotSent(blockpos);
2800 }
2801 stat.add("interact_denied", player->getName());
2802 return;
2803 }
2804
2805 /*
2806 If something goes wrong, this player is to blame
2807 */
2808 RollbackScopeActor rollback_scope(m_rollback,
2809 std::string("player:")+player->getName());
2810
2811 /*
2812 0: start digging or punch object
2813 */
2814 if(action == 0)
2815 {
2816 if(pointed.type == POINTEDTHING_NODE)
2817 {
2818 /*
2819 NOTE: This can be used in the future to check if
2820 somebody is cheating, by checking the timing.
2821 */
2822 MapNode n(CONTENT_IGNORE);
2823 bool pos_ok;
2824 n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
2825 if (pos_ok)
2826 n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
2827
2828 if (!pos_ok) {
2829 infostream<<"Server: Not punching: Node not found."
2830 <<" Adding block to emerge queue."
2831 <<std::endl;
2832 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2833 }
2834
2835 if(n.getContent() != CONTENT_IGNORE)
2836 m_script->node_on_punch(p_under, n, playersao, pointed);
2837 // Cheat prevention
2838 playersao->noCheatDigStart(p_under);
2839 }
2840 else if(pointed.type == POINTEDTHING_OBJECT)
2841 {
2842 // Skip if object has been removed
2843 if(pointed_object->m_removed)
2844 return;
2845
2846 actionstream<<player->getName()<<" punches object "
2847 <<pointed.object_id<<": "
2848 <<pointed_object->getDescription()<<std::endl;
2849
2850 ItemStack punchitem = playersao->getWieldedItem();
2851 ToolCapabilities toolcap =
2852 punchitem.getToolCapabilities(m_itemdef);
2853 v3f dir = (pointed_object->getBasePosition() -
2854 (player->getPosition() + player->getEyeOffset())
2855 ).normalize();
2856 float time_from_last_punch =
2857 playersao->resetTimeFromLastPunch();
2858 pointed_object->punch(dir, &toolcap, playersao,
2859 time_from_last_punch);
2860 stat.add("punch", player->getName());
2861 }
2862
2863 } // action == 0
2864
2865 /*
2866 1: stop digging
2867 */
2868 else if(action == 1)
2869 {
2870 } // action == 1
2871
2872 /*
2873 2: Digging completed
2874 */
2875 else if(action == 2)
2876 {
2877 // Only digging of nodes
2878 if(pointed.type == POINTEDTHING_NODE)
2879 {
2880 bool pos_ok;
2881 MapNode n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
2882 if (!pos_ok) {
2883 infostream << "Server: Not finishing digging: Node not found."
2884 << " Adding block to emerge queue."
2885 << std::endl;
2886 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2887 }
2888
2889 /* Cheat prevention */
2890 bool is_valid_dig = true;
2891 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2892 {
2893 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2894 float nocheat_t = playersao->getNoCheatDigTime();
2895 playersao->noCheatDigEnd();
2896 // If player didn't start digging this, ignore dig
2897 if(nocheat_p != p_under){
2898 infostream<<"Server: NoCheat: "<<player->getName()
2899 <<" started digging "
2900 <<PP(nocheat_p)<<" and completed digging "
2901 <<PP(p_under)<<"; not digging."<<std::endl;
2902 is_valid_dig = false;
2903 // Call callbacks
2904 m_script->on_cheat(playersao, "finished_unknown_dig");
2905 }
2906 // Get player's wielded item
2907 ItemStack playeritem;
2908 InventoryList *mlist = playersao->getInventory()->getList("main");
2909 if(mlist != NULL)
2910 playeritem = mlist->getItem(playersao->getWieldIndex());
2911 ToolCapabilities playeritem_toolcap =
2912 playeritem.getToolCapabilities(m_itemdef);
2913 // Get diggability and expected digging time
2914 DigParams params = getDigParams(m_nodedef->get(n).groups,
2915 &playeritem_toolcap);
2916 // If can't dig, try hand
2917 if(!params.diggable){
2918 const ItemDefinition &hand = m_itemdef->get("");
2919 const ToolCapabilities *tp = hand.tool_capabilities;
2920 if(tp)
2921 params = getDigParams(m_nodedef->get(n).groups, tp);
2922 }
2923 // If can't dig, ignore dig
2924 if(!params.diggable){
2925 infostream<<"Server: NoCheat: "<<player->getName()
2926 <<" completed digging "<<PP(p_under)
2927 <<", which is not diggable with tool. not digging."
2928 <<std::endl;
2929 is_valid_dig = false;
2930 // Call callbacks
2931 m_script->on_cheat(playersao, "dug_unbreakable");
2932 }
2933 // Check digging time
2934 // If already invalidated, we don't have to
2935 if(!is_valid_dig){
2936 // Well not our problem then
2937 }
2938 // Clean and long dig
2939 else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
2940 // All is good, but grab time from pool; don't care if
2941 // it's actually available
2942 playersao->getDigPool().grab(params.time);
2943 }
2944 // Short or laggy dig
2945 // Try getting the time from pool
2946 else if(playersao->getDigPool().grab(params.time)){
2947 // All is good
2948 }
2949 // Dig not possible
2950 else{
2951 infostream<<"Server: NoCheat: "<<player->getName()
2952 <<" completed digging "<<PP(p_under)
2953 <<"too fast; not digging."<<std::endl;
2954 is_valid_dig = false;
2955 // Call callbacks
2956 m_script->on_cheat(playersao, "dug_too_fast");
2957 }
2958 }
2959
2960 /* Actually dig node */
2961
2962 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
2963 {
2964 m_script->node_on_dig(p_under, n, playersao);
2965 stat.add("dig", player->getName());
2966 stat.add("dig_"+ m_nodedef->get(n).name , player->getName());
2967 }
2968
2969 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2970 RemoteClient *client = getClient(peer_id);
2971 // Send unusual result (that is, node not being removed)
2972 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
2973 {
2974 // Re-send block to revert change on client-side
2975 client->SetBlockNotSent(blockpos);
2976 }
2977 else {
2978 client->ResendBlockIfOnWire(blockpos);
2979 }
2980 }
2981 } // action == 2
2982
2983 /*
2984 3: place block or right-click object
2985 */
2986 else if(action == 3)
2987 {
2988 ItemStack item = playersao->getWieldedItem();
2989
2990 // Reset build time counter
2991 if(pointed.type == POINTEDTHING_NODE &&
2992 item.getDefinition(m_itemdef).type == ITEM_NODE)
2993 getClient(peer_id)->m_time_from_building = 0.0;
2994
2995 if(pointed.type == POINTEDTHING_OBJECT)
2996 {
2997 // Right click object
2998
2999 // Skip if object has been removed
3000 if(pointed_object->m_removed)
3001 return;
3002
3003 /* android bug - too many
3004 actionstream<<player->getName()<<" right-clicks object "
3005 <<pointed.object_id<<": "
3006 <<pointed_object->getDescription()<<std::endl;
3007 */
3008
3009 // Do stuff
3010 pointed_object->rightClick(playersao);
3011 }
3012 else if(m_script->item_OnPlace(
3013 item, playersao, pointed))
3014 {
3015 // Placement was handled in lua
3016
3017 // Apply returned ItemStack
3018 playersao->setWieldedItem(item);
3019 stat.add("place", player->getName());
3020 //stat.add("place_" + item.name, player->getName());
3021 }
3022
3023 // If item has node placement prediction, always send the
3024 // blocks to make sure the client knows what exactly happened
3025 RemoteClient *client = getClient(peer_id);
3026 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3027 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3028 if(item.getDefinition(m_itemdef).node_placement_prediction != "") {
3029 client->SetBlockNotSent(blockpos);
3030 if(blockpos2 != blockpos) {
3031 client->SetBlockNotSent(blockpos2);
3032 }
3033 }
3034 else {
3035 client->ResendBlockIfOnWire(blockpos);
3036 if(blockpos2 != blockpos) {
3037 client->ResendBlockIfOnWire(blockpos2);
3038 }
3039 }
3040 } // action == 3
3041
3042 /*
3043 4: use
3044 */
3045 else if(action == 4)
3046 {
3047 ItemStack item = playersao->getWieldedItem();
3048
3049 actionstream<<player->getName()<<" uses "<<item.name
3050 <<", pointing at "<<pointed.dump()<<std::endl;
3051
3052 if(m_script->item_OnUse(
3053 item, playersao, pointed))
3054 {
3055 // Apply returned ItemStack
3056 playersao->setWieldedItem(item);
3057 stat.add("use", player->getName());
3058 stat.add("use_" + item.name, player->getName());
3059 }
3060
3061 } // action == 4
3062
3063
3064 /*
3065 Catch invalid actions
3066 */
3067 else
3068 {
3069 infostream<<"WARNING: Server: Invalid action "
3070 <<action<<std::endl;
3071 }
3072 }
3073 else if(command == TOSERVER_REMOVED_SOUNDS)
3074 {
3075 std::string datastring((char*)&data[2], datasize-2);
3076 std::istringstream is(datastring, std::ios_base::binary);
3077
3078 int num = readU16(is);
3079 for(int k=0; k<num; k++){
3080 s32 id = readS32(is);
3081 std::map<s32, ServerPlayingSound>::iterator i =
3082 m_playing_sounds.find(id);
3083 if(i == m_playing_sounds.end())
3084 continue;
3085 ServerPlayingSound &psound = i->second;
3086 psound.clients.erase(peer_id);
3087 if(psound.clients.size() == 0)
3088 m_playing_sounds.erase(i++);
3089 }
3090 }
3091 else if(command == TOSERVER_NODEMETA_FIELDS)
3092 {
3093 std::string datastring((char*)&data[2], datasize-2);
3094 std::istringstream is(datastring, std::ios_base::binary);
3095
3096 v3s16 p = readV3S16(is);
3097 std::string formname = deSerializeString(is);
3098 int num = readU16(is);
3099 std::map<std::string, std::string> fields;
3100 for(int k=0; k<num; k++){
3101 std::string fieldname = deSerializeString(is);
3102 std::string fieldvalue = deSerializeLongString(is);
3103 fields[fieldname] = fieldvalue;
3104 }
3105
3106 // If something goes wrong, this player is to blame
3107 RollbackScopeActor rollback_scope(m_rollback,
3108 std::string("player:")+player->getName());
3109
3110 // Check the target node for rollback data; leave others unnoticed
3111 RollbackNode rn_old(&m_env->getMap(), p, this);
3112
3113 m_script->node_on_receive_fields(p, formname, fields,playersao);
3114
3115 // Report rollback data
3116 RollbackNode rn_new(&m_env->getMap(), p, this);
3117 if(rollback() && rn_new != rn_old){
3118 RollbackAction action;
3119 action.setSetNode(p, rn_old, rn_new);
3120 rollback()->reportAction(action);
3121 }
3122 }
3123 else if(command == TOSERVER_INVENTORY_FIELDS)
3124 {
3125 std::string datastring((char*)&data[2], datasize-2);
3126 std::istringstream is(datastring, std::ios_base::binary);
3127
3128 std::string formname = deSerializeString(is);
3129 int num = readU16(is);
3130 std::map<std::string, std::string> fields;
3131 for(int k=0; k<num; k++){
3132 std::string fieldname = deSerializeString(is);
3133 std::string fieldvalue = deSerializeLongString(is);
3134 fields[fieldname] = fieldvalue;
3135 }
3136
3137 m_script->on_playerReceiveFields(playersao, formname, fields);
3138 }
3139 else
3140 {
3141 infostream<<"Server::ProcessData(): Ignoring "
3142 "unknown command "<<command<<std::endl;
3143 }
3144
3145 } //try
3146 catch(SendFailedException &e)
3147 {
3148 errorstream<<"Server::ProcessData(): SendFailedException: "
3149 <<"what="<<e.what()
3150 <<std::endl;
3151 }
3152 }
3153
setTimeOfDay(u32 time)3154 void Server::setTimeOfDay(u32 time)
3155 {
3156 m_env->setTimeOfDay(time);
3157 m_time_of_day_send_timer = 0;
3158 }
3159
onMapEditEvent(MapEditEvent * event)3160 void Server::onMapEditEvent(MapEditEvent *event)
3161 {
3162 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3163 if(m_ignore_map_edit_events)
3164 return;
3165 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3166 return;
3167 MapEditEvent *e = event->clone();
3168 m_unsent_map_edit_queue.push_back(e);
3169 }
3170
getInventory(const InventoryLocation & loc)3171 Inventory* Server::getInventory(const InventoryLocation &loc)
3172 {
3173 switch(loc.type){
3174 case InventoryLocation::UNDEFINED:
3175 {}
3176 break;
3177 case InventoryLocation::CURRENT_PLAYER:
3178 {}
3179 break;
3180 case InventoryLocation::PLAYER:
3181 {
3182 Player *player = m_env->getPlayer(loc.name.c_str());
3183 if(!player)
3184 return NULL;
3185 PlayerSAO *playersao = player->getPlayerSAO();
3186 if(!playersao)
3187 return NULL;
3188 return playersao->getInventory();
3189 }
3190 break;
3191 case InventoryLocation::NODEMETA:
3192 {
3193 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3194 if(!meta)
3195 return NULL;
3196 return meta->getInventory();
3197 }
3198 break;
3199 case InventoryLocation::DETACHED:
3200 {
3201 if(m_detached_inventories.count(loc.name) == 0)
3202 return NULL;
3203 return m_detached_inventories[loc.name];
3204 }
3205 break;
3206 default:
3207 assert(0);
3208 }
3209 return NULL;
3210 }
setInventoryModified(const InventoryLocation & loc)3211 void Server::setInventoryModified(const InventoryLocation &loc)
3212 {
3213 switch(loc.type){
3214 case InventoryLocation::UNDEFINED:
3215 {}
3216 break;
3217 case InventoryLocation::PLAYER:
3218 {
3219 Player *player = m_env->getPlayer(loc.name.c_str());
3220 if(!player)
3221 return;
3222 PlayerSAO *playersao = player->getPlayerSAO();
3223 if(!playersao)
3224 return;
3225 playersao->m_inventory_not_sent = true;
3226 playersao->m_wielded_item_not_sent = true;
3227 }
3228 break;
3229 case InventoryLocation::NODEMETA:
3230 {
3231 v3s16 blockpos = getNodeBlockPos(loc.p);
3232
3233 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3234 if(block)
3235 block->raiseModified(MOD_STATE_WRITE_NEEDED, "inventoryModified");
3236
3237 setBlockNotSent(blockpos);
3238 }
3239 break;
3240 case InventoryLocation::DETACHED:
3241 {
3242 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
3243 }
3244 break;
3245 default:
3246 assert(0);
3247 }
3248 }
3249
SetBlocksNotSent(std::map<v3s16,MapBlock * > & block)3250 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
3251 {
3252 std::list<u16> clients = m_clients.getClientIDs();
3253 // Set the modified blocks unsent for all the clients
3254 for (std::list<u16>::iterator
3255 i = clients.begin();
3256 i != clients.end(); ++i) {
3257 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
3258 if (client != NULL)
3259 client->SetBlocksNotSent(block);
3260 }
3261 }
3262
peerAdded(con::Peer * peer)3263 void Server::peerAdded(con::Peer *peer)
3264 {
3265 DSTACK(__FUNCTION_NAME);
3266 verbosestream<<"Server::peerAdded(): peer->id="
3267 <<peer->id<<std::endl;
3268
3269 con::PeerChange c;
3270 c.type = con::PEER_ADDED;
3271 c.peer_id = peer->id;
3272 c.timeout = false;
3273 m_peer_change_queue.push_back(c);
3274 }
3275
deletingPeer(con::Peer * peer,bool timeout)3276 void Server::deletingPeer(con::Peer *peer, bool timeout)
3277 {
3278 DSTACK(__FUNCTION_NAME);
3279 verbosestream<<"Server::deletingPeer(): peer->id="
3280 <<peer->id<<", timeout="<<timeout<<std::endl;
3281
3282 m_clients.event(peer->id, CSE_Disconnect);
3283 con::PeerChange c;
3284 c.type = con::PEER_REMOVED;
3285 c.peer_id = peer->id;
3286 c.timeout = timeout;
3287 m_peer_change_queue.push_back(c);
3288 }
3289
getClientConInfo(u16 peer_id,con::rtt_stat_type type,float * retval)3290 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
3291 {
3292 *retval = m_con.getPeerStat(peer_id,type);
3293 if (*retval == -1) return false;
3294 return true;
3295 }
3296
getClientInfo(u16 peer_id,ClientState * state,u32 * uptime,u8 * ser_vers,u16 * prot_vers,u8 * major,u8 * minor,u8 * patch,std::string * vers_string)3297 bool Server::getClientInfo(
3298 u16 peer_id,
3299 ClientState* state,
3300 u32* uptime,
3301 u8* ser_vers,
3302 u16* prot_vers,
3303 u8* major,
3304 u8* minor,
3305 u8* patch,
3306 std::string* vers_string
3307 )
3308 {
3309 *state = m_clients.getClientState(peer_id);
3310 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
3311
3312 if (client == NULL) {
3313 return false;
3314 }
3315
3316 *uptime = client->uptime();
3317 *ser_vers = client->serialization_version;
3318 *prot_vers = client->net_proto_version;
3319
3320 *major = client->getMajor();
3321 *minor = client->getMinor();
3322 *patch = client->getPatch();
3323 *vers_string = client->getPatch();
3324
3325 return true;
3326 }
3327
handlePeerChanges()3328 void Server::handlePeerChanges()
3329 {
3330 while(m_peer_change_queue.size() > 0)
3331 {
3332 con::PeerChange c = m_peer_change_queue.pop_front();
3333
3334 verbosestream<<"Server: Handling peer change: "
3335 <<"id="<<c.peer_id<<", timeout="<<c.timeout
3336 <<std::endl;
3337
3338 switch(c.type)
3339 {
3340 case con::PEER_ADDED:
3341 m_clients.CreateClient(c.peer_id);
3342 break;
3343
3344 case con::PEER_REMOVED:
3345 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
3346 break;
3347
3348 default:
3349 assert("Invalid peer change event received!" == 0);
3350 break;
3351 }
3352 }
3353 }
3354
SendMovement(u16 peer_id)3355 void Server::SendMovement(u16 peer_id)
3356 {
3357 DSTACK(__FUNCTION_NAME);
3358 std::ostringstream os(std::ios_base::binary);
3359
3360 writeU16(os, TOCLIENT_MOVEMENT);
3361 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
3362 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
3363 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
3364 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
3365 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
3366 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
3367 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
3368 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
3369 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
3370 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
3371 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
3372 writeF1000(os, g_settings->getFloat("movement_gravity"));
3373
3374 // Make data buffer
3375 std::string s = os.str();
3376 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3377 // Send as reliable
3378 m_clients.send(peer_id, 0, data, true);
3379 }
3380
SendHP(u16 peer_id,u8 hp)3381 void Server::SendHP(u16 peer_id, u8 hp)
3382 {
3383 DSTACK(__FUNCTION_NAME);
3384 std::ostringstream os(std::ios_base::binary);
3385
3386 writeU16(os, TOCLIENT_HP);
3387 writeU8(os, hp);
3388
3389 // Make data buffer
3390 std::string s = os.str();
3391 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3392 // Send as reliable
3393 m_clients.send(peer_id, 0, data, true);
3394 }
3395
SendBreath(u16 peer_id,u16 breath)3396 void Server::SendBreath(u16 peer_id, u16 breath)
3397 {
3398 DSTACK(__FUNCTION_NAME);
3399 std::ostringstream os(std::ios_base::binary);
3400
3401 writeU16(os, TOCLIENT_BREATH);
3402 writeU16(os, breath);
3403
3404 // Make data buffer
3405 std::string s = os.str();
3406 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3407 // Send as reliable
3408 m_clients.send(peer_id, 0, data, true);
3409 }
3410
SendAccessDenied(u16 peer_id,const std::wstring & reason)3411 void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
3412 {
3413 DSTACK(__FUNCTION_NAME);
3414 std::ostringstream os(std::ios_base::binary);
3415
3416 writeU16(os, TOCLIENT_ACCESS_DENIED);
3417 os<<serializeWideString(reason);
3418
3419 // Make data buffer
3420 std::string s = os.str();
3421 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3422 // Send as reliable
3423 m_clients.send(peer_id, 0, data, true);
3424 }
3425
SendDeathscreen(u16 peer_id,bool set_camera_point_target,v3f camera_point_target)3426 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
3427 v3f camera_point_target)
3428 {
3429 DSTACK(__FUNCTION_NAME);
3430 std::ostringstream os(std::ios_base::binary);
3431
3432 writeU16(os, TOCLIENT_DEATHSCREEN);
3433 writeU8(os, set_camera_point_target);
3434 writeV3F1000(os, camera_point_target);
3435
3436 // Make data buffer
3437 std::string s = os.str();
3438 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3439 // Send as reliable
3440 m_clients.send(peer_id, 0, data, true);
3441 }
3442
SendItemDef(u16 peer_id,IItemDefManager * itemdef,u16 protocol_version)3443 void Server::SendItemDef(u16 peer_id,
3444 IItemDefManager *itemdef, u16 protocol_version)
3445 {
3446 DSTACK(__FUNCTION_NAME);
3447 std::ostringstream os(std::ios_base::binary);
3448
3449 /*
3450 u16 command
3451 u32 length of the next item
3452 zlib-compressed serialized ItemDefManager
3453 */
3454 writeU16(os, TOCLIENT_ITEMDEF);
3455 std::ostringstream tmp_os(std::ios::binary);
3456 itemdef->serialize(tmp_os, protocol_version);
3457 std::ostringstream tmp_os2(std::ios::binary);
3458 compressZlib(tmp_os.str(), tmp_os2);
3459 os<<serializeLongString(tmp_os2.str());
3460
3461 // Make data buffer
3462 std::string s = os.str();
3463 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3464 <<"): size="<<s.size()<<std::endl;
3465 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3466 // Send as reliable
3467 m_clients.send(peer_id, 0, data, true);
3468 }
3469
SendNodeDef(u16 peer_id,INodeDefManager * nodedef,u16 protocol_version)3470 void Server::SendNodeDef(u16 peer_id,
3471 INodeDefManager *nodedef, u16 protocol_version)
3472 {
3473 DSTACK(__FUNCTION_NAME);
3474 std::ostringstream os(std::ios_base::binary);
3475
3476 /*
3477 u16 command
3478 u32 length of the next item
3479 zlib-compressed serialized NodeDefManager
3480 */
3481 writeU16(os, TOCLIENT_NODEDEF);
3482 std::ostringstream tmp_os(std::ios::binary);
3483 nodedef->serialize(tmp_os, protocol_version);
3484 std::ostringstream tmp_os2(std::ios::binary);
3485 compressZlib(tmp_os.str(), tmp_os2);
3486 os<<serializeLongString(tmp_os2.str());
3487
3488 // Make data buffer
3489 std::string s = os.str();
3490 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3491 <<"): size="<<s.size()<<std::endl;
3492 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3493 // Send as reliable
3494 m_clients.send(peer_id, 0, data, true);
3495 }
3496
3497 /*
3498 Non-static send methods
3499 */
3500
SendInventory(u16 peer_id)3501 void Server::SendInventory(u16 peer_id)
3502 {
3503 DSTACK(__FUNCTION_NAME);
3504
3505 PlayerSAO *playersao = getPlayerSAO(peer_id);
3506 assert(playersao);
3507
3508 playersao->m_inventory_not_sent = false;
3509
3510 /*
3511 Serialize it
3512 */
3513
3514 std::ostringstream os;
3515 playersao->getInventory()->serialize(os);
3516
3517 std::string s = os.str();
3518
3519 SharedBuffer<u8> data(s.size()+2);
3520 writeU16(&data[0], TOCLIENT_INVENTORY);
3521 memcpy(&data[2], s.c_str(), s.size());
3522
3523 // Send as reliable
3524 m_clients.send(peer_id, 0, data, true);
3525 }
3526
SendChatMessage(u16 peer_id,const std::wstring & message)3527 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3528 {
3529 DSTACK(__FUNCTION_NAME);
3530
3531 std::ostringstream os(std::ios_base::binary);
3532 u8 buf[12];
3533
3534 // Write command
3535 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3536 os.write((char*)buf, 2);
3537
3538 // Write length
3539 writeU16(buf, message.size());
3540 os.write((char*)buf, 2);
3541
3542 // Write string
3543 for(u32 i=0; i<message.size(); i++)
3544 {
3545 u16 w = message[i];
3546 writeU16(buf, w);
3547 os.write((char*)buf, 2);
3548 }
3549
3550 // Make data buffer
3551 std::string s = os.str();
3552 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3553
3554 if (peer_id != PEER_ID_INEXISTENT)
3555 {
3556 // Send as reliable
3557 m_clients.send(peer_id, 0, data, true);
3558 }
3559 else
3560 {
3561 m_clients.sendToAll(0,data,true);
3562 }
3563 }
3564
SendShowFormspecMessage(u16 peer_id,const std::string & formspec,const std::string & formname)3565 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
3566 const std::string &formname)
3567 {
3568 DSTACK(__FUNCTION_NAME);
3569
3570 std::ostringstream os(std::ios_base::binary);
3571 u8 buf[12];
3572
3573
3574 // Write command
3575 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3576 os.write((char*)buf, 2);
3577 os<<serializeLongString(FORMSPEC_VERSION_STRING + formspec);
3578 os<<serializeString(formname);
3579
3580 // Make data buffer
3581 std::string s = os.str();
3582 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3583 // Send as reliable
3584 m_clients.send(peer_id, 0, data, true);
3585 }
3586
3587 // Spawns a particle on peer with peer_id
SendSpawnParticle(u16 peer_id,v3f pos,v3f velocity,v3f acceleration,float expirationtime,float size,bool collisiondetection,bool vertical,std::string texture)3588 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3589 float expirationtime, float size, bool collisiondetection,
3590 bool vertical, std::string texture)
3591 {
3592 DSTACK(__FUNCTION_NAME);
3593
3594 std::ostringstream os(std::ios_base::binary);
3595 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3596 writeV3F1000(os, pos);
3597 writeV3F1000(os, velocity);
3598 writeV3F1000(os, acceleration);
3599 writeF1000(os, expirationtime);
3600 writeF1000(os, size);
3601 writeU8(os, collisiondetection);
3602 os<<serializeLongString(texture);
3603 writeU8(os, vertical);
3604
3605 // Make data buffer
3606 std::string s = os.str();
3607 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3608
3609 if (peer_id != PEER_ID_INEXISTENT)
3610 {
3611 // Send as reliable
3612 m_clients.send(peer_id, 0, data, true);
3613 }
3614 else
3615 {
3616 m_clients.sendToAll(0,data,true);
3617 }
3618 }
3619
3620 // Adds a ParticleSpawner on peer with peer_id
SendAddParticleSpawner(u16 peer_id,u16 amount,float spawntime,v3f minpos,v3f maxpos,v3f minvel,v3f maxvel,v3f minacc,v3f maxacc,float minexptime,float maxexptime,float minsize,float maxsize,bool collisiondetection,bool vertical,std::string texture,u32 id)3621 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3622 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3623 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
3624 {
3625 DSTACK(__FUNCTION_NAME);
3626
3627 std::ostringstream os(std::ios_base::binary);
3628 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3629
3630 writeU16(os, amount);
3631 writeF1000(os, spawntime);
3632 writeV3F1000(os, minpos);
3633 writeV3F1000(os, maxpos);
3634 writeV3F1000(os, minvel);
3635 writeV3F1000(os, maxvel);
3636 writeV3F1000(os, minacc);
3637 writeV3F1000(os, maxacc);
3638 writeF1000(os, minexptime);
3639 writeF1000(os, maxexptime);
3640 writeF1000(os, minsize);
3641 writeF1000(os, maxsize);
3642 writeU8(os, collisiondetection);
3643 os<<serializeLongString(texture);
3644 writeU32(os, id);
3645 writeU8(os, vertical);
3646
3647 // Make data buffer
3648 std::string s = os.str();
3649 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3650
3651 if (peer_id != PEER_ID_INEXISTENT)
3652 {
3653 // Send as reliable
3654 m_clients.send(peer_id, 0, data, true);
3655 }
3656 else {
3657 m_clients.sendToAll(0,data,true);
3658 }
3659 }
3660
SendDeleteParticleSpawner(u16 peer_id,u32 id)3661 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3662 {
3663 DSTACK(__FUNCTION_NAME);
3664
3665 std::ostringstream os(std::ios_base::binary);
3666 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3667
3668 writeU16(os, id);
3669
3670 // Make data buffer
3671 std::string s = os.str();
3672 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3673
3674 if (peer_id != PEER_ID_INEXISTENT) {
3675 // Send as reliable
3676 m_clients.send(peer_id, 0, data, true);
3677 }
3678 else {
3679 m_clients.sendToAll(0,data,true);
3680 }
3681
3682 }
3683
SendHUDAdd(u16 peer_id,u32 id,HudElement * form)3684 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3685 {
3686 std::ostringstream os(std::ios_base::binary);
3687
3688 // Write command
3689 writeU16(os, TOCLIENT_HUDADD);
3690 writeU32(os, id);
3691 writeU8(os, (u8)form->type);
3692 writeV2F1000(os, form->pos);
3693 os << serializeString(form->name);
3694 writeV2F1000(os, form->scale);
3695 os << serializeString(form->text);
3696 writeU32(os, form->number);
3697 writeU32(os, form->item);
3698 writeU32(os, form->dir);
3699 writeV2F1000(os, form->align);
3700 writeV2F1000(os, form->offset);
3701 writeV3F1000(os, form->world_pos);
3702 writeV2S32(os,form->size);
3703
3704 // Make data buffer
3705 std::string s = os.str();
3706 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3707 // Send as reliable
3708 m_clients.send(peer_id, 1, data, true);
3709 }
3710
SendHUDRemove(u16 peer_id,u32 id)3711 void Server::SendHUDRemove(u16 peer_id, u32 id)
3712 {
3713 std::ostringstream os(std::ios_base::binary);
3714
3715 // Write command
3716 writeU16(os, TOCLIENT_HUDRM);
3717 writeU32(os, id);
3718
3719 // Make data buffer
3720 std::string s = os.str();
3721 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3722 // Send as reliable
3723
3724 m_clients.send(peer_id, 1, data, true);
3725 }
3726
SendHUDChange(u16 peer_id,u32 id,HudElementStat stat,void * value)3727 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3728 {
3729 std::ostringstream os(std::ios_base::binary);
3730
3731 // Write command
3732 writeU16(os, TOCLIENT_HUDCHANGE);
3733 writeU32(os, id);
3734 writeU8(os, (u8)stat);
3735 switch (stat) {
3736 case HUD_STAT_POS:
3737 case HUD_STAT_SCALE:
3738 case HUD_STAT_ALIGN:
3739 case HUD_STAT_OFFSET:
3740 writeV2F1000(os, *(v2f *)value);
3741 break;
3742 case HUD_STAT_NAME:
3743 case HUD_STAT_TEXT:
3744 os << serializeString(*(std::string *)value);
3745 break;
3746 case HUD_STAT_WORLD_POS:
3747 writeV3F1000(os, *(v3f *)value);
3748 break;
3749 case HUD_STAT_SIZE:
3750 writeV2S32(os,*(v2s32 *)value);
3751 break;
3752 case HUD_STAT_NUMBER:
3753 case HUD_STAT_ITEM:
3754 case HUD_STAT_DIR:
3755 default:
3756 writeU32(os, *(u32 *)value);
3757 break;
3758 }
3759
3760 // Make data buffer
3761 std::string s = os.str();
3762 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3763 // Send as reliable
3764 m_clients.send(peer_id, 0, data, true);
3765 }
3766
SendHUDSetFlags(u16 peer_id,u32 flags,u32 mask)3767 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3768 {
3769 std::ostringstream os(std::ios_base::binary);
3770
3771 // Write command
3772 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3773
3774 //////////////////////////// compatibility code to be removed //////////////
3775 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
3776 ////////////////////////////////////////////////////////////////////////////
3777 writeU32(os, flags);
3778 writeU32(os, mask);
3779
3780 // Make data buffer
3781 std::string s = os.str();
3782 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3783 // Send as reliable
3784 m_clients.send(peer_id, 0, data, true);
3785 }
3786
SendHUDSetParam(u16 peer_id,u16 param,const std::string & value)3787 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3788 {
3789 std::ostringstream os(std::ios_base::binary);
3790
3791 // Write command
3792 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3793 writeU16(os, param);
3794 os<<serializeString(value);
3795
3796 // Make data buffer
3797 std::string s = os.str();
3798 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3799 // Send as reliable
3800 m_clients.send(peer_id, 0, data, true);
3801 }
3802
SendSetSky(u16 peer_id,const video::SColor & bgcolor,const std::string & type,const std::vector<std::string> & params)3803 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
3804 const std::string &type, const std::vector<std::string> ¶ms)
3805 {
3806 std::ostringstream os(std::ios_base::binary);
3807
3808 // Write command
3809 writeU16(os, TOCLIENT_SET_SKY);
3810 writeARGB8(os, bgcolor);
3811 os<<serializeString(type);
3812 writeU16(os, params.size());
3813 for(size_t i=0; i<params.size(); i++)
3814 os<<serializeString(params[i]);
3815
3816 // Make data buffer
3817 std::string s = os.str();
3818 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3819 // Send as reliable
3820 m_clients.send(peer_id, 0, data, true);
3821 }
3822
SendOverrideDayNightRatio(u16 peer_id,bool do_override,float ratio)3823 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
3824 float ratio)
3825 {
3826 std::ostringstream os(std::ios_base::binary);
3827
3828 // Write command
3829 writeU16(os, TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO);
3830 writeU8(os, do_override);
3831 writeU16(os, ratio*65535);
3832
3833 // Make data buffer
3834 std::string s = os.str();
3835 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3836 // Send as reliable
3837 m_clients.send(peer_id, 0, data, true);
3838 }
3839
SendTimeOfDay(u16 peer_id,u16 time,f32 time_speed)3840 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3841 {
3842 DSTACK(__FUNCTION_NAME);
3843
3844 // Make packet
3845 SharedBuffer<u8> data(2+2+4);
3846 writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3847 writeU16(&data[2], time);
3848 writeF1000(&data[4], time_speed);
3849
3850 if (peer_id == PEER_ID_INEXISTENT) {
3851 m_clients.sendToAll(0,data,true);
3852 }
3853 else {
3854 // Send as reliable
3855 m_clients.send(peer_id, 0, data, true);
3856 }
3857 }
3858
SendPlayerHP(u16 peer_id)3859 void Server::SendPlayerHP(u16 peer_id)
3860 {
3861 DSTACK(__FUNCTION_NAME);
3862 PlayerSAO *playersao = getPlayerSAO(peer_id);
3863 assert(playersao);
3864 playersao->m_hp_not_sent = false;
3865 SendHP(peer_id, playersao->getHP());
3866 m_script->player_event(playersao,"health_changed");
3867
3868 // Send to other clients
3869 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
3870 ActiveObjectMessage aom(playersao->getId(), true, str);
3871 playersao->m_messages_out.push_back(aom);
3872 }
3873
SendPlayerBreath(u16 peer_id)3874 void Server::SendPlayerBreath(u16 peer_id)
3875 {
3876 DSTACK(__FUNCTION_NAME);
3877 PlayerSAO *playersao = getPlayerSAO(peer_id);
3878 assert(playersao);
3879 playersao->m_breath_not_sent = false;
3880 m_script->player_event(playersao,"breath_changed");
3881 SendBreath(peer_id, playersao->getBreath());
3882 }
3883
SendMovePlayer(u16 peer_id)3884 void Server::SendMovePlayer(u16 peer_id)
3885 {
3886 DSTACK(__FUNCTION_NAME);
3887 Player *player = m_env->getPlayer(peer_id);
3888 assert(player);
3889
3890 std::ostringstream os(std::ios_base::binary);
3891 writeU16(os, TOCLIENT_MOVE_PLAYER);
3892 writeV3F1000(os, player->getPosition());
3893 writeF1000(os, player->getPitch());
3894 writeF1000(os, player->getYaw());
3895
3896 {
3897 v3f pos = player->getPosition();
3898 f32 pitch = player->getPitch();
3899 f32 yaw = player->getYaw();
3900 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3901 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3902 <<" pitch="<<pitch
3903 <<" yaw="<<yaw
3904 <<std::endl;
3905 }
3906
3907 // Make data buffer
3908 std::string s = os.str();
3909 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3910 // Send as reliable
3911 m_clients.send(peer_id, 0, data, true);
3912 }
3913
SendLocalPlayerAnimations(u16 peer_id,v2s32 animation_frames[4],f32 animation_speed)3914 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
3915 {
3916 std::ostringstream os(std::ios_base::binary);
3917
3918 writeU16(os, TOCLIENT_LOCAL_PLAYER_ANIMATIONS);
3919 writeV2S32(os, animation_frames[0]);
3920 writeV2S32(os, animation_frames[1]);
3921 writeV2S32(os, animation_frames[2]);
3922 writeV2S32(os, animation_frames[3]);
3923 writeF1000(os, animation_speed);
3924
3925 // Make data buffer
3926 std::string s = os.str();
3927 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3928 // Send as reliable
3929 m_clients.send(peer_id, 0, data, true);
3930 }
3931
SendEyeOffset(u16 peer_id,v3f first,v3f third)3932 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
3933 {
3934 std::ostringstream os(std::ios_base::binary);
3935
3936 writeU16(os, TOCLIENT_EYE_OFFSET);
3937 writeV3F1000(os, first);
3938 writeV3F1000(os, third);
3939
3940 // Make data buffer
3941 std::string s = os.str();
3942 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3943 // Send as reliable
3944 m_clients.send(peer_id, 0, data, true);
3945 }
SendPlayerPrivileges(u16 peer_id)3946 void Server::SendPlayerPrivileges(u16 peer_id)
3947 {
3948 Player *player = m_env->getPlayer(peer_id);
3949 assert(player);
3950 if(player->peer_id == PEER_ID_INEXISTENT)
3951 return;
3952
3953 std::set<std::string> privs;
3954 m_script->getAuth(player->getName(), NULL, &privs);
3955
3956 std::ostringstream os(std::ios_base::binary);
3957 writeU16(os, TOCLIENT_PRIVILEGES);
3958 writeU16(os, privs.size());
3959 for(std::set<std::string>::const_iterator i = privs.begin();
3960 i != privs.end(); i++){
3961 os<<serializeString(*i);
3962 }
3963
3964 // Make data buffer
3965 std::string s = os.str();
3966 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3967 // Send as reliable
3968 m_clients.send(peer_id, 0, data, true);
3969 }
3970
SendPlayerInventoryFormspec(u16 peer_id)3971 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3972 {
3973 Player *player = m_env->getPlayer(peer_id);
3974 assert(player);
3975 if(player->peer_id == PEER_ID_INEXISTENT)
3976 return;
3977
3978 std::ostringstream os(std::ios_base::binary);
3979 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3980 os<<serializeLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
3981
3982 // Make data buffer
3983 std::string s = os.str();
3984 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3985 // Send as reliable
3986 m_clients.send(peer_id, 0, data, true);
3987 }
3988
playSound(const SimpleSoundSpec & spec,const ServerSoundParams & params)3989 s32 Server::playSound(const SimpleSoundSpec &spec,
3990 const ServerSoundParams ¶ms)
3991 {
3992 // Find out initial position of sound
3993 bool pos_exists = false;
3994 v3f pos = params.getPos(m_env, &pos_exists);
3995 // If position is not found while it should be, cancel sound
3996 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3997 return -1;
3998
3999 // Filter destination clients
4000 std::list<u16> dst_clients;
4001 if(params.to_player != "")
4002 {
4003 Player *player = m_env->getPlayer(params.to_player.c_str());
4004 if(!player){
4005 infostream<<"Server::playSound: Player \""<<params.to_player
4006 <<"\" not found"<<std::endl;
4007 return -1;
4008 }
4009 if(player->peer_id == PEER_ID_INEXISTENT){
4010 infostream<<"Server::playSound: Player \""<<params.to_player
4011 <<"\" not connected"<<std::endl;
4012 return -1;
4013 }
4014 dst_clients.push_back(player->peer_id);
4015 }
4016 else
4017 {
4018 std::list<u16> clients = m_clients.getClientIDs();
4019
4020 for(std::list<u16>::iterator
4021 i = clients.begin(); i != clients.end(); ++i)
4022 {
4023 Player *player = m_env->getPlayer(*i);
4024 if(!player)
4025 continue;
4026 if(pos_exists){
4027 if(player->getPosition().getDistanceFrom(pos) >
4028 params.max_hear_distance)
4029 continue;
4030 }
4031 dst_clients.push_back(*i);
4032 }
4033 }
4034 if(dst_clients.size() == 0)
4035 return -1;
4036
4037 // Create the sound
4038 s32 id = m_next_sound_id++;
4039 // The sound will exist as a reference in m_playing_sounds
4040 m_playing_sounds[id] = ServerPlayingSound();
4041 ServerPlayingSound &psound = m_playing_sounds[id];
4042 psound.params = params;
4043 for(std::list<u16>::iterator i = dst_clients.begin();
4044 i != dst_clients.end(); i++)
4045 psound.clients.insert(*i);
4046 // Create packet
4047 std::ostringstream os(std::ios_base::binary);
4048 writeU16(os, TOCLIENT_PLAY_SOUND);
4049 writeS32(os, id);
4050 os<<serializeString(spec.name);
4051 writeF1000(os, spec.gain * params.gain);
4052 writeU8(os, params.type);
4053 writeV3F1000(os, pos);
4054 writeU16(os, params.object);
4055 writeU8(os, params.loop);
4056 // Make data buffer
4057 std::string s = os.str();
4058 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4059 // Send
4060 for(std::list<u16>::iterator i = dst_clients.begin();
4061 i != dst_clients.end(); i++){
4062 // Send as reliable
4063 m_clients.send(*i, 0, data, true);
4064 }
4065 return id;
4066 }
stopSound(s32 handle)4067 void Server::stopSound(s32 handle)
4068 {
4069 // Get sound reference
4070 std::map<s32, ServerPlayingSound>::iterator i =
4071 m_playing_sounds.find(handle);
4072 if(i == m_playing_sounds.end())
4073 return;
4074 ServerPlayingSound &psound = i->second;
4075 // Create packet
4076 std::ostringstream os(std::ios_base::binary);
4077 writeU16(os, TOCLIENT_STOP_SOUND);
4078 writeS32(os, handle);
4079 // Make data buffer
4080 std::string s = os.str();
4081 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4082 // Send
4083 for(std::set<u16>::iterator i = psound.clients.begin();
4084 i != psound.clients.end(); i++){
4085 // Send as reliable
4086 m_clients.send(*i, 0, data, true);
4087 }
4088 // Remove sound reference
4089 m_playing_sounds.erase(i);
4090 }
4091
sendRemoveNode(v3s16 p,u16 ignore_id,std::list<u16> * far_players,float far_d_nodes)4092 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
4093 std::list<u16> *far_players, float far_d_nodes)
4094 {
4095 float maxd = far_d_nodes*BS;
4096 v3f p_f = intToFloat(p, BS);
4097
4098 // Create packet
4099 u32 replysize = 8;
4100 SharedBuffer<u8> reply(replysize);
4101 writeU16(&reply[0], TOCLIENT_REMOVENODE);
4102 writeS16(&reply[2], p.X);
4103 writeS16(&reply[4], p.Y);
4104 writeS16(&reply[6], p.Z);
4105
4106 std::list<u16> clients = m_clients.getClientIDs();
4107 for(std::list<u16>::iterator
4108 i = clients.begin();
4109 i != clients.end(); ++i)
4110 {
4111 if(far_players)
4112 {
4113 // Get player
4114 Player *player = m_env->getPlayer(*i);
4115 if(player)
4116 {
4117 // If player is far away, only set modified blocks not sent
4118 v3f player_pos = player->getPosition();
4119 if(player_pos.getDistanceFrom(p_f) > maxd)
4120 {
4121 far_players->push_back(*i);
4122 continue;
4123 }
4124 }
4125 }
4126
4127 // Send as reliable
4128 m_clients.send(*i, 0, reply, true);
4129 }
4130 }
4131
sendAddNode(v3s16 p,MapNode n,u16 ignore_id,std::list<u16> * far_players,float far_d_nodes,bool remove_metadata)4132 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
4133 std::list<u16> *far_players, float far_d_nodes,
4134 bool remove_metadata)
4135 {
4136 float maxd = far_d_nodes*BS;
4137 v3f p_f = intToFloat(p, BS);
4138
4139 std::list<u16> clients = m_clients.getClientIDs();
4140 for(std::list<u16>::iterator
4141 i = clients.begin();
4142 i != clients.end(); ++i)
4143 {
4144
4145 if(far_players)
4146 {
4147 // Get player
4148 Player *player = m_env->getPlayer(*i);
4149 if(player)
4150 {
4151 // If player is far away, only set modified blocks not sent
4152 v3f player_pos = player->getPosition();
4153 if(player_pos.getDistanceFrom(p_f) > maxd)
4154 {
4155 far_players->push_back(*i);
4156 continue;
4157 }
4158 }
4159 }
4160 SharedBuffer<u8> reply(0);
4161 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
4162 if (client != 0)
4163 {
4164 // Create packet
4165 u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
4166 reply = SharedBuffer<u8>(replysize);
4167 writeU16(&reply[0], TOCLIENT_ADDNODE);
4168 writeS16(&reply[2], p.X);
4169 writeS16(&reply[4], p.Y);
4170 writeS16(&reply[6], p.Z);
4171 n.serialize(&reply[8], client->serialization_version);
4172 u32 index = 8 + MapNode::serializedLength(client->serialization_version);
4173 writeU8(&reply[index], remove_metadata ? 0 : 1);
4174
4175 if (!remove_metadata) {
4176 if (client->net_proto_version <= 21) {
4177 // Old clients always clear metadata; fix it
4178 // by sending the full block again.
4179 client->SetBlockNotSent(p);
4180 }
4181 }
4182 }
4183
4184 // Send as reliable
4185 if (reply.getSize() > 0)
4186 m_clients.send(*i, 0, reply, true);
4187 }
4188 }
4189
setBlockNotSent(v3s16 p)4190 void Server::setBlockNotSent(v3s16 p)
4191 {
4192 auto clients = m_clients.getClientIDs();
4193 for(std::list<u16>::iterator
4194 i = clients.begin();
4195 i != clients.end(); ++i)
4196 {
4197 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
4198 client->SetBlockNotSent(p);
4199 }
4200 }
4201
SendBlockNoLock(u16 peer_id,MapBlock * block,u8 ver,u16 net_proto_version,bool reliable)4202 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version, bool reliable)
4203 {
4204 DSTACK(__FUNCTION_NAME);
4205
4206 g_profiler->add("Connection: blocks sent", 1);
4207
4208 v3s16 p = block->getPos();
4209
4210 #if 0
4211 // Analyze it a bit
4212 bool completely_air = true;
4213 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4214 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4215 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4216 {
4217 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
4218 {
4219 completely_air = false;
4220 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
4221 }
4222 }
4223
4224 // Print result
4225 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
4226 if(completely_air)
4227 infostream<<"[completely air] ";
4228 infostream<<std::endl;
4229 #endif
4230
4231 /*
4232 Create a packet with the block in the right format
4233 */
4234
4235 std::ostringstream os(std::ios_base::binary);
4236 block->serialize(os, ver, false);
4237 block->serializeNetworkSpecific(os, net_proto_version);
4238 std::string s = os.str();
4239 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4240
4241 u32 replysize = 8 + blockdata.getSize();
4242 SharedBuffer<u8> reply(replysize);
4243 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4244 writeS16(&reply[2], p.X);
4245 writeS16(&reply[4], p.Y);
4246 writeS16(&reply[6], p.Z);
4247 memcpy(&reply[8], *blockdata, blockdata.getSize());
4248
4249 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4250 <<": \tpacket size: "<<replysize<<std::endl;*/
4251
4252 //JMutexAutoLock lock(m_env_mutex);
4253 /*
4254 Send packet
4255 */
4256 m_clients.send(peer_id, 2, reply, reliable);
4257 }
4258
SendBlocks(float dtime)4259 int Server::SendBlocks(float dtime)
4260 {
4261 DSTACK(__FUNCTION_NAME);
4262 //TimeTaker timer("SendBlocks inside");
4263
4264 //JMutexAutoLock envlock(m_env_mutex);
4265 //TODO check if one big lock could be faster then multiple small ones
4266
4267 //ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
4268
4269 int total = 0;
4270
4271 std::vector<PrioritySortedBlockTransfer> queue;
4272
4273 {
4274 //ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4275
4276 std::list<u16> clients = m_clients.getClientIDs();
4277
4278 for(std::list<u16>::iterator
4279 i = clients.begin();
4280 i != clients.end(); ++i)
4281 {
4282 auto client = m_clients.getClient(*i, CS_Active);
4283
4284 if (client == NULL)
4285 continue;
4286
4287 total += client->GetNextBlocks(m_env, m_emerge, dtime, m_uptime.get() + m_env->m_game_time_start, queue);
4288 }
4289 }
4290
4291 // Sort.
4292 // Lowest priority number comes first.
4293 // Lowest is most important.
4294 std::sort(queue.begin(), queue.end());
4295
4296 for(u32 i=0; i<queue.size(); i++)
4297 {
4298 //TODO: Calculate limit dynamically
4299
4300 PrioritySortedBlockTransfer q = queue[i];
4301
4302 MapBlock *block = NULL;
4303 try
4304 {
4305 block = m_env->getMap().getBlockNoCreate(q.pos);
4306 }
4307 catch(InvalidPositionException &e)
4308 {
4309 continue;
4310 }
4311
4312 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
4313
4314 if(!client)
4315 continue;
4316
4317 {
4318 auto lock = block->try_lock_shared_rec();
4319 if (!lock->owns_lock())
4320 continue;
4321
4322 // maybe sometimes blocks will not load (must wait 1+ minute), but reduce network load: q.priority<=4
4323 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version, 1);
4324 }
4325
4326 client->SentBlock(q.pos, m_uptime.get() + m_env->m_game_time_start);
4327 ++total;
4328 }
4329 return total;
4330 }
4331
fillMediaCache()4332 void Server::fillMediaCache()
4333 {
4334 DSTACK(__FUNCTION_NAME);
4335
4336 infostream<<"Server: Calculating media file checksums"<<std::endl;
4337
4338 // Collect all media file paths
4339 std::list<std::string> paths;
4340 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4341 i != m_mods.end(); i++){
4342 const ModSpec &mod = *i;
4343 paths.push_back(mod.path + DIR_DELIM + "textures");
4344 paths.push_back(mod.path + DIR_DELIM + "sounds");
4345 paths.push_back(mod.path + DIR_DELIM + "media");
4346 paths.push_back(mod.path + DIR_DELIM + "models");
4347 }
4348 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
4349
4350 // Collect media file information from paths into cache
4351 for(std::list<std::string>::iterator i = paths.begin();
4352 i != paths.end(); i++)
4353 {
4354 std::string mediapath = *i;
4355 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4356 for(u32 j=0; j<dirlist.size(); j++){
4357 if(dirlist[j].dir) // Ignode dirs
4358 continue;
4359 std::string filename = dirlist[j].name;
4360 // If name contains illegal characters, ignore the file
4361 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4362 infostream<<"Server: ignoring illegal file name: \""
4363 <<filename<<"\""<<std::endl;
4364 continue;
4365 }
4366 // If name is not in a supported format, ignore it
4367 const char *supported_ext[] = {
4368 ".png", ".jpg", ".bmp", ".tga",
4369 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4370 ".ogg",
4371 ".x", ".b3d", ".md2", ".obj",
4372 NULL
4373 };
4374 if(removeStringEnd(filename, supported_ext) == ""){
4375 infostream<<"Server: ignoring unsupported file extension: \""
4376 <<filename<<"\""<<std::endl;
4377 continue;
4378 }
4379 // Ok, attempt to load the file and add to cache
4380 std::string filepath = mediapath + DIR_DELIM + filename;
4381 // Read data
4382 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4383 if(fis.good() == false){
4384 errorstream<<"Server::fillMediaCache(): Could not open \""
4385 <<filename<<"\" for reading"<<std::endl;
4386 continue;
4387 }
4388 std::ostringstream tmp_os(std::ios_base::binary);
4389 bool bad = false;
4390 for(;;){
4391 char buf[1024];
4392 fis.read(buf, 1024);
4393 std::streamsize len = fis.gcount();
4394 tmp_os.write(buf, len);
4395 if(fis.eof())
4396 break;
4397 if(!fis.good()){
4398 bad = true;
4399 break;
4400 }
4401 }
4402 if(bad){
4403 errorstream<<"Server::fillMediaCache(): Failed to read \""
4404 <<filename<<"\""<<std::endl;
4405 continue;
4406 }
4407 if(tmp_os.str().length() == 0){
4408 errorstream<<"Server::fillMediaCache(): Empty file \""
4409 <<filepath<<"\""<<std::endl;
4410 continue;
4411 }
4412
4413 SHA1 sha1;
4414 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4415
4416 unsigned char *digest = sha1.getDigest();
4417 std::string sha1_base64 = base64_encode(digest, 20);
4418 std::string sha1_hex = hex_encode((char*)digest, 20);
4419 free(digest);
4420
4421 // Put in list
4422 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4423 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4424 }
4425 }
4426 }
4427
4428 struct SendableMediaAnnouncement
4429 {
4430 std::string name;
4431 std::string sha1_digest;
4432
SendableMediaAnnouncementSendableMediaAnnouncement4433 SendableMediaAnnouncement(const std::string &name_="",
4434 const std::string &sha1_digest_=""):
4435 name(name_),
4436 sha1_digest(sha1_digest_)
4437 {}
4438 };
4439
sendMediaAnnouncement(u16 peer_id)4440 void Server::sendMediaAnnouncement(u16 peer_id)
4441 {
4442 DSTACK(__FUNCTION_NAME);
4443
4444 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4445 <<std::endl;
4446
4447 std::list<SendableMediaAnnouncement> file_announcements;
4448
4449 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4450 i != m_media.end(); i++){
4451 // Put in list
4452 file_announcements.push_back(
4453 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4454 }
4455
4456 // Make packet
4457 std::ostringstream os(std::ios_base::binary);
4458
4459 /*
4460 u16 command
4461 u32 number of files
4462 for each texture {
4463 u16 length of name
4464 string name
4465 u16 length of sha1_digest
4466 string sha1_digest
4467 }
4468 */
4469
4470 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4471 writeU16(os, file_announcements.size());
4472
4473 for(std::list<SendableMediaAnnouncement>::iterator
4474 j = file_announcements.begin();
4475 j != file_announcements.end(); ++j){
4476 os<<serializeString(j->name);
4477 os<<serializeString(j->sha1_digest);
4478 }
4479 os<<serializeString(g_settings->get("remote_media"));
4480
4481 // Make data buffer
4482 std::string s = os.str();
4483 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4484
4485 // Send as reliable
4486 m_clients.send(peer_id, 0, data, true);
4487 }
4488
4489 struct SendableMedia
4490 {
4491 std::string name;
4492 std::string path;
4493 std::string data;
4494
SendableMediaSendableMedia4495 SendableMedia(const std::string &name_="", const std::string &path_="",
4496 const std::string &data_=""):
4497 name(name_),
4498 path(path_),
4499 data(data_)
4500 {}
4501 };
4502
sendRequestedMedia(u16 peer_id,const std::list<std::string> & tosend)4503 void Server::sendRequestedMedia(u16 peer_id,
4504 const std::list<std::string> &tosend)
4505 {
4506 DSTACK(__FUNCTION_NAME);
4507
4508 verbosestream<<"Server::sendRequestedMedia(): "
4509 <<"Sending files to client"<<std::endl;
4510
4511 /* Read files */
4512
4513 // Put 5kB in one bunch (this is not accurate)
4514 u32 bytes_per_bunch = 5000;
4515
4516 std::vector< std::list<SendableMedia> > file_bunches;
4517 file_bunches.push_back(std::list<SendableMedia>());
4518
4519 u32 file_size_bunch_total = 0;
4520
4521 for(std::list<std::string>::const_iterator i = tosend.begin();
4522 i != tosend.end(); ++i)
4523 {
4524 const std::string &name = *i;
4525
4526 if(m_media.find(name) == m_media.end()){
4527 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4528 <<"unknown file \""<<(name)<<"\""<<std::endl;
4529 continue;
4530 }
4531
4532 //TODO get path + name
4533 std::string tpath = m_media[name].path;
4534
4535 // Read data
4536 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4537 if(fis.good() == false){
4538 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4539 <<tpath<<"\" for reading"<<std::endl;
4540 continue;
4541 }
4542 std::ostringstream tmp_os(std::ios_base::binary);
4543 bool bad = false;
4544 for(;;){
4545 char buf[1024];
4546 fis.read(buf, 1024);
4547 std::streamsize len = fis.gcount();
4548 tmp_os.write(buf, len);
4549 file_size_bunch_total += len;
4550 if(fis.eof())
4551 break;
4552 if(!fis.good()){
4553 bad = true;
4554 break;
4555 }
4556 }
4557 if(bad){
4558 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4559 <<name<<"\""<<std::endl;
4560 continue;
4561 }
4562 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4563 <<tname<<"\""<<std::endl;*/
4564 // Put in list
4565 file_bunches[file_bunches.size()-1].push_back(
4566 SendableMedia(name, tpath, tmp_os.str()));
4567
4568 // Start next bunch if got enough data
4569 if(file_size_bunch_total >= bytes_per_bunch){
4570 file_bunches.push_back(std::list<SendableMedia>());
4571 file_size_bunch_total = 0;
4572 }
4573
4574 }
4575
4576 /* Create and send packets */
4577
4578 u32 num_bunches = file_bunches.size();
4579 for(u32 i=0; i<num_bunches; i++)
4580 {
4581 std::ostringstream os(std::ios_base::binary);
4582
4583 /*
4584 u16 command
4585 u16 total number of texture bunches
4586 u16 index of this bunch
4587 u32 number of files in this bunch
4588 for each file {
4589 u16 length of name
4590 string name
4591 u32 length of data
4592 data
4593 }
4594 */
4595
4596 writeU16(os, TOCLIENT_MEDIA);
4597 writeU16(os, num_bunches);
4598 writeU16(os, i);
4599 writeU32(os, file_bunches[i].size());
4600
4601 for(std::list<SendableMedia>::iterator
4602 j = file_bunches[i].begin();
4603 j != file_bunches[i].end(); ++j){
4604 os<<serializeString(j->name);
4605 os<<serializeLongString(j->data);
4606 }
4607
4608 // Make data buffer
4609 std::string s = os.str();
4610 verbosestream<<"Server::sendRequestedMedia(): bunch "
4611 <<i<<"/"<<num_bunches
4612 <<" files="<<file_bunches[i].size()
4613 <<" size=" <<s.size()<<std::endl;
4614 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4615 // Send as reliable
4616 m_clients.send(peer_id, 2, data, true);
4617 }
4618 }
4619
sendDetachedInventory(const std::string & name,u16 peer_id)4620 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4621 {
4622 if(m_detached_inventories.count(name) == 0){
4623 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4624 return;
4625 }
4626 Inventory *inv = m_detached_inventories[name];
4627
4628 std::ostringstream os(std::ios_base::binary);
4629 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4630 os<<serializeString(name);
4631 inv->serialize(os);
4632
4633 // Make data buffer
4634 std::string s = os.str();
4635 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4636
4637 if (peer_id != PEER_ID_INEXISTENT)
4638 {
4639 // Send as reliable
4640 m_clients.send(peer_id, 0, data, true);
4641 }
4642 else
4643 {
4644 m_clients.sendToAll(0,data,true);
4645 }
4646 }
4647
sendDetachedInventories(u16 peer_id)4648 void Server::sendDetachedInventories(u16 peer_id)
4649 {
4650 DSTACK(__FUNCTION_NAME);
4651
4652 for(std::map<std::string, Inventory*>::iterator
4653 i = m_detached_inventories.begin();
4654 i != m_detached_inventories.end(); i++){
4655 const std::string &name = i->first;
4656 //Inventory *inv = i->second;
4657 sendDetachedInventory(name, peer_id);
4658 }
4659 }
4660
4661 /*
4662 Something random
4663 */
4664
DiePlayer(u16 peer_id)4665 void Server::DiePlayer(u16 peer_id)
4666 {
4667 DSTACK(__FUNCTION_NAME);
4668
4669 PlayerSAO *playersao = getPlayerSAO(peer_id);
4670 assert(playersao);
4671
4672 infostream<<"Server::DiePlayer(): Player "
4673 <<playersao->getPlayer()->getName()
4674 <<" dies"<<std::endl;
4675
4676 playersao->setHP(0);
4677
4678 // Trigger scripted stuff
4679 m_script->on_dieplayer(playersao);
4680
4681 SendPlayerHP(peer_id);
4682 SendDeathscreen(peer_id, false, v3f(0,0,0));
4683
4684 stat.add("die", playersao->getPlayer()->getName());
4685 }
4686
RespawnPlayer(u16 peer_id)4687 void Server::RespawnPlayer(u16 peer_id)
4688 {
4689 DSTACK(__FUNCTION_NAME);
4690
4691 PlayerSAO *playersao = getPlayerSAO(peer_id);
4692 assert(playersao);
4693
4694 infostream<<"Server::RespawnPlayer(): Player "
4695 <<playersao->getPlayer()->getName()
4696 <<" respawns"<<std::endl;
4697
4698 playersao->setHP(PLAYER_MAX_HP);
4699
4700 bool repositioned = m_script->on_respawnplayer(playersao);
4701 if(!repositioned){
4702 v3f pos = findSpawnPos(m_env->getServerMap());
4703 playersao->setPos(pos);
4704 }
4705
4706 stat.add("respawn", playersao->getPlayer()->getName());
4707 }
4708
DenyAccess(u16 peer_id,const std::wstring & reason)4709 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4710 {
4711 DSTACK(__FUNCTION_NAME);
4712
4713 SendAccessDenied(peer_id, reason);
4714 m_clients.event(peer_id, CSE_SetDenied);
4715 m_con.DisconnectPeer(peer_id);
4716 }
4717
DeleteClient(u16 peer_id,ClientDeletionReason reason)4718 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4719 {
4720 DSTACK(__FUNCTION_NAME);
4721 std::wstring message;
4722 {
4723 /*
4724 Clear references to playing sounds
4725 */
4726 for(std::map<s32, ServerPlayingSound>::iterator
4727 i = m_playing_sounds.begin();
4728 i != m_playing_sounds.end();)
4729 {
4730 ServerPlayingSound &psound = i->second;
4731 psound.clients.erase(peer_id);
4732 if(psound.clients.size() == 0)
4733 m_playing_sounds.erase(i++);
4734 else
4735 i++;
4736 }
4737
4738 Player *player = m_env->getPlayer(peer_id);
4739
4740 // Collect information about leaving in chat
4741 {
4742 if(player != NULL && reason != CDR_DENY)
4743 {
4744 std::wstring name = narrow_to_wide(player->getName());
4745 message += L"*** ";
4746 message += name;
4747 message += L" left the game.";
4748 if(reason == CDR_TIMEOUT)
4749 message += L" (timed out)";
4750 }
4751 }
4752
4753 /* Run scripts and remove from environment */
4754 {
4755 if(player != NULL)
4756 {
4757 PlayerSAO *playersao = player->getPlayerSAO();
4758 assert(playersao);
4759
4760 //JMutexAutoLock env_lock(m_env_mutex);
4761 m_script->on_leaveplayer(playersao);
4762
4763 playersao->disconnected();
4764 }
4765 }
4766
4767 /*
4768 Print out action
4769 */
4770 {
4771 if(player != NULL && reason != CDR_DENY)
4772 {
4773 std::ostringstream os(std::ios_base::binary);
4774 std::list<u16> clients = m_clients.getClientIDs();
4775
4776 for(std::list<u16>::iterator
4777 i = clients.begin();
4778 i != clients.end(); ++i)
4779 {
4780 // Get player
4781 Player *player = m_env->getPlayer(*i);
4782 if(!player)
4783 continue;
4784 // Get name of player
4785 os<<player->getName()<<" ";
4786 }
4787
4788 actionstream<<player->getName()<<" "
4789 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4790 <<" List of players: "<<os.str()<<std::endl;
4791 }
4792 }
4793 {
4794 //JMutexAutoLock env_lock(m_env_mutex);
4795 m_clients.DeleteClient(peer_id);
4796 }
4797 }
4798
4799 // Send leave chat message to all remaining clients
4800 if(message.length() != 0)
4801 SendChatMessage(PEER_ID_INEXISTENT,message);
4802 }
4803
UpdateCrafting(u16 peer_id)4804 void Server::UpdateCrafting(u16 peer_id)
4805 {
4806 DSTACK(__FUNCTION_NAME);
4807
4808 Player* player = m_env->getPlayer(peer_id);
4809 assert(player);
4810
4811 // Get a preview for crafting
4812 ItemStack preview;
4813 InventoryLocation loc;
4814 loc.setPlayer(player->getName());
4815 getCraftingResult(&player->inventory, preview, false, this);
4816 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
4817
4818 // Put the new preview in
4819 InventoryList *plist = player->inventory.getList("craftpreview");
4820 assert(plist);
4821 assert(plist->getSize() >= 1);
4822 plist->changeItem(0, preview);
4823 }
4824
getClient(u16 peer_id,ClientState state_min)4825 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
4826 {
4827 RemoteClient *client = getClientNoEx(peer_id,state_min);
4828 if(!client)
4829 throw ClientNotFoundException("Client not found");
4830
4831 return client;
4832 }
getClientNoEx(u16 peer_id,ClientState state_min)4833 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
4834 {
4835 return m_clients.getClientNoEx(peer_id, state_min);
4836 }
4837
getPlayerName(u16 peer_id)4838 std::string Server::getPlayerName(u16 peer_id)
4839 {
4840 Player *player = m_env->getPlayer(peer_id);
4841 if(player == NULL)
4842 return "[id="+itos(peer_id)+"]";
4843 return player->getName();
4844 }
4845
getPlayerSAO(u16 peer_id)4846 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4847 {
4848 Player *player = m_env->getPlayer(peer_id);
4849 if(player == NULL)
4850 return NULL;
4851 return player->getPlayerSAO();
4852 }
4853
getStatusString()4854 std::wstring Server::getStatusString()
4855 {
4856 std::wostringstream os(std::ios_base::binary);
4857 os<<L"# Server: ";
4858 // Version
4859 os<<L"version="<<narrow_to_wide(minetest_version_simple);
4860 // Uptime
4861 os<<L", uptime="<<m_uptime.get();
4862 // Max lag estimate
4863 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4864 // Information about clients
4865 bool first = true;
4866 os<<L", clients={";
4867 std::list<u16> clients = m_clients.getClientIDs();
4868 for(std::list<u16>::iterator i = clients.begin();
4869 i != clients.end(); ++i)
4870 {
4871 // Get player
4872 Player *player = m_env->getPlayer(*i);
4873 // Get name of player
4874 std::wstring name = L"unknown";
4875 if(player != NULL)
4876 name = narrow_to_wide(player->getName());
4877 // Add name to information string
4878 if(!first)
4879 os<<L", ";
4880 else
4881 first = false;
4882 os<<name;
4883 }
4884 os<<L"}";
4885 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4886 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4887 if(g_settings->get("motd") != "")
4888 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4889 return os.str();
4890 }
4891
getPlayerEffectivePrivs(const std::string & name)4892 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4893 {
4894 std::set<std::string> privs;
4895 m_script->getAuth(name, NULL, &privs);
4896 return privs;
4897 }
4898
checkPriv(const std::string & name,const std::string & priv)4899 bool Server::checkPriv(const std::string &name, const std::string &priv)
4900 {
4901 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4902 return (privs.count(priv) != 0);
4903 }
4904
reportPrivsModified(const std::string & name)4905 void Server::reportPrivsModified(const std::string &name)
4906 {
4907 if(name == ""){
4908 std::list<u16> clients = m_clients.getClientIDs();
4909 for(std::list<u16>::iterator
4910 i = clients.begin();
4911 i != clients.end(); ++i){
4912 Player *player = m_env->getPlayer(*i);
4913 reportPrivsModified(player->getName());
4914 }
4915 } else {
4916 Player *player = m_env->getPlayer(name.c_str());
4917 if(!player)
4918 return;
4919 SendPlayerPrivileges(player->peer_id);
4920 PlayerSAO *sao = player->getPlayerSAO();
4921 if(!sao)
4922 return;
4923 sao->updatePrivileges(
4924 getPlayerEffectivePrivs(name),
4925 isSingleplayer());
4926 }
4927 }
4928
reportInventoryFormspecModified(const std::string & name)4929 void Server::reportInventoryFormspecModified(const std::string &name)
4930 {
4931 Player *player = m_env->getPlayer(name.c_str());
4932 if(!player)
4933 return;
4934 SendPlayerInventoryFormspec(player->peer_id);
4935 }
4936
setIpBanned(const std::string & ip,const std::string & name)4937 void Server::setIpBanned(const std::string &ip, const std::string &name)
4938 {
4939 m_banmanager->add(ip, name);
4940 }
4941
unsetIpBanned(const std::string & ip_or_name)4942 void Server::unsetIpBanned(const std::string &ip_or_name)
4943 {
4944 m_banmanager->remove(ip_or_name);
4945 }
4946
getBanDescription(const std::string & ip_or_name)4947 std::string Server::getBanDescription(const std::string &ip_or_name)
4948 {
4949 return m_banmanager->getBanDescription(ip_or_name);
4950 }
4951
notifyPlayer(const char * name,const std::wstring & msg)4952 void Server::notifyPlayer(const char *name, const std::wstring &msg)
4953 {
4954 Player *player = m_env->getPlayer(name);
4955 if(!player)
4956 return;
4957
4958 if (player->peer_id == PEER_ID_INEXISTENT)
4959 return;
4960
4961 SendChatMessage(player->peer_id, std::wstring(L"\vffffff")+msg);
4962 }
4963
showFormspec(const char * playername,const std::string & formspec,const std::string & formname)4964 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4965 {
4966 Player *player = m_env->getPlayer(playername);
4967
4968 if(!player)
4969 {
4970 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4971 return false;
4972 }
4973
4974 SendShowFormspecMessage(player->peer_id, formspec, formname);
4975 return true;
4976 }
4977
hudAdd(Player * player,HudElement * form)4978 u32 Server::hudAdd(Player *player, HudElement *form) {
4979 if (!player)
4980 return -1;
4981
4982 u32 id = player->addHud(form);
4983
4984 SendHUDAdd(player->peer_id, id, form);
4985
4986 return id;
4987 }
4988
hudRemove(Player * player,u32 id)4989 bool Server::hudRemove(Player *player, u32 id) {
4990 if (!player)
4991 return false;
4992
4993 HudElement* todel = player->removeHud(id);
4994
4995 if (!todel)
4996 return false;
4997
4998 delete todel;
4999
5000 SendHUDRemove(player->peer_id, id);
5001 return true;
5002 }
5003
hudChange(Player * player,u32 id,HudElementStat stat,void * data)5004 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
5005 if (!player)
5006 return false;
5007
5008 SendHUDChange(player->peer_id, id, stat, data);
5009 return true;
5010 }
5011
hudSetFlags(Player * player,u32 flags,u32 mask)5012 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
5013 if (!player)
5014 return false;
5015
5016 SendHUDSetFlags(player->peer_id, flags, mask);
5017 player->hud_flags = flags;
5018
5019 PlayerSAO* playersao = player->getPlayerSAO();
5020
5021 if (playersao == NULL)
5022 return false;
5023
5024 m_script->player_event(playersao, "hud_changed");
5025 return true;
5026 }
5027
hudSetHotbarItemcount(Player * player,s32 hotbar_itemcount)5028 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
5029 if (!player)
5030 return false;
5031 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
5032 return false;
5033
5034 std::ostringstream os(std::ios::binary);
5035 writeS32(os, hotbar_itemcount);
5036 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
5037 return true;
5038 }
5039
hudSetHotbarImage(Player * player,std::string name)5040 void Server::hudSetHotbarImage(Player *player, std::string name) {
5041 if (!player)
5042 return;
5043
5044 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
5045 }
5046
hudSetHotbarSelectedImage(Player * player,std::string name)5047 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
5048 if (!player)
5049 return;
5050
5051 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
5052 }
5053
setLocalPlayerAnimations(Player * player,v2s32 animation_frames[4],f32 frame_speed)5054 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
5055 {
5056 if (!player)
5057 return false;
5058
5059 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
5060 return true;
5061 }
5062
setPlayerEyeOffset(Player * player,v3f first,v3f third)5063 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
5064 {
5065 if (!player)
5066 return false;
5067
5068 SendEyeOffset(player->peer_id, first, third);
5069 return true;
5070 }
5071
setSky(Player * player,const video::SColor & bgcolor,const std::string & type,const std::vector<std::string> & params)5072 bool Server::setSky(Player *player, const video::SColor &bgcolor,
5073 const std::string &type, const std::vector<std::string> ¶ms)
5074 {
5075 if (!player)
5076 return false;
5077
5078 SendSetSky(player->peer_id, bgcolor, type, params);
5079 return true;
5080 }
5081
overrideDayNightRatio(Player * player,bool do_override,float ratio)5082 bool Server::overrideDayNightRatio(Player *player, bool do_override,
5083 float ratio)
5084 {
5085 if (!player)
5086 return false;
5087
5088 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
5089 return true;
5090 }
5091
notifyPlayers(const std::wstring & msg)5092 void Server::notifyPlayers(const std::wstring &msg)
5093 {
5094 SendChatMessage(PEER_ID_INEXISTENT,msg);
5095 }
5096
spawnParticle(const char * playername,v3f pos,v3f velocity,v3f acceleration,float expirationtime,float size,bool collisiondetection,bool vertical,std::string texture)5097 void Server::spawnParticle(const char *playername, v3f pos,
5098 v3f velocity, v3f acceleration,
5099 float expirationtime, float size, bool
5100 collisiondetection, bool vertical, std::string texture)
5101 {
5102 Player *player = m_env->getPlayer(playername);
5103 if(!player)
5104 return;
5105 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
5106 expirationtime, size, collisiondetection, vertical, texture);
5107 }
5108
spawnParticleAll(v3f pos,v3f velocity,v3f acceleration,float expirationtime,float size,bool collisiondetection,bool vertical,std::string texture)5109 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
5110 float expirationtime, float size,
5111 bool collisiondetection, bool vertical, std::string texture)
5112 {
5113 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
5114 expirationtime, size, collisiondetection, vertical, texture);
5115 }
5116
addParticleSpawner(const char * playername,u16 amount,float spawntime,v3f minpos,v3f maxpos,v3f minvel,v3f maxvel,v3f minacc,v3f maxacc,float minexptime,float maxexptime,float minsize,float maxsize,bool collisiondetection,bool vertical,std::string texture)5117 u32 Server::addParticleSpawner(const char *playername,
5118 u16 amount, float spawntime,
5119 v3f minpos, v3f maxpos,
5120 v3f minvel, v3f maxvel,
5121 v3f minacc, v3f maxacc,
5122 float minexptime, float maxexptime,
5123 float minsize, float maxsize,
5124 bool collisiondetection, bool vertical, std::string texture)
5125 {
5126 Player *player = m_env->getPlayer(playername);
5127 if(!player)
5128 return -1;
5129
5130 u32 id = 0;
5131 for(;;) // look for unused particlespawner id
5132 {
5133 id++;
5134 if (std::find(m_particlespawner_ids.begin(),
5135 m_particlespawner_ids.end(), id)
5136 == m_particlespawner_ids.end())
5137 {
5138 m_particlespawner_ids.push_back(id);
5139 break;
5140 }
5141 }
5142
5143 SendAddParticleSpawner(player->peer_id, amount, spawntime,
5144 minpos, maxpos, minvel, maxvel, minacc, maxacc,
5145 minexptime, maxexptime, minsize, maxsize,
5146 collisiondetection, vertical, texture, id);
5147
5148 return id;
5149 }
5150
addParticleSpawnerAll(u16 amount,float spawntime,v3f minpos,v3f maxpos,v3f minvel,v3f maxvel,v3f minacc,v3f maxacc,float minexptime,float maxexptime,float minsize,float maxsize,bool collisiondetection,bool vertical,std::string texture)5151 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
5152 v3f minpos, v3f maxpos,
5153 v3f minvel, v3f maxvel,
5154 v3f minacc, v3f maxacc,
5155 float minexptime, float maxexptime,
5156 float minsize, float maxsize,
5157 bool collisiondetection, bool vertical, std::string texture)
5158 {
5159 u32 id = 0;
5160 for(;;) // look for unused particlespawner id
5161 {
5162 id++;
5163 if (std::find(m_particlespawner_ids.begin(),
5164 m_particlespawner_ids.end(), id)
5165 == m_particlespawner_ids.end())
5166 {
5167 m_particlespawner_ids.push_back(id);
5168 break;
5169 }
5170 }
5171
5172 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
5173 minpos, maxpos, minvel, maxvel, minacc, maxacc,
5174 minexptime, maxexptime, minsize, maxsize,
5175 collisiondetection, vertical, texture, id);
5176
5177 return id;
5178 }
5179
deleteParticleSpawner(const char * playername,u32 id)5180 void Server::deleteParticleSpawner(const char *playername, u32 id)
5181 {
5182 Player *player = m_env->getPlayer(playername);
5183 if(!player)
5184 return;
5185
5186 m_particlespawner_ids.erase(
5187 std::remove(m_particlespawner_ids.begin(),
5188 m_particlespawner_ids.end(), id),
5189 m_particlespawner_ids.end());
5190 SendDeleteParticleSpawner(player->peer_id, id);
5191 }
5192
deleteParticleSpawnerAll(u32 id)5193 void Server::deleteParticleSpawnerAll(u32 id)
5194 {
5195 m_particlespawner_ids.erase(
5196 std::remove(m_particlespawner_ids.begin(),
5197 m_particlespawner_ids.end(), id),
5198 m_particlespawner_ids.end());
5199 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
5200 }
5201
createDetachedInventory(const std::string & name)5202 Inventory* Server::createDetachedInventory(const std::string &name)
5203 {
5204 if(m_detached_inventories.count(name) > 0){
5205 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
5206 delete m_detached_inventories[name];
5207 } else {
5208 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
5209 }
5210 Inventory *inv = new Inventory(m_itemdef);
5211 assert(inv);
5212 m_detached_inventories[name] = inv;
5213 //TODO find a better way to do this
5214 sendDetachedInventory(name,PEER_ID_INEXISTENT);
5215 return inv;
5216 }
5217
5218 class BoolScopeSet
5219 {
5220 public:
BoolScopeSet(bool * dst,bool val)5221 BoolScopeSet(bool *dst, bool val):
5222 m_dst(dst)
5223 {
5224 m_orig_state = *m_dst;
5225 *m_dst = val;
5226 }
~BoolScopeSet()5227 ~BoolScopeSet()
5228 {
5229 *m_dst = m_orig_state;
5230 }
5231 private:
5232 bool *m_dst;
5233 bool m_orig_state;
5234 };
5235
5236 // actions: time-reversed list
5237 // Return value: success/failure
rollbackRevertActions(const std::list<RollbackAction> & actions,std::list<std::string> * log)5238 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
5239 std::list<std::string> *log)
5240 {
5241 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
5242 ServerMap *map = (ServerMap*)(&m_env->getMap());
5243
5244 // Fail if no actions to handle
5245 if(actions.empty()){
5246 log->push_back("Nothing to do.");
5247 return false;
5248 }
5249
5250 int num_tried = 0;
5251 int num_failed = 0;
5252
5253 for(std::list<RollbackAction>::const_iterator
5254 i = actions.begin();
5255 i != actions.end(); i++)
5256 {
5257 const RollbackAction &action = *i;
5258 num_tried++;
5259 bool success = action.applyRevert(map, this, this);
5260 if(!success){
5261 num_failed++;
5262 std::ostringstream os;
5263 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
5264 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
5265 if(log)
5266 log->push_back(os.str());
5267 }else{
5268 std::ostringstream os;
5269 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
5270 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
5271 if(log)
5272 log->push_back(os.str());
5273 }
5274 }
5275
5276 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
5277 <<" failed"<<std::endl;
5278
5279 // Call it done if less than half failed
5280 return num_failed <= num_tried/2;
5281 }
5282
5283 // IGameDef interface
5284 // Under envlock
getItemDefManager()5285 IItemDefManager* Server::getItemDefManager()
5286 {
5287 return m_itemdef;
5288 }
getNodeDefManager()5289 INodeDefManager* Server::getNodeDefManager()
5290 {
5291 return m_nodedef;
5292 }
getCraftDefManager()5293 ICraftDefManager* Server::getCraftDefManager()
5294 {
5295 return m_craftdef;
5296 }
getTextureSource()5297 ITextureSource* Server::getTextureSource()
5298 {
5299 return NULL;
5300 }
getShaderSource()5301 IShaderSource* Server::getShaderSource()
5302 {
5303 return NULL;
5304 }
getSceneManager()5305 scene::ISceneManager* Server::getSceneManager()
5306 {
5307 return NULL;
5308 }
5309
allocateUnknownNodeId(const std::string & name)5310 u16 Server::allocateUnknownNodeId(const std::string &name)
5311 {
5312 return m_nodedef->allocateDummy(name);
5313 }
getSoundManager()5314 ISoundManager* Server::getSoundManager()
5315 {
5316 return &dummySoundManager;
5317 }
getEventManager()5318 MtEventManager* Server::getEventManager()
5319 {
5320 return m_event;
5321 }
5322
getWritableItemDefManager()5323 IWritableItemDefManager* Server::getWritableItemDefManager()
5324 {
5325 return m_itemdef;
5326 }
getWritableNodeDefManager()5327 IWritableNodeDefManager* Server::getWritableNodeDefManager()
5328 {
5329 return m_nodedef;
5330 }
getWritableCraftDefManager()5331 IWritableCraftDefManager* Server::getWritableCraftDefManager()
5332 {
5333 return m_craftdef;
5334 }
5335
getModSpec(const std::string & modname)5336 const ModSpec* Server::getModSpec(const std::string &modname)
5337 {
5338 for(std::vector<ModSpec>::iterator i = m_mods.begin();
5339 i != m_mods.end(); i++){
5340 const ModSpec &mod = *i;
5341 if(mod.name == modname)
5342 return &mod;
5343 }
5344 return NULL;
5345 }
getModNames(std::list<std::string> & modlist)5346 void Server::getModNames(std::list<std::string> &modlist)
5347 {
5348 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
5349 {
5350 modlist.push_back(i->name);
5351 }
5352 }
getBuiltinLuaPath()5353 std::string Server::getBuiltinLuaPath()
5354 {
5355 return porting::path_share + DIR_DELIM + "builtin";
5356 }
5357
findSpawnPos(ServerMap & map)5358 v3f findSpawnPos(ServerMap &map)
5359 {
5360 //return v3f(50,50,50)*BS;
5361
5362 v3s16 nodepos;
5363
5364 #if 0
5365 nodepos = v2s16(0,0);
5366 groundheight = 20;
5367 #endif
5368
5369 #if 1
5370 s16 water_level = map.getWaterLevel();
5371
5372 // Try to find a good place a few times
5373 for(s32 i=0; i<1000; i++)
5374 {
5375 s32 range = 1 + i;
5376 // We're going to try to throw the player to this position
5377 v2s16 nodepos2d = v2s16(
5378 -range + (myrand() % (range * 2)),
5379 -range + (myrand() % (range * 2)));
5380
5381 // Get ground height at point
5382 s16 groundheight = map.findGroundLevel(nodepos2d, g_settings->getBool("cache_block_before_spawn"));
5383 if (groundheight <= water_level) // Don't go underwater
5384 continue;
5385 if (groundheight > water_level + g_settings->getS16("max_spawn_height")) // Don't go to high places
5386 continue;
5387
5388 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
5389 bool is_good = false;
5390 s32 air_count = 0;
5391 for (s32 i = 0; i < 10; i++) {
5392 v3s16 blockpos = getNodeBlockPos(nodepos);
5393 map.emergeBlock(blockpos, true);
5394 content_t c = map.getNodeNoEx(nodepos).getContent();
5395 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
5396 air_count++;
5397 if (air_count >= 2){
5398 is_good = true;
5399 break;
5400 }
5401 }
5402 nodepos.Y++;
5403 }
5404 if(is_good){
5405 // Found a good place
5406 //infostream<<"Searched through "<<i<<" places."<<std::endl;
5407 break;
5408 }
5409 }
5410 #endif
5411
5412 return intToFloat(nodepos, BS);
5413 }
5414
emergePlayer(const char * name,u16 peer_id)5415 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
5416 {
5417 RemotePlayer *player = NULL;
5418 bool newplayer = false;
5419
5420 /*
5421 Try to get an existing player
5422 */
5423 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
5424
5425 // If player is already connected, cancel
5426 if(player != NULL && player->peer_id != 0)
5427 {
5428 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5429 return NULL;
5430 }
5431
5432 /*
5433 If player with the wanted peer_id already exists, cancel.
5434 */
5435 if(m_env->getPlayer(peer_id) != NULL)
5436 {
5437 infostream<<"emergePlayer(): Player with wrong name but same"
5438 " peer_id already exists"<<std::endl;
5439 return NULL;
5440 }
5441
5442 if (!player && maintenance_status) {
5443 infostream<<"emergePlayer(): Maintenance in progress, disallowing loading player"<<std::endl;
5444 return nullptr;
5445 }
5446
5447 // Load player if it isn't already loaded
5448 if (!player) {
5449 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
5450 }
5451
5452 // Create player if it doesn't exist
5453 if (!player) {
5454 newplayer = true;
5455 player = new RemotePlayer(this, name);
5456 // Set player position
5457 infostream<<"Server: Finding spawn place for player \""
5458 <<name<<"\""<<std::endl;
5459 v3f pos = findSpawnPos(m_env->getServerMap());
5460 player->setPosition(pos);
5461
5462 // Add player to environment
5463 m_env->addPlayer(player);
5464 }
5465
5466 // Create a new player active object
5467 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5468 getPlayerEffectivePrivs(player->getName()),
5469 isSingleplayer());
5470
5471 /* Clean up old HUD elements from previous sessions */
5472 player->clearHud();
5473
5474 /* Add object to environment */
5475 m_env->addActiveObject(playersao);
5476
5477 /* Run scripts */
5478 if (newplayer) {
5479 m_script->on_newplayer(playersao);
5480 }
5481
5482 return playersao;
5483 }
5484
dedicated_server_loop(Server & server,bool & kill)5485 void dedicated_server_loop(Server &server, bool &kill)
5486 {
5487 DSTACK(__FUNCTION_NAME);
5488
5489 IntervalLimiter m_profiler_interval;
5490
5491 int errors = 0;
5492 float steplen = g_settings->getFloat("dedicated_server_step");
5493 for(;;)
5494 {
5495 // This is kind of a hack but can be done like this
5496 // because server.step() is very light
5497 {
5498 /*
5499 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5500 */
5501 sleep_ms((int)(steplen*1000.0));
5502 }
5503 try {
5504 server.step(steplen);
5505 }
5506 //TODO: more errors here
5507 catch(std::exception &e) {
5508 if (!errors++ || !(errors % (int)(60/steplen)))
5509 errorstream<<"Fatal error n="<<errors<< " : "<<e.what()<<std::endl;
5510 }
5511 catch (...){
5512 if (!errors++ || !(errors % (int)(60/steplen)))
5513 errorstream<<"Fatal error unknown "<<errors<<std::endl;
5514 }
5515 if(server.getShutdownRequested() || kill)
5516 {
5517 infostream<<"Dedicated server quitting"<<std::endl;
5518 #if USE_CURL
5519 if(g_settings->getBool("server_announce") == true)
5520 ServerList::sendAnnounce("delete");
5521 #endif
5522 break;
5523 }
5524
5525 /*
5526 Profiler
5527 */
5528 float profiler_print_interval =
5529 g_settings->getFloat("profiler_print_interval");
5530 if(server.m_clients.getClientList().size() && profiler_print_interval != 0)
5531 {
5532 if(m_profiler_interval.step(steplen, profiler_print_interval))
5533 {
5534 infostream<<"Profiler:"<<std::endl;
5535 g_profiler->print(infostream);
5536 g_profiler->clear();
5537 }
5538 }
5539 }
5540 }
5541
5542
5543
5544
5545
5546
5547 //freeminer:
5548
deleteDetachedInventory(const std::string & name)5549 void Server::deleteDetachedInventory(const std::string &name)
5550 {
5551 if(m_detached_inventories.count(name) > 0){
5552 infostream<<"Server deleting detached inventory \""<<name<<"\""<<std::endl;
5553 delete m_detached_inventories[name];
5554 m_detached_inventories.erase(name);
5555 }
5556 }
5557
maintenance_start()5558 void Server::maintenance_start() {
5559 infostream<<"Server: Starting maintenance: saving..."<<std::endl;
5560 m_emerge->stopThreads();
5561 save(0.1);
5562 m_env->getServerMap().m_map_saving_enabled = false;
5563 m_env->getServerMap().m_map_loading_enabled = false;
5564 m_env->getServerMap().dbase->close();
5565 m_env->m_key_value_storage->close();
5566 m_env->m_players_storage->close();
5567 stat.close();
5568 actionstream<<"Server: Starting maintenance: bases closed now."<<std::endl;
5569
5570 };
5571
maintenance_end()5572 void Server::maintenance_end() {
5573 m_env->getServerMap().dbase->open();
5574 m_env->m_key_value_storage->open();
5575 m_env->m_players_storage->open();
5576 stat.open();
5577 m_env->getServerMap().m_map_saving_enabled = true;
5578 m_env->getServerMap().m_map_loading_enabled = true;
5579 m_emerge->startThreads();
5580 actionstream<<"Server: Starting maintenance: ended."<<std::endl;
5581 };
5582