Line data Source code
1 : /*
2 : Minetest
3 : Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4 :
5 : This program is free software; you can redistribute it and/or modify
6 : it under the terms of the GNU Lesser General Public License as published by
7 : the Free Software Foundation; either version 2.1 of the License, or
8 : (at your option) any later version.
9 :
10 : This program is distributed in the hope that it will be useful,
11 : but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : GNU Lesser General Public License for more details.
14 :
15 : You should have received a copy of the GNU Lesser General Public License along
16 : with this program; if not, write to the Free Software Foundation, Inc.,
17 : 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 : */
19 :
20 : #include "server.h"
21 : #include <iostream>
22 : #include <queue>
23 : #include <algorithm>
24 : #include "network/networkprotocol.h"
25 : #include "network/serveropcodes.h"
26 : #include "ban.h"
27 : #include "environment.h"
28 : #include "map.h"
29 : #include "jthread/jmutexautolock.h"
30 : #include "constants.h"
31 : #include "voxel.h"
32 : #include "config.h"
33 : #include "version.h"
34 : #include "filesys.h"
35 : #include "mapblock.h"
36 : #include "serverobject.h"
37 : #include "genericobject.h"
38 : #include "settings.h"
39 : #include "profiler.h"
40 : #include "log.h"
41 : #include "scripting_game.h"
42 : #include "nodedef.h"
43 : #include "itemdef.h"
44 : #include "craftdef.h"
45 : #include "emerge.h"
46 : #include "mapgen.h"
47 : #include "mg_biome.h"
48 : #include "content_mapnode.h"
49 : #include "content_nodemeta.h"
50 : #include "content_abm.h"
51 : #include "content_sao.h"
52 : #include "mods.h"
53 : #include "sound.h" // dummySoundManager
54 : #include "event_manager.h"
55 : #include "serverlist.h"
56 : #include "util/string.h"
57 : #include "util/mathconstants.h"
58 : #include "rollback.h"
59 : #include "util/serialize.h"
60 : #include "util/thread.h"
61 : #include "defaultsettings.h"
62 : #include "util/base64.h"
63 : #include "util/sha1.h"
64 : #include "util/hex.h"
65 :
66 0 : class ClientNotFoundException : public BaseException
67 : {
68 : public:
69 0 : ClientNotFoundException(const char *s):
70 0 : BaseException(s)
71 0 : {}
72 : };
73 :
74 0 : class ServerThread : public JThread
75 : {
76 : Server *m_server;
77 :
78 : public:
79 :
80 0 : ServerThread(Server *server):
81 : JThread(),
82 0 : m_server(server)
83 : {
84 0 : }
85 :
86 : void * Thread();
87 : };
88 :
89 0 : void * ServerThread::Thread()
90 : {
91 0 : log_register_thread("ServerThread");
92 :
93 0 : DSTACK(__FUNCTION_NAME);
94 : BEGIN_DEBUG_EXCEPTION_HANDLER
95 :
96 0 : m_server->AsyncRunStep(true);
97 :
98 0 : ThreadStarted();
99 :
100 0 : porting::setThreadName("ServerThread");
101 :
102 0 : while(!StopRequested())
103 : {
104 : try{
105 : //TimeTaker timer("AsyncRunStep() + Receive()");
106 :
107 0 : m_server->AsyncRunStep();
108 :
109 0 : m_server->Receive();
110 :
111 : }
112 0 : catch(con::NoIncomingDataException &e)
113 : {
114 : }
115 0 : catch(con::PeerNotFoundException &e)
116 : {
117 0 : infostream<<"Server: PeerNotFoundException"<<std::endl;
118 : }
119 0 : catch(ClientNotFoundException &e)
120 : {
121 : }
122 0 : catch(con::ConnectionBindFailed &e)
123 : {
124 0 : m_server->setAsyncFatalError(e.what());
125 : }
126 0 : catch(LuaError &e)
127 : {
128 0 : m_server->setAsyncFatalError(e.what());
129 : }
130 : }
131 :
132 0 : END_DEBUG_EXCEPTION_HANDLER(errorstream)
133 :
134 0 : return NULL;
135 : }
136 :
137 0 : v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
138 : {
139 0 : if(pos_exists) *pos_exists = false;
140 0 : switch(type){
141 : case SSP_LOCAL:
142 0 : return v3f(0,0,0);
143 : case SSP_POSITIONAL:
144 0 : if(pos_exists) *pos_exists = true;
145 0 : return pos;
146 : case SSP_OBJECT: {
147 0 : if(object == 0)
148 0 : return v3f(0,0,0);
149 0 : ServerActiveObject *sao = env->getActiveObject(object);
150 0 : if(!sao)
151 0 : return v3f(0,0,0);
152 0 : if(pos_exists) *pos_exists = true;
153 0 : return sao->getBasePosition(); }
154 : }
155 0 : return v3f(0,0,0);
156 : }
157 :
158 :
159 :
160 : /*
161 : Server
162 : */
163 :
164 0 : Server::Server(
165 : const std::string &path_world,
166 : const SubgameSpec &gamespec,
167 : bool simple_singleplayer_mode,
168 : bool ipv6
169 : ):
170 : m_path_world(path_world),
171 : m_gamespec(gamespec),
172 : m_simple_singleplayer_mode(simple_singleplayer_mode),
173 : m_async_fatal_error(""),
174 : m_env(NULL),
175 : m_con(PROTOCOL_ID,
176 : 512,
177 : CONNECTION_TIMEOUT,
178 : ipv6,
179 : this),
180 : m_banmanager(NULL),
181 : m_rollback(NULL),
182 : m_enable_rollback_recording(false),
183 : m_emerge(NULL),
184 : m_script(NULL),
185 0 : m_itemdef(createItemDefManager()),
186 0 : m_nodedef(createNodeDefManager()),
187 0 : m_craftdef(createCraftDefManager()),
188 0 : m_event(new EventManager()),
189 : m_thread(NULL),
190 : m_time_of_day_send_timer(0),
191 : m_uptime(0),
192 : m_clients(&m_con),
193 : m_shutdown_requested(false),
194 : m_ignore_map_edit_events(false),
195 : m_ignore_map_edit_events_peer_id(0),
196 0 : m_next_sound_id(0)
197 :
198 : {
199 0 : m_liquid_transform_timer = 0.0;
200 0 : m_liquid_transform_every = 1.0;
201 0 : m_print_info_timer = 0.0;
202 0 : m_masterserver_timer = 0.0;
203 0 : m_objectdata_timer = 0.0;
204 0 : m_emergethread_trigger_timer = 0.0;
205 0 : m_savemap_timer = 0.0;
206 :
207 0 : m_step_dtime = 0.0;
208 0 : m_lag = g_settings->getFloat("dedicated_server_step");
209 :
210 0 : if(path_world == "")
211 0 : throw ServerError("Supplied empty world path");
212 :
213 0 : if(!gamespec.isValid())
214 0 : throw ServerError("Supplied invalid gamespec");
215 :
216 0 : infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
217 0 : if(m_simple_singleplayer_mode)
218 0 : infostream<<" in simple singleplayer mode"<<std::endl;
219 : else
220 0 : infostream<<std::endl;
221 0 : infostream<<"- world: "<<m_path_world<<std::endl;
222 0 : infostream<<"- game: "<<m_gamespec.path<<std::endl;
223 :
224 : // Create world if it doesn't exist
225 0 : if(!loadGameConfAndInitWorld(m_path_world, m_gamespec))
226 0 : throw ServerError("Failed to initialize world");
227 :
228 : // Create server thread
229 0 : m_thread = new ServerThread(this);
230 :
231 : // Create emerge manager
232 0 : m_emerge = new EmergeManager(this);
233 :
234 : // Create ban manager
235 0 : std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
236 0 : m_banmanager = new BanManager(ban_path);
237 :
238 0 : ModConfiguration modconf(m_path_world);
239 0 : m_mods = modconf.getMods();
240 0 : std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
241 : // complain about mods with unsatisfied dependencies
242 0 : if(!modconf.isConsistent()) {
243 0 : for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
244 0 : it != unsatisfied_mods.end(); ++it) {
245 0 : ModSpec mod = *it;
246 0 : errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
247 0 : for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
248 0 : dep_it != mod.unsatisfied_depends.end(); ++dep_it)
249 0 : errorstream << " \"" << *dep_it << "\"";
250 0 : errorstream << std::endl;
251 : }
252 : }
253 :
254 0 : Settings worldmt_settings;
255 0 : std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
256 0 : worldmt_settings.readConfigFile(worldmt.c_str());
257 0 : std::vector<std::string> names = worldmt_settings.getNames();
258 0 : std::set<std::string> load_mod_names;
259 0 : for(std::vector<std::string>::iterator it = names.begin();
260 0 : it != names.end(); ++it) {
261 0 : std::string name = *it;
262 0 : if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
263 0 : load_mod_names.insert(name.substr(9));
264 : }
265 : // complain about mods declared to be loaded, but not found
266 0 : for(std::vector<ModSpec>::iterator it = m_mods.begin();
267 0 : it != m_mods.end(); ++it)
268 0 : load_mod_names.erase((*it).name);
269 0 : for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
270 0 : it != unsatisfied_mods.end(); ++it)
271 0 : load_mod_names.erase((*it).name);
272 0 : if(!load_mod_names.empty()) {
273 0 : errorstream << "The following mods could not be found:";
274 0 : for(std::set<std::string>::iterator it = load_mod_names.begin();
275 0 : it != load_mod_names.end(); ++it)
276 0 : errorstream << " \"" << (*it) << "\"";
277 0 : errorstream << std::endl;
278 : }
279 :
280 : // Lock environment
281 0 : JMutexAutoLock envlock(m_env_mutex);
282 :
283 : // Load mapgen params from Settings
284 0 : m_emerge->loadMapgenParams();
285 :
286 : // Create the Map (loads map_meta.txt, overriding configured mapgen params)
287 0 : ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
288 :
289 : // Initialize scripting
290 0 : infostream<<"Server: Initializing Lua"<<std::endl;
291 :
292 0 : m_script = new GameScripting(this);
293 :
294 0 : std::string script_path = getBuiltinLuaPath() + DIR_DELIM "init.lua";
295 0 : std::string error_msg;
296 :
297 0 : if (!m_script->loadMod(script_path, BUILTIN_MOD_NAME, &error_msg))
298 0 : throw ModError("Failed to load and run " + script_path
299 0 : + "\nError from Lua:\n" + error_msg);
300 :
301 : // Print mods
302 0 : infostream << "Server: Loading mods: ";
303 0 : for(std::vector<ModSpec>::iterator i = m_mods.begin();
304 0 : i != m_mods.end(); i++) {
305 0 : const ModSpec &mod = *i;
306 0 : infostream << mod.name << " ";
307 : }
308 0 : infostream << std::endl;
309 : // Load and run "mod" scripts
310 0 : for (std::vector<ModSpec>::iterator i = m_mods.begin();
311 0 : i != m_mods.end(); i++) {
312 0 : const ModSpec &mod = *i;
313 0 : if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
314 0 : std::ostringstream err;
315 0 : err << "Error loading mod \"" << mod.name
316 0 : << "\": mod_name does not follow naming conventions: "
317 0 : << "Only chararacters [a-z0-9_] are allowed." << std::endl;
318 0 : errorstream << err.str().c_str();
319 0 : throw ModError(err.str());
320 : }
321 0 : std::string script_path = mod.path + DIR_DELIM "init.lua";
322 0 : infostream << " [" << padStringRight(mod.name, 12) << "] [\""
323 0 : << script_path << "\"]" << std::endl;
324 0 : if (!m_script->loadMod(script_path, mod.name, &error_msg)) {
325 0 : errorstream << "Server: Failed to load and run "
326 0 : << script_path << std::endl;
327 0 : throw ModError("Failed to load and run " + script_path
328 0 : + "\nError from Lua:\n" + error_msg);
329 : }
330 : }
331 :
332 : // Read Textures and calculate sha1 sums
333 0 : fillMediaCache();
334 :
335 : // Apply item aliases in the node definition manager
336 0 : m_nodedef->updateAliases(m_itemdef);
337 :
338 : // Apply texture overrides from texturepack/override.txt
339 0 : std::string texture_path = g_settings->get("texture_path");
340 0 : if (texture_path != "" && fs::IsDir(texture_path))
341 0 : m_nodedef->applyTextureOverrides(texture_path + DIR_DELIM + "override.txt");
342 :
343 0 : m_nodedef->setNodeRegistrationStatus(true);
344 :
345 : // Perform pending node name resolutions
346 0 : m_nodedef->runNodeResolveCallbacks();
347 :
348 : // init the recipe hashes to speed up crafting
349 0 : m_craftdef->initHashes(this);
350 :
351 : // Initialize Environment
352 0 : m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
353 :
354 0 : m_clients.setEnv(m_env);
355 :
356 : // Initialize mapgens
357 0 : m_emerge->initMapgens();
358 :
359 0 : m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
360 0 : if (m_enable_rollback_recording) {
361 : // Create rollback manager
362 0 : m_rollback = new RollbackManager(m_path_world, this);
363 : }
364 :
365 : // Give environment reference to scripting api
366 0 : m_script->initializeEnvironment(m_env);
367 :
368 : // Register us to receive map edit events
369 0 : servermap->addEventReceiver(this);
370 :
371 : // If file exists, load environment metadata
372 0 : if(fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt"))
373 : {
374 0 : infostream<<"Server: Loading environment metadata"<<std::endl;
375 0 : m_env->loadMeta();
376 : }
377 :
378 : // Add some test ActiveBlockModifiers to environment
379 0 : add_legacy_abms(m_env, m_nodedef);
380 :
381 0 : m_liquid_transform_every = g_settings->getFloat("liquid_update");
382 0 : }
383 :
384 0 : Server::~Server()
385 : {
386 0 : infostream<<"Server destructing"<<std::endl;
387 :
388 : // Send shutdown message
389 0 : SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
390 :
391 : {
392 0 : JMutexAutoLock envlock(m_env_mutex);
393 :
394 : // Execute script shutdown hooks
395 0 : m_script->on_shutdown();
396 :
397 0 : infostream<<"Server: Saving players"<<std::endl;
398 0 : m_env->saveLoadedPlayers();
399 :
400 0 : infostream<<"Server: Saving environment metadata"<<std::endl;
401 0 : m_env->saveMeta();
402 : }
403 :
404 : // Stop threads
405 0 : stop();
406 0 : delete m_thread;
407 :
408 : // stop all emerge threads before deleting players that may have
409 : // requested blocks to be emerged
410 0 : m_emerge->stopThreads();
411 :
412 : // Delete things in the reverse order of creation
413 0 : delete m_env;
414 :
415 : // N.B. the EmergeManager should be deleted after the Environment since Map
416 : // depends on EmergeManager to write its current params to the map meta
417 0 : delete m_emerge;
418 0 : delete m_rollback;
419 0 : delete m_banmanager;
420 0 : delete m_event;
421 0 : delete m_itemdef;
422 0 : delete m_nodedef;
423 0 : delete m_craftdef;
424 :
425 : // Deinitialize scripting
426 0 : infostream<<"Server: Deinitializing scripting"<<std::endl;
427 0 : delete m_script;
428 :
429 : // Delete detached inventories
430 0 : for (std::map<std::string, Inventory*>::iterator
431 0 : i = m_detached_inventories.begin();
432 0 : i != m_detached_inventories.end(); i++) {
433 0 : delete i->second;
434 : }
435 0 : }
436 :
437 0 : void Server::start(Address bind_addr)
438 : {
439 0 : DSTACK(__FUNCTION_NAME);
440 :
441 0 : m_bind_addr = bind_addr;
442 :
443 0 : infostream<<"Starting server on "
444 0 : << bind_addr.serializeString() <<"..."<<std::endl;
445 :
446 : // Stop thread if already running
447 0 : m_thread->Stop();
448 :
449 : // Initialize connection
450 0 : m_con.SetTimeoutMs(30);
451 0 : m_con.Serve(bind_addr);
452 :
453 : // Start thread
454 0 : m_thread->Start();
455 :
456 : // ASCII art for the win!
457 : actionstream
458 0 : <<" .__ __ __ "<<std::endl
459 0 : <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
460 0 : <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
461 0 : <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
462 0 : <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
463 0 : <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
464 0 : actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
465 0 : actionstream<<"Server for gameid=\""<<m_gamespec.id
466 0 : <<"\" listening on "<<bind_addr.serializeString()<<":"
467 0 : <<bind_addr.getPort() << "."<<std::endl;
468 0 : }
469 :
470 0 : void Server::stop()
471 : {
472 0 : DSTACK(__FUNCTION_NAME);
473 :
474 0 : infostream<<"Server: Stopping and waiting threads"<<std::endl;
475 :
476 : // Stop threads (set run=false first so both start stopping)
477 0 : m_thread->Stop();
478 : //m_emergethread.setRun(false);
479 0 : m_thread->Wait();
480 : //m_emergethread.stop();
481 :
482 0 : infostream<<"Server: Threads stopped"<<std::endl;
483 0 : }
484 :
485 0 : void Server::step(float dtime)
486 : {
487 0 : DSTACK(__FUNCTION_NAME);
488 : // Limit a bit
489 0 : if(dtime > 2.0)
490 0 : dtime = 2.0;
491 : {
492 0 : JMutexAutoLock lock(m_step_dtime_mutex);
493 0 : m_step_dtime += dtime;
494 : }
495 : // Throw if fatal error occurred in thread
496 0 : std::string async_err = m_async_fatal_error.get();
497 0 : if(async_err != "") {
498 0 : if (m_simple_singleplayer_mode) {
499 0 : throw ServerError(async_err);
500 : }
501 : else {
502 0 : errorstream << "UNRECOVERABLE error occurred. Stopping server. "
503 0 : << "Please fix the following error:" << std::endl
504 0 : << async_err << std::endl;
505 0 : FATAL_ERROR(async_err.c_str());
506 : }
507 : }
508 0 : }
509 :
510 0 : void Server::AsyncRunStep(bool initial_step)
511 : {
512 0 : DSTACK(__FUNCTION_NAME);
513 :
514 0 : g_profiler->add("Server::AsyncRunStep (num)", 1);
515 :
516 : float dtime;
517 : {
518 0 : JMutexAutoLock lock1(m_step_dtime_mutex);
519 0 : dtime = m_step_dtime;
520 : }
521 :
522 : {
523 : // Send blocks to clients
524 0 : SendBlocks(dtime);
525 : }
526 :
527 0 : if((dtime < 0.001) && (initial_step == false))
528 0 : return;
529 :
530 0 : g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
531 :
532 : //infostream<<"Server steps "<<dtime<<std::endl;
533 : //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
534 :
535 : {
536 0 : JMutexAutoLock lock1(m_step_dtime_mutex);
537 0 : m_step_dtime -= dtime;
538 : }
539 :
540 : /*
541 : Update uptime
542 : */
543 : {
544 0 : m_uptime.set(m_uptime.get() + dtime);
545 : }
546 :
547 0 : handlePeerChanges();
548 :
549 : /*
550 : Update time of day and overall game time
551 : */
552 0 : m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
553 :
554 : /*
555 : Send to clients at constant intervals
556 : */
557 :
558 0 : m_time_of_day_send_timer -= dtime;
559 0 : if(m_time_of_day_send_timer < 0.0) {
560 0 : m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
561 0 : u16 time = m_env->getTimeOfDay();
562 0 : float time_speed = g_settings->getFloat("time_speed");
563 0 : SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
564 : }
565 :
566 : {
567 0 : JMutexAutoLock lock(m_env_mutex);
568 : // Figure out and report maximum lag to environment
569 0 : float max_lag = m_env->getMaxLagEstimate();
570 0 : max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
571 0 : if(dtime > max_lag){
572 0 : if(dtime > 0.1 && dtime > max_lag * 2.0)
573 0 : infostream<<"Server: Maximum lag peaked to "<<dtime
574 0 : <<" s"<<std::endl;
575 0 : max_lag = dtime;
576 : }
577 0 : m_env->reportMaxLagEstimate(max_lag);
578 : // Step environment
579 0 : ScopeProfiler sp(g_profiler, "SEnv step");
580 0 : ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
581 0 : m_env->step(dtime);
582 : }
583 :
584 : static const float map_timer_and_unload_dtime = 2.92;
585 0 : if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
586 : {
587 0 : JMutexAutoLock lock(m_env_mutex);
588 : // Run Map's timers and unload unused data
589 0 : ScopeProfiler sp(g_profiler, "Server: map timer and unload");
590 0 : m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
591 0 : g_settings->getFloat("server_unload_unused_data_timeout"));
592 : }
593 :
594 : /*
595 : Do background stuff
596 : */
597 :
598 : /* Transform liquids */
599 0 : m_liquid_transform_timer += dtime;
600 0 : if(m_liquid_transform_timer >= m_liquid_transform_every)
601 : {
602 0 : m_liquid_transform_timer -= m_liquid_transform_every;
603 :
604 0 : JMutexAutoLock lock(m_env_mutex);
605 :
606 0 : ScopeProfiler sp(g_profiler, "Server: liquid transform");
607 :
608 0 : std::map<v3s16, MapBlock*> modified_blocks;
609 0 : m_env->getMap().transformLiquids(modified_blocks);
610 : #if 0
611 : /*
612 : Update lighting
613 : */
614 : core::map<v3s16, MapBlock*> lighting_modified_blocks;
615 : ServerMap &map = ((ServerMap&)m_env->getMap());
616 : map.updateLighting(modified_blocks, lighting_modified_blocks);
617 :
618 : // Add blocks modified by lighting to modified_blocks
619 : for(core::map<v3s16, MapBlock*>::Iterator
620 : i = lighting_modified_blocks.getIterator();
621 : i.atEnd() == false; i++)
622 : {
623 : MapBlock *block = i.getNode()->getValue();
624 : modified_blocks.insert(block->getPos(), block);
625 : }
626 : #endif
627 : /*
628 : Set the modified blocks unsent for all the clients
629 : */
630 0 : if(!modified_blocks.empty())
631 : {
632 0 : SetBlocksNotSent(modified_blocks);
633 : }
634 : }
635 0 : m_clients.step(dtime);
636 :
637 0 : m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
638 : #if USE_CURL
639 : // send masterserver announce
640 : {
641 0 : float &counter = m_masterserver_timer;
642 0 : if(!isSingleplayer() && (!counter || counter >= 300.0) &&
643 0 : g_settings->getBool("server_announce"))
644 : {
645 0 : ServerList::sendAnnounce(counter ? "update" : "start",
646 0 : m_bind_addr.getPort(),
647 0 : m_clients.getPlayerNames(),
648 : m_uptime.get(),
649 0 : m_env->getGameTime(),
650 : m_lag,
651 : m_gamespec.id,
652 0 : m_emerge->params.mg_name,
653 0 : m_mods);
654 0 : counter = 0.01;
655 : }
656 0 : counter += dtime;
657 : }
658 : #endif
659 :
660 : /*
661 : Check added and deleted active objects
662 : */
663 : {
664 : //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
665 0 : JMutexAutoLock envlock(m_env_mutex);
666 :
667 0 : m_clients.Lock();
668 0 : std::map<u16, RemoteClient*> clients = m_clients.getClientList();
669 0 : ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
670 :
671 : // Radius inside which objects are active
672 0 : s16 radius = g_settings->getS16("active_object_send_range_blocks");
673 0 : s16 player_radius = g_settings->getS16("player_transfer_distance");
674 :
675 0 : if (player_radius == 0 && g_settings->exists("unlimited_player_transfer_distance") &&
676 0 : !g_settings->getBool("unlimited_player_transfer_distance"))
677 0 : player_radius = radius;
678 :
679 0 : radius *= MAP_BLOCKSIZE;
680 0 : player_radius *= MAP_BLOCKSIZE;
681 :
682 0 : for(std::map<u16, RemoteClient*>::iterator
683 0 : i = clients.begin();
684 0 : i != clients.end(); ++i)
685 : {
686 0 : RemoteClient *client = i->second;
687 :
688 : // If definitions and textures have not been sent, don't
689 : // send objects either
690 0 : if (client->getState() < CS_DefinitionsSent)
691 0 : continue;
692 :
693 0 : Player *player = m_env->getPlayer(client->peer_id);
694 0 : if(player==NULL)
695 : {
696 : // This can happen if the client timeouts somehow
697 : /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
698 : <<client->peer_id
699 : <<" has no associated player"<<std::endl;*/
700 0 : continue;
701 : }
702 0 : v3s16 pos = floatToInt(player->getPosition(), BS);
703 :
704 0 : std::set<u16> removed_objects;
705 0 : std::set<u16> added_objects;
706 0 : m_env->getRemovedActiveObjects(pos, radius, player_radius,
707 0 : client->m_known_objects, removed_objects);
708 0 : m_env->getAddedActiveObjects(pos, radius, player_radius,
709 0 : client->m_known_objects, added_objects);
710 :
711 : // Ignore if nothing happened
712 0 : if(removed_objects.empty() && added_objects.empty())
713 : {
714 : //infostream<<"active objects: none changed"<<std::endl;
715 0 : continue;
716 : }
717 :
718 0 : std::string data_buffer;
719 :
720 : char buf[4];
721 :
722 : // Handle removed objects
723 0 : writeU16((u8*)buf, removed_objects.size());
724 0 : data_buffer.append(buf, 2);
725 0 : for(std::set<u16>::iterator
726 0 : i = removed_objects.begin();
727 0 : i != removed_objects.end(); ++i)
728 : {
729 : // Get object
730 0 : u16 id = *i;
731 0 : ServerActiveObject* obj = m_env->getActiveObject(id);
732 :
733 : // Add to data buffer for sending
734 0 : writeU16((u8*)buf, id);
735 0 : data_buffer.append(buf, 2);
736 :
737 : // Remove from known objects
738 0 : client->m_known_objects.erase(id);
739 :
740 0 : if(obj && obj->m_known_by_count > 0)
741 0 : obj->m_known_by_count--;
742 : }
743 :
744 : // Handle added objects
745 0 : writeU16((u8*)buf, added_objects.size());
746 0 : data_buffer.append(buf, 2);
747 0 : for(std::set<u16>::iterator
748 0 : i = added_objects.begin();
749 0 : i != added_objects.end(); ++i)
750 : {
751 : // Get object
752 0 : u16 id = *i;
753 0 : ServerActiveObject* obj = m_env->getActiveObject(id);
754 :
755 : // Get object type
756 0 : u8 type = ACTIVEOBJECT_TYPE_INVALID;
757 0 : if(obj == NULL)
758 0 : infostream<<"WARNING: "<<__FUNCTION_NAME
759 0 : <<": NULL object"<<std::endl;
760 : else
761 0 : type = obj->getSendType();
762 :
763 : // Add to data buffer for sending
764 0 : writeU16((u8*)buf, id);
765 0 : data_buffer.append(buf, 2);
766 0 : writeU8((u8*)buf, type);
767 0 : data_buffer.append(buf, 1);
768 :
769 0 : if(obj)
770 0 : data_buffer.append(serializeLongString(
771 0 : obj->getClientInitializationData(client->net_proto_version)));
772 : else
773 0 : data_buffer.append(serializeLongString(""));
774 :
775 : // Add to known objects
776 0 : client->m_known_objects.insert(id);
777 :
778 0 : if(obj)
779 0 : obj->m_known_by_count++;
780 : }
781 :
782 0 : u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
783 0 : verbosestream << "Server: Sent object remove/add: "
784 0 : << removed_objects.size() << " removed, "
785 0 : << added_objects.size() << " added, "
786 0 : << "packet size is " << pktSize << std::endl;
787 : }
788 0 : m_clients.Unlock();
789 : }
790 :
791 : /*
792 : Send object messages
793 : */
794 : {
795 0 : JMutexAutoLock envlock(m_env_mutex);
796 0 : ScopeProfiler sp(g_profiler, "Server: sending object messages");
797 :
798 : // Key = object id
799 : // Value = data sent by object
800 0 : std::map<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
801 :
802 : // Get active object messages from environment
803 0 : for(;;) {
804 0 : ActiveObjectMessage aom = m_env->getActiveObjectMessage();
805 0 : if (aom.id == 0)
806 0 : break;
807 :
808 0 : std::vector<ActiveObjectMessage>* message_list = NULL;
809 0 : std::map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
810 0 : n = buffered_messages.find(aom.id);
811 0 : if (n == buffered_messages.end()) {
812 0 : message_list = new std::vector<ActiveObjectMessage>;
813 0 : buffered_messages[aom.id] = message_list;
814 : }
815 : else {
816 0 : message_list = n->second;
817 : }
818 0 : message_list->push_back(aom);
819 : }
820 :
821 0 : m_clients.Lock();
822 0 : std::map<u16, RemoteClient*> clients = m_clients.getClientList();
823 : // Route data to every client
824 0 : for (std::map<u16, RemoteClient*>::iterator
825 0 : i = clients.begin();
826 0 : i != clients.end(); ++i) {
827 0 : RemoteClient *client = i->second;
828 0 : std::string reliable_data;
829 0 : std::string unreliable_data;
830 : // Go through all objects in message buffer
831 0 : for (std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
832 0 : j = buffered_messages.begin();
833 0 : j != buffered_messages.end(); ++j) {
834 : // If object is not known by client, skip it
835 0 : u16 id = j->first;
836 0 : if (client->m_known_objects.find(id) == client->m_known_objects.end())
837 0 : continue;
838 :
839 : // Get message list of object
840 0 : std::vector<ActiveObjectMessage>* list = j->second;
841 : // Go through every message
842 0 : for (std::vector<ActiveObjectMessage>::iterator
843 0 : k = list->begin(); k != list->end(); ++k) {
844 : // Compose the full new data with header
845 0 : ActiveObjectMessage aom = *k;
846 0 : std::string new_data;
847 : // Add object id
848 : char buf[2];
849 0 : writeU16((u8*)&buf[0], aom.id);
850 0 : new_data.append(buf, 2);
851 : // Add data
852 0 : new_data += serializeString(aom.datastring);
853 : // Add data to buffer
854 0 : if(aom.reliable)
855 0 : reliable_data += new_data;
856 : else
857 0 : unreliable_data += new_data;
858 : }
859 : }
860 : /*
861 : reliable_data and unreliable_data are now ready.
862 : Send them.
863 : */
864 0 : if(reliable_data.size() > 0) {
865 0 : SendActiveObjectMessages(client->peer_id, reliable_data);
866 : }
867 :
868 0 : if(unreliable_data.size() > 0) {
869 0 : SendActiveObjectMessages(client->peer_id, unreliable_data, false);
870 : }
871 : }
872 0 : m_clients.Unlock();
873 :
874 : // Clear buffered_messages
875 0 : for(std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
876 0 : i = buffered_messages.begin();
877 0 : i != buffered_messages.end(); ++i) {
878 0 : delete i->second;
879 : }
880 : }
881 :
882 : /*
883 : Send queued-for-sending map edit events.
884 : */
885 : {
886 : // We will be accessing the environment
887 0 : JMutexAutoLock lock(m_env_mutex);
888 :
889 : // Don't send too many at a time
890 : //u32 count = 0;
891 :
892 : // Single change sending is disabled if queue size is not small
893 0 : bool disable_single_change_sending = false;
894 0 : if(m_unsent_map_edit_queue.size() >= 4)
895 0 : disable_single_change_sending = true;
896 :
897 0 : int event_count = m_unsent_map_edit_queue.size();
898 :
899 : // We'll log the amount of each
900 0 : Profiler prof;
901 :
902 0 : while(m_unsent_map_edit_queue.size() != 0)
903 : {
904 0 : MapEditEvent* event = m_unsent_map_edit_queue.front();
905 0 : m_unsent_map_edit_queue.pop();
906 :
907 : // Players far away from the change are stored here.
908 : // Instead of sending the changes, MapBlocks are set not sent
909 : // for them.
910 0 : std::vector<u16> far_players;
911 :
912 0 : switch (event->type) {
913 : case MEET_ADDNODE:
914 : case MEET_SWAPNODE:
915 0 : prof.add("MEET_ADDNODE", 1);
916 0 : sendAddNode(event->p, event->n, event->already_known_by_peer,
917 : &far_players, disable_single_change_sending ? 5 : 30,
918 0 : event->type == MEET_ADDNODE);
919 0 : break;
920 : case MEET_REMOVENODE:
921 0 : prof.add("MEET_REMOVENODE", 1);
922 0 : sendRemoveNode(event->p, event->already_known_by_peer,
923 0 : &far_players, disable_single_change_sending ? 5 : 30);
924 0 : break;
925 : case MEET_BLOCK_NODE_METADATA_CHANGED:
926 0 : infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
927 0 : prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
928 0 : setBlockNotSent(event->p);
929 0 : break;
930 : case MEET_OTHER:
931 0 : infostream << "Server: MEET_OTHER" << std::endl;
932 0 : prof.add("MEET_OTHER", 1);
933 0 : for(std::set<v3s16>::iterator
934 0 : i = event->modified_blocks.begin();
935 0 : i != event->modified_blocks.end(); ++i) {
936 0 : setBlockNotSent(*i);
937 : }
938 0 : break;
939 : default:
940 0 : prof.add("unknown", 1);
941 0 : infostream << "WARNING: Server: Unknown MapEditEvent "
942 0 : << ((u32)event->type) << std::endl;
943 0 : break;
944 : }
945 :
946 : /*
947 : Set blocks not sent to far players
948 : */
949 0 : if(!far_players.empty()) {
950 : // Convert list format to that wanted by SetBlocksNotSent
951 0 : std::map<v3s16, MapBlock*> modified_blocks2;
952 0 : for(std::set<v3s16>::iterator
953 0 : i = event->modified_blocks.begin();
954 0 : i != event->modified_blocks.end(); ++i) {
955 0 : modified_blocks2[*i] =
956 0 : m_env->getMap().getBlockNoCreateNoEx(*i);
957 : }
958 :
959 : // Set blocks not sent
960 0 : for(std::vector<u16>::iterator
961 0 : i = far_players.begin();
962 0 : i != far_players.end(); ++i) {
963 0 : if(RemoteClient *client = getClient(*i))
964 0 : client->SetBlocksNotSent(modified_blocks2);
965 : }
966 : }
967 :
968 0 : delete event;
969 :
970 : /*// Don't send too many at a time
971 : count++;
972 : if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
973 : break;*/
974 : }
975 :
976 0 : if(event_count >= 5){
977 0 : infostream<<"Server: MapEditEvents:"<<std::endl;
978 0 : prof.print(infostream);
979 0 : } else if(event_count != 0){
980 0 : verbosestream<<"Server: MapEditEvents:"<<std::endl;
981 0 : prof.print(verbosestream);
982 : }
983 :
984 : }
985 :
986 : /*
987 : Trigger emergethread (it somehow gets to a non-triggered but
988 : bysy state sometimes)
989 : */
990 : {
991 0 : float &counter = m_emergethread_trigger_timer;
992 0 : counter += dtime;
993 0 : if(counter >= 2.0)
994 : {
995 0 : counter = 0.0;
996 :
997 0 : m_emerge->startThreads();
998 : }
999 : }
1000 :
1001 : // Save map, players and auth stuff
1002 : {
1003 0 : float &counter = m_savemap_timer;
1004 0 : counter += dtime;
1005 0 : if(counter >= g_settings->getFloat("server_map_save_interval"))
1006 : {
1007 0 : counter = 0.0;
1008 0 : JMutexAutoLock lock(m_env_mutex);
1009 :
1010 0 : ScopeProfiler sp(g_profiler, "Server: saving stuff");
1011 :
1012 : // Save ban file
1013 0 : if (m_banmanager->isModified()) {
1014 0 : m_banmanager->save();
1015 : }
1016 :
1017 : // Save changed parts of map
1018 0 : m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1019 :
1020 : // Save players
1021 0 : m_env->saveLoadedPlayers();
1022 :
1023 : // Save environment metadata
1024 0 : m_env->saveMeta();
1025 : }
1026 : }
1027 : }
1028 :
1029 0 : void Server::Receive()
1030 : {
1031 0 : DSTACK(__FUNCTION_NAME);
1032 0 : SharedBuffer<u8> data;
1033 : u16 peer_id;
1034 : try {
1035 0 : NetworkPacket pkt;
1036 0 : m_con.Receive(&pkt);
1037 0 : peer_id = pkt.getPeerId();
1038 0 : ProcessData(&pkt);
1039 : }
1040 0 : catch(con::InvalidIncomingDataException &e) {
1041 : infostream<<"Server::Receive(): "
1042 0 : "InvalidIncomingDataException: what()="
1043 0 : <<e.what()<<std::endl;
1044 : }
1045 0 : catch(SerializationError &e) {
1046 : infostream<<"Server::Receive(): "
1047 0 : "SerializationError: what()="
1048 0 : <<e.what()<<std::endl;
1049 : }
1050 0 : catch(ClientStateError &e) {
1051 0 : errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1052 0 : DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1053 0 : L"Try reconnecting or updating your client");
1054 : }
1055 0 : catch(con::PeerNotFoundException &e) {
1056 : // Do nothing
1057 : }
1058 0 : }
1059 :
1060 0 : PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1061 : {
1062 0 : std::string playername = "";
1063 0 : PlayerSAO *playersao = NULL;
1064 0 : m_clients.Lock();
1065 : try {
1066 0 : RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1067 0 : if (client != NULL) {
1068 0 : playername = client->getName();
1069 0 : playersao = emergePlayer(playername.c_str(), peer_id);
1070 : }
1071 0 : } catch (std::exception &e) {
1072 0 : m_clients.Unlock();
1073 0 : throw;
1074 : }
1075 0 : m_clients.Unlock();
1076 :
1077 : RemotePlayer *player =
1078 0 : static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1079 :
1080 : // If failed, cancel
1081 0 : if ((playersao == NULL) || (player == NULL)) {
1082 0 : if (player && player->peer_id != 0) {
1083 0 : actionstream << "Server: Failed to emerge player \"" << playername
1084 0 : << "\" (player allocated to an another client)" << std::endl;
1085 0 : DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1086 : L"name. If your client closed unexpectedly, try again in "
1087 0 : L"a minute.");
1088 : } else {
1089 0 : errorstream << "Server: " << playername << ": Failed to emerge player"
1090 0 : << std::endl;
1091 0 : DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1092 : }
1093 0 : return NULL;
1094 : }
1095 :
1096 : /*
1097 : Send complete position information
1098 : */
1099 0 : SendMovePlayer(peer_id);
1100 :
1101 : // Send privileges
1102 0 : SendPlayerPrivileges(peer_id);
1103 :
1104 : // Send inventory formspec
1105 0 : SendPlayerInventoryFormspec(peer_id);
1106 :
1107 : // Send inventory
1108 0 : SendInventory(playersao);
1109 :
1110 : // Send HP
1111 0 : SendPlayerHPOrDie(peer_id, playersao->getHP() == 0);
1112 :
1113 : // Send Breath
1114 0 : SendPlayerBreath(peer_id);
1115 :
1116 : // Show death screen if necessary
1117 0 : if(player->isDead())
1118 0 : SendDeathscreen(peer_id, false, v3f(0,0,0));
1119 :
1120 : // Note things in chat if not in simple singleplayer mode
1121 0 : if(!m_simple_singleplayer_mode) {
1122 : // Send information about server to player in chat
1123 0 : SendChatMessage(peer_id, getStatusString());
1124 :
1125 : // Send information about joining in chat
1126 : {
1127 0 : std::wstring name = L"unknown";
1128 0 : Player *player = m_env->getPlayer(peer_id);
1129 0 : if(player != NULL)
1130 0 : name = narrow_to_wide(player->getName());
1131 :
1132 0 : std::wstring message;
1133 0 : message += L"*** ";
1134 0 : message += name;
1135 0 : message += L" joined the game.";
1136 0 : SendChatMessage(PEER_ID_INEXISTENT,message);
1137 : }
1138 : }
1139 0 : Address addr = getPeerAddress(player->peer_id);
1140 0 : std::string ip_str = addr.serializeString();
1141 0 : actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1142 : /*
1143 : Print out action
1144 : */
1145 : {
1146 0 : std::vector<std::string> names = m_clients.getPlayerNames();
1147 :
1148 0 : actionstream<<player->getName() <<" joins game. List of players: ";
1149 :
1150 0 : for (std::vector<std::string>::iterator i = names.begin();
1151 0 : i != names.end(); i++) {
1152 0 : actionstream << *i << " ";
1153 : }
1154 :
1155 0 : actionstream << player->getName() <<std::endl;
1156 : }
1157 0 : return playersao;
1158 : }
1159 :
1160 0 : inline void Server::handleCommand(NetworkPacket* pkt)
1161 : {
1162 0 : const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1163 0 : (this->*opHandle.handler)(pkt);
1164 0 : }
1165 :
1166 0 : void Server::ProcessData(NetworkPacket *pkt)
1167 : {
1168 0 : DSTACK(__FUNCTION_NAME);
1169 : // Environment is locked first.
1170 0 : JMutexAutoLock envlock(m_env_mutex);
1171 :
1172 0 : ScopeProfiler sp(g_profiler, "Server::ProcessData");
1173 0 : u32 peer_id = pkt->getPeerId();
1174 :
1175 : try {
1176 0 : Address address = getPeerAddress(peer_id);
1177 0 : std::string addr_s = address.serializeString();
1178 :
1179 0 : if(m_banmanager->isIpBanned(addr_s)) {
1180 0 : std::string ban_name = m_banmanager->getBanName(addr_s);
1181 0 : infostream << "Server: A banned client tried to connect from "
1182 0 : << addr_s << "; banned name was "
1183 0 : << ban_name << std::endl;
1184 : // This actually doesn't seem to transfer to the client
1185 0 : DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1186 0 : + narrow_to_wide(ban_name));
1187 0 : return;
1188 : }
1189 : }
1190 0 : catch(con::PeerNotFoundException &e) {
1191 : /*
1192 : * no peer for this packet found
1193 : * most common reason is peer timeout, e.g. peer didn't
1194 : * respond for some time, your server was overloaded or
1195 : * things like that.
1196 : */
1197 0 : infostream << "Server::ProcessData(): Canceling: peer "
1198 0 : << peer_id << " not found" << std::endl;
1199 0 : return;
1200 : }
1201 :
1202 : try {
1203 0 : ToServerCommand command = (ToServerCommand) pkt->getCommand();
1204 :
1205 : // Command must be handled into ToServerCommandHandler
1206 0 : if (command >= TOSERVER_NUM_MSG_TYPES) {
1207 0 : infostream << "Server: Ignoring unknown command "
1208 0 : << command << std::endl;
1209 0 : return;
1210 : }
1211 :
1212 0 : if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1213 0 : handleCommand(pkt);
1214 0 : return;
1215 : }
1216 :
1217 0 : u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1218 :
1219 0 : if(peer_ser_ver == SER_FMT_VER_INVALID) {
1220 : errorstream << "Server::ProcessData(): Cancelling: Peer"
1221 : " serialization format invalid or not initialized."
1222 0 : " Skipping incoming command=" << command << std::endl;
1223 0 : return;
1224 : }
1225 :
1226 : /* Handle commands related to client startup */
1227 0 : if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1228 0 : handleCommand(pkt);
1229 0 : return;
1230 : }
1231 :
1232 0 : if (m_clients.getClientState(peer_id) < CS_Active) {
1233 0 : if (command == TOSERVER_PLAYERPOS) return;
1234 :
1235 0 : errorstream << "Got packet command: " << command << " for peer id "
1236 0 : << peer_id << " but client isn't active yet. Dropping packet "
1237 0 : << std::endl;
1238 0 : return;
1239 : }
1240 :
1241 0 : handleCommand(pkt);
1242 0 : } catch (SendFailedException &e) {
1243 0 : errorstream << "Server::ProcessData(): SendFailedException: "
1244 0 : << "what=" << e.what()
1245 0 : << std::endl;
1246 0 : } catch (PacketError &e) {
1247 0 : actionstream << "Server::ProcessData(): PacketError: "
1248 0 : << "what=" << e.what()
1249 0 : << std::endl;
1250 : }
1251 : }
1252 :
1253 0 : void Server::setTimeOfDay(u32 time)
1254 : {
1255 0 : m_env->setTimeOfDay(time);
1256 0 : m_time_of_day_send_timer = 0;
1257 0 : }
1258 :
1259 0 : void Server::onMapEditEvent(MapEditEvent *event)
1260 : {
1261 0 : if(m_ignore_map_edit_events)
1262 0 : return;
1263 0 : if(m_ignore_map_edit_events_area.contains(event->getArea()))
1264 0 : return;
1265 0 : MapEditEvent *e = event->clone();
1266 0 : m_unsent_map_edit_queue.push(e);
1267 : }
1268 :
1269 0 : Inventory* Server::getInventory(const InventoryLocation &loc)
1270 : {
1271 0 : switch (loc.type) {
1272 : case InventoryLocation::UNDEFINED:
1273 : case InventoryLocation::CURRENT_PLAYER:
1274 0 : break;
1275 : case InventoryLocation::PLAYER:
1276 : {
1277 0 : Player *player = m_env->getPlayer(loc.name.c_str());
1278 0 : if(!player)
1279 0 : return NULL;
1280 0 : PlayerSAO *playersao = player->getPlayerSAO();
1281 0 : if(!playersao)
1282 0 : return NULL;
1283 0 : return playersao->getInventory();
1284 : }
1285 : break;
1286 : case InventoryLocation::NODEMETA:
1287 : {
1288 0 : NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1289 0 : if(!meta)
1290 0 : return NULL;
1291 0 : return meta->getInventory();
1292 : }
1293 : break;
1294 : case InventoryLocation::DETACHED:
1295 : {
1296 0 : if(m_detached_inventories.count(loc.name) == 0)
1297 0 : return NULL;
1298 0 : return m_detached_inventories[loc.name];
1299 : }
1300 : break;
1301 : default:
1302 0 : sanity_check(false); // abort
1303 : break;
1304 : }
1305 0 : return NULL;
1306 : }
1307 0 : void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1308 : {
1309 0 : switch(loc.type){
1310 : case InventoryLocation::UNDEFINED:
1311 0 : break;
1312 : case InventoryLocation::PLAYER:
1313 : {
1314 0 : if (!playerSend)
1315 0 : return;
1316 :
1317 0 : Player *player = m_env->getPlayer(loc.name.c_str());
1318 0 : if(!player)
1319 0 : return;
1320 0 : PlayerSAO *playersao = player->getPlayerSAO();
1321 0 : if(!playersao)
1322 0 : return;
1323 :
1324 0 : SendInventory(playersao);
1325 : }
1326 0 : break;
1327 : case InventoryLocation::NODEMETA:
1328 : {
1329 0 : v3s16 blockpos = getNodeBlockPos(loc.p);
1330 :
1331 0 : MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1332 0 : if(block)
1333 0 : block->raiseModified(MOD_STATE_WRITE_NEEDED);
1334 :
1335 0 : setBlockNotSent(blockpos);
1336 : }
1337 0 : break;
1338 : case InventoryLocation::DETACHED:
1339 : {
1340 0 : sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1341 : }
1342 0 : break;
1343 : default:
1344 0 : sanity_check(false); // abort
1345 : break;
1346 : }
1347 : }
1348 :
1349 0 : void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1350 : {
1351 0 : std::vector<u16> clients = m_clients.getClientIDs();
1352 0 : m_clients.Lock();
1353 : // Set the modified blocks unsent for all the clients
1354 0 : for (std::vector<u16>::iterator i = clients.begin();
1355 0 : i != clients.end(); ++i) {
1356 0 : if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1357 0 : client->SetBlocksNotSent(block);
1358 : }
1359 0 : m_clients.Unlock();
1360 0 : }
1361 :
1362 0 : void Server::peerAdded(con::Peer *peer)
1363 : {
1364 0 : DSTACK(__FUNCTION_NAME);
1365 0 : verbosestream<<"Server::peerAdded(): peer->id="
1366 0 : <<peer->id<<std::endl;
1367 :
1368 : con::PeerChange c;
1369 0 : c.type = con::PEER_ADDED;
1370 0 : c.peer_id = peer->id;
1371 0 : c.timeout = false;
1372 0 : m_peer_change_queue.push(c);
1373 0 : }
1374 :
1375 0 : void Server::deletingPeer(con::Peer *peer, bool timeout)
1376 : {
1377 0 : DSTACK(__FUNCTION_NAME);
1378 0 : verbosestream<<"Server::deletingPeer(): peer->id="
1379 0 : <<peer->id<<", timeout="<<timeout<<std::endl;
1380 :
1381 0 : m_clients.event(peer->id, CSE_Disconnect);
1382 : con::PeerChange c;
1383 0 : c.type = con::PEER_REMOVED;
1384 0 : c.peer_id = peer->id;
1385 0 : c.timeout = timeout;
1386 0 : m_peer_change_queue.push(c);
1387 0 : }
1388 :
1389 0 : bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1390 : {
1391 0 : *retval = m_con.getPeerStat(peer_id,type);
1392 0 : if (*retval == -1) return false;
1393 0 : return true;
1394 : }
1395 :
1396 0 : bool Server::getClientInfo(
1397 : u16 peer_id,
1398 : ClientState* state,
1399 : u32* uptime,
1400 : u8* ser_vers,
1401 : u16* prot_vers,
1402 : u8* major,
1403 : u8* minor,
1404 : u8* patch,
1405 : std::string* vers_string
1406 : )
1407 : {
1408 0 : *state = m_clients.getClientState(peer_id);
1409 0 : m_clients.Lock();
1410 0 : RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1411 :
1412 0 : if (client == NULL) {
1413 0 : m_clients.Unlock();
1414 0 : return false;
1415 : }
1416 :
1417 0 : *uptime = client->uptime();
1418 0 : *ser_vers = client->serialization_version;
1419 0 : *prot_vers = client->net_proto_version;
1420 :
1421 0 : *major = client->getMajor();
1422 0 : *minor = client->getMinor();
1423 0 : *patch = client->getPatch();
1424 0 : *vers_string = client->getPatch();
1425 :
1426 0 : m_clients.Unlock();
1427 :
1428 0 : return true;
1429 : }
1430 :
1431 0 : void Server::handlePeerChanges()
1432 : {
1433 0 : while(m_peer_change_queue.size() > 0)
1434 : {
1435 0 : con::PeerChange c = m_peer_change_queue.front();
1436 0 : m_peer_change_queue.pop();
1437 :
1438 0 : verbosestream<<"Server: Handling peer change: "
1439 0 : <<"id="<<c.peer_id<<", timeout="<<c.timeout
1440 0 : <<std::endl;
1441 :
1442 0 : switch(c.type)
1443 : {
1444 : case con::PEER_ADDED:
1445 0 : m_clients.CreateClient(c.peer_id);
1446 0 : break;
1447 :
1448 : case con::PEER_REMOVED:
1449 0 : DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1450 0 : break;
1451 :
1452 : default:
1453 0 : FATAL_ERROR("Invalid peer change event received!");
1454 : break;
1455 : }
1456 : }
1457 0 : }
1458 :
1459 0 : void Server::Send(NetworkPacket* pkt)
1460 : {
1461 0 : m_clients.send(pkt->getPeerId(),
1462 0 : clientCommandFactoryTable[pkt->getCommand()].channel,
1463 : pkt,
1464 0 : clientCommandFactoryTable[pkt->getCommand()].reliable);
1465 0 : }
1466 :
1467 0 : void Server::SendMovement(u16 peer_id)
1468 : {
1469 0 : DSTACK(__FUNCTION_NAME);
1470 0 : std::ostringstream os(std::ios_base::binary);
1471 :
1472 0 : NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1473 :
1474 0 : pkt << g_settings->getFloat("movement_acceleration_default");
1475 0 : pkt << g_settings->getFloat("movement_acceleration_air");
1476 0 : pkt << g_settings->getFloat("movement_acceleration_fast");
1477 0 : pkt << g_settings->getFloat("movement_speed_walk");
1478 0 : pkt << g_settings->getFloat("movement_speed_crouch");
1479 0 : pkt << g_settings->getFloat("movement_speed_fast");
1480 0 : pkt << g_settings->getFloat("movement_speed_climb");
1481 0 : pkt << g_settings->getFloat("movement_speed_jump");
1482 0 : pkt << g_settings->getFloat("movement_liquid_fluidity");
1483 0 : pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1484 0 : pkt << g_settings->getFloat("movement_liquid_sink");
1485 0 : pkt << g_settings->getFloat("movement_gravity");
1486 :
1487 0 : Send(&pkt);
1488 0 : }
1489 :
1490 0 : void Server::SendHP(u16 peer_id, u8 hp)
1491 : {
1492 0 : DSTACK(__FUNCTION_NAME);
1493 :
1494 0 : NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1495 0 : pkt << hp;
1496 0 : Send(&pkt);
1497 0 : }
1498 :
1499 0 : void Server::SendBreath(u16 peer_id, u16 breath)
1500 : {
1501 0 : DSTACK(__FUNCTION_NAME);
1502 :
1503 0 : NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1504 0 : pkt << (u16) breath;
1505 0 : Send(&pkt);
1506 0 : }
1507 :
1508 0 : void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
1509 : {
1510 0 : DSTACK(__FUNCTION_NAME);
1511 :
1512 0 : NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1513 0 : pkt << (u8) reason;
1514 :
1515 0 : if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING) {
1516 0 : pkt << custom_reason;
1517 : }
1518 0 : Send(&pkt);
1519 0 : }
1520 :
1521 0 : void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
1522 : {
1523 0 : DSTACK(__FUNCTION_NAME);
1524 :
1525 0 : NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1526 0 : pkt << reason;
1527 0 : Send(&pkt);
1528 0 : }
1529 :
1530 0 : void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1531 : v3f camera_point_target)
1532 : {
1533 0 : DSTACK(__FUNCTION_NAME);
1534 :
1535 0 : NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1536 0 : pkt << set_camera_point_target << camera_point_target;
1537 0 : Send(&pkt);
1538 0 : }
1539 :
1540 0 : void Server::SendItemDef(u16 peer_id,
1541 : IItemDefManager *itemdef, u16 protocol_version)
1542 : {
1543 0 : DSTACK(__FUNCTION_NAME);
1544 :
1545 0 : NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1546 :
1547 : /*
1548 : u16 command
1549 : u32 length of the next item
1550 : zlib-compressed serialized ItemDefManager
1551 : */
1552 0 : std::ostringstream tmp_os(std::ios::binary);
1553 0 : itemdef->serialize(tmp_os, protocol_version);
1554 0 : std::ostringstream tmp_os2(std::ios::binary);
1555 0 : compressZlib(tmp_os.str(), tmp_os2);
1556 0 : pkt.putLongString(tmp_os2.str());
1557 :
1558 : // Make data buffer
1559 0 : verbosestream << "Server: Sending item definitions to id(" << peer_id
1560 0 : << "): size=" << pkt.getSize() << std::endl;
1561 :
1562 0 : Send(&pkt);
1563 0 : }
1564 :
1565 0 : void Server::SendNodeDef(u16 peer_id,
1566 : INodeDefManager *nodedef, u16 protocol_version)
1567 : {
1568 0 : DSTACK(__FUNCTION_NAME);
1569 :
1570 0 : NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1571 :
1572 : /*
1573 : u16 command
1574 : u32 length of the next item
1575 : zlib-compressed serialized NodeDefManager
1576 : */
1577 0 : std::ostringstream tmp_os(std::ios::binary);
1578 0 : nodedef->serialize(tmp_os, protocol_version);
1579 0 : std::ostringstream tmp_os2(std::ios::binary);
1580 0 : compressZlib(tmp_os.str(), tmp_os2);
1581 :
1582 0 : pkt.putLongString(tmp_os2.str());
1583 :
1584 : // Make data buffer
1585 0 : verbosestream << "Server: Sending node definitions to id(" << peer_id
1586 0 : << "): size=" << pkt.getSize() << std::endl;
1587 :
1588 0 : Send(&pkt);
1589 0 : }
1590 :
1591 : /*
1592 : Non-static send methods
1593 : */
1594 :
1595 0 : void Server::SendInventory(PlayerSAO* playerSAO)
1596 : {
1597 0 : DSTACK(__FUNCTION_NAME);
1598 :
1599 0 : UpdateCrafting(playerSAO->getPlayer());
1600 :
1601 : /*
1602 : Serialize it
1603 : */
1604 :
1605 0 : NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1606 :
1607 0 : std::ostringstream os;
1608 0 : playerSAO->getInventory()->serialize(os);
1609 :
1610 0 : std::string s = os.str();
1611 :
1612 0 : pkt.putRawString(s.c_str(), s.size());
1613 0 : Send(&pkt);
1614 0 : }
1615 :
1616 0 : void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1617 : {
1618 0 : DSTACK(__FUNCTION_NAME);
1619 :
1620 0 : NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1621 0 : pkt << message;
1622 :
1623 0 : if (peer_id != PEER_ID_INEXISTENT) {
1624 0 : Send(&pkt);
1625 : }
1626 : else {
1627 0 : m_clients.sendToAll(0, &pkt, true);
1628 : }
1629 0 : }
1630 :
1631 0 : void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1632 : const std::string &formname)
1633 : {
1634 0 : DSTACK(__FUNCTION_NAME);
1635 :
1636 0 : NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1637 :
1638 0 : pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1639 0 : pkt << formname;
1640 :
1641 0 : Send(&pkt);
1642 0 : }
1643 :
1644 : // Spawns a particle on peer with peer_id
1645 0 : void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1646 : float expirationtime, float size, bool collisiondetection,
1647 : bool vertical, std::string texture)
1648 : {
1649 0 : DSTACK(__FUNCTION_NAME);
1650 :
1651 0 : NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1652 :
1653 0 : pkt << pos << velocity << acceleration << expirationtime
1654 0 : << size << collisiondetection;
1655 0 : pkt.putLongString(texture);
1656 0 : pkt << vertical;
1657 :
1658 0 : if (peer_id != PEER_ID_INEXISTENT) {
1659 0 : Send(&pkt);
1660 : }
1661 : else {
1662 0 : m_clients.sendToAll(0, &pkt, true);
1663 : }
1664 0 : }
1665 :
1666 : // Adds a ParticleSpawner on peer with peer_id
1667 0 : void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1668 : v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1669 : float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
1670 : {
1671 0 : DSTACK(__FUNCTION_NAME);
1672 :
1673 0 : NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1674 :
1675 0 : pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1676 0 : << minacc << maxacc << minexptime << maxexptime << minsize
1677 0 : << maxsize << collisiondetection;
1678 :
1679 0 : pkt.putLongString(texture);
1680 :
1681 0 : pkt << id << vertical;
1682 :
1683 0 : if (peer_id != PEER_ID_INEXISTENT) {
1684 0 : Send(&pkt);
1685 : }
1686 : else {
1687 0 : m_clients.sendToAll(0, &pkt, true);
1688 : }
1689 0 : }
1690 :
1691 0 : void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1692 : {
1693 0 : DSTACK(__FUNCTION_NAME);
1694 :
1695 0 : NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
1696 :
1697 : // Ugly error in this packet
1698 0 : pkt << (u16) id;
1699 :
1700 0 : if (peer_id != PEER_ID_INEXISTENT) {
1701 0 : Send(&pkt);
1702 : }
1703 : else {
1704 0 : m_clients.sendToAll(0, &pkt, true);
1705 : }
1706 :
1707 0 : }
1708 :
1709 0 : void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1710 : {
1711 0 : NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1712 :
1713 0 : pkt << id << (u8) form->type << form->pos << form->name << form->scale
1714 0 : << form->text << form->number << form->item << form->dir
1715 0 : << form->align << form->offset << form->world_pos << form->size;
1716 :
1717 0 : Send(&pkt);
1718 0 : }
1719 :
1720 0 : void Server::SendHUDRemove(u16 peer_id, u32 id)
1721 : {
1722 0 : NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1723 0 : pkt << id;
1724 0 : Send(&pkt);
1725 0 : }
1726 :
1727 0 : void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1728 : {
1729 0 : NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1730 0 : pkt << id << (u8) stat;
1731 :
1732 0 : switch (stat) {
1733 : case HUD_STAT_POS:
1734 : case HUD_STAT_SCALE:
1735 : case HUD_STAT_ALIGN:
1736 : case HUD_STAT_OFFSET:
1737 0 : pkt << *(v2f *) value;
1738 0 : break;
1739 : case HUD_STAT_NAME:
1740 : case HUD_STAT_TEXT:
1741 0 : pkt << *(std::string *) value;
1742 0 : break;
1743 : case HUD_STAT_WORLD_POS:
1744 0 : pkt << *(v3f *) value;
1745 0 : break;
1746 : case HUD_STAT_SIZE:
1747 0 : pkt << *(v2s32 *) value;
1748 0 : break;
1749 : case HUD_STAT_NUMBER:
1750 : case HUD_STAT_ITEM:
1751 : case HUD_STAT_DIR:
1752 : default:
1753 0 : pkt << *(u32 *) value;
1754 0 : break;
1755 : }
1756 :
1757 0 : Send(&pkt);
1758 0 : }
1759 :
1760 0 : void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1761 : {
1762 0 : NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1763 :
1764 0 : flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1765 :
1766 0 : pkt << flags << mask;
1767 :
1768 0 : Send(&pkt);
1769 0 : }
1770 :
1771 0 : void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1772 : {
1773 0 : NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1774 0 : pkt << param << value;
1775 0 : Send(&pkt);
1776 0 : }
1777 :
1778 0 : void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1779 : const std::string &type, const std::vector<std::string> ¶ms)
1780 : {
1781 0 : NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1782 0 : pkt << bgcolor << type << (u16) params.size();
1783 :
1784 0 : for(size_t i=0; i<params.size(); i++)
1785 0 : pkt << params[i];
1786 :
1787 0 : Send(&pkt);
1788 0 : }
1789 :
1790 0 : void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1791 : float ratio)
1792 : {
1793 : NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1794 0 : 1 + 2, peer_id);
1795 :
1796 0 : pkt << do_override << (u16) (ratio * 65535);
1797 :
1798 0 : Send(&pkt);
1799 0 : }
1800 :
1801 0 : void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1802 : {
1803 0 : DSTACK(__FUNCTION_NAME);
1804 :
1805 0 : NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1806 0 : pkt << time << time_speed;
1807 :
1808 0 : if (peer_id == PEER_ID_INEXISTENT) {
1809 0 : m_clients.sendToAll(0, &pkt, true);
1810 : }
1811 : else {
1812 0 : Send(&pkt);
1813 : }
1814 0 : }
1815 :
1816 0 : void Server::SendPlayerHP(u16 peer_id)
1817 : {
1818 0 : DSTACK(__FUNCTION_NAME);
1819 0 : PlayerSAO *playersao = getPlayerSAO(peer_id);
1820 : // In some rare case, if the player is disconnected
1821 : // while Lua call l_punch, for example, this can be NULL
1822 0 : if (!playersao)
1823 0 : return;
1824 :
1825 0 : SendHP(peer_id, playersao->getHP());
1826 0 : m_script->player_event(playersao,"health_changed");
1827 :
1828 : // Send to other clients
1829 0 : std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1830 0 : ActiveObjectMessage aom(playersao->getId(), true, str);
1831 0 : playersao->m_messages_out.push(aom);
1832 : }
1833 :
1834 0 : void Server::SendPlayerBreath(u16 peer_id)
1835 : {
1836 0 : DSTACK(__FUNCTION_NAME);
1837 0 : PlayerSAO *playersao = getPlayerSAO(peer_id);
1838 : assert(playersao);
1839 :
1840 0 : m_script->player_event(playersao, "breath_changed");
1841 0 : SendBreath(peer_id, playersao->getBreath());
1842 0 : }
1843 :
1844 0 : void Server::SendMovePlayer(u16 peer_id)
1845 : {
1846 0 : DSTACK(__FUNCTION_NAME);
1847 0 : Player *player = m_env->getPlayer(peer_id);
1848 : assert(player);
1849 :
1850 0 : NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1851 0 : pkt << player->getPosition() << player->getPitch() << player->getYaw();
1852 :
1853 : {
1854 0 : v3f pos = player->getPosition();
1855 0 : f32 pitch = player->getPitch();
1856 0 : f32 yaw = player->getYaw();
1857 0 : verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1858 0 : << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1859 0 : << " pitch=" << pitch
1860 0 : << " yaw=" << yaw
1861 0 : << std::endl;
1862 : }
1863 :
1864 0 : Send(&pkt);
1865 0 : }
1866 :
1867 0 : void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1868 : {
1869 : NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1870 0 : peer_id);
1871 :
1872 0 : pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1873 0 : << animation_frames[3] << animation_speed;
1874 :
1875 0 : Send(&pkt);
1876 0 : }
1877 :
1878 0 : void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1879 : {
1880 0 : NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1881 0 : pkt << first << third;
1882 0 : Send(&pkt);
1883 0 : }
1884 0 : void Server::SendPlayerPrivileges(u16 peer_id)
1885 : {
1886 0 : Player *player = m_env->getPlayer(peer_id);
1887 : assert(player);
1888 0 : if(player->peer_id == PEER_ID_INEXISTENT)
1889 0 : return;
1890 :
1891 0 : std::set<std::string> privs;
1892 0 : m_script->getAuth(player->getName(), NULL, &privs);
1893 :
1894 0 : NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1895 0 : pkt << (u16) privs.size();
1896 :
1897 0 : for(std::set<std::string>::const_iterator i = privs.begin();
1898 0 : i != privs.end(); i++) {
1899 0 : pkt << (*i);
1900 : }
1901 :
1902 0 : Send(&pkt);
1903 : }
1904 :
1905 0 : void Server::SendPlayerInventoryFormspec(u16 peer_id)
1906 : {
1907 0 : Player *player = m_env->getPlayer(peer_id);
1908 : assert(player);
1909 0 : if(player->peer_id == PEER_ID_INEXISTENT)
1910 0 : return;
1911 :
1912 0 : NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1913 0 : pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1914 0 : Send(&pkt);
1915 : }
1916 :
1917 0 : u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
1918 : {
1919 0 : NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1920 0 : pkt.putRawString(datas.c_str(), datas.size());
1921 0 : Send(&pkt);
1922 0 : return pkt.getSize();
1923 : }
1924 :
1925 0 : void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
1926 : {
1927 : NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1928 0 : datas.size(), peer_id);
1929 :
1930 0 : pkt.putRawString(datas.c_str(), datas.size());
1931 :
1932 0 : m_clients.send(pkt.getPeerId(),
1933 0 : reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1934 0 : &pkt, reliable);
1935 :
1936 0 : }
1937 :
1938 0 : s32 Server::playSound(const SimpleSoundSpec &spec,
1939 : const ServerSoundParams ¶ms)
1940 : {
1941 : // Find out initial position of sound
1942 0 : bool pos_exists = false;
1943 0 : v3f pos = params.getPos(m_env, &pos_exists);
1944 : // If position is not found while it should be, cancel sound
1945 0 : if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1946 0 : return -1;
1947 :
1948 : // Filter destination clients
1949 0 : std::vector<u16> dst_clients;
1950 0 : if(params.to_player != "")
1951 : {
1952 0 : Player *player = m_env->getPlayer(params.to_player.c_str());
1953 0 : if(!player){
1954 0 : infostream<<"Server::playSound: Player \""<<params.to_player
1955 0 : <<"\" not found"<<std::endl;
1956 0 : return -1;
1957 : }
1958 0 : if(player->peer_id == PEER_ID_INEXISTENT){
1959 0 : infostream<<"Server::playSound: Player \""<<params.to_player
1960 0 : <<"\" not connected"<<std::endl;
1961 0 : return -1;
1962 : }
1963 0 : dst_clients.push_back(player->peer_id);
1964 : }
1965 : else {
1966 0 : std::vector<u16> clients = m_clients.getClientIDs();
1967 :
1968 0 : for(std::vector<u16>::iterator
1969 0 : i = clients.begin(); i != clients.end(); ++i) {
1970 0 : Player *player = m_env->getPlayer(*i);
1971 0 : if(!player)
1972 0 : continue;
1973 :
1974 0 : if(pos_exists) {
1975 0 : if(player->getPosition().getDistanceFrom(pos) >
1976 0 : params.max_hear_distance)
1977 0 : continue;
1978 : }
1979 0 : dst_clients.push_back(*i);
1980 : }
1981 : }
1982 :
1983 0 : if(dst_clients.empty())
1984 0 : return -1;
1985 :
1986 : // Create the sound
1987 0 : s32 id = m_next_sound_id++;
1988 : // The sound will exist as a reference in m_playing_sounds
1989 0 : m_playing_sounds[id] = ServerPlayingSound();
1990 0 : ServerPlayingSound &psound = m_playing_sounds[id];
1991 0 : psound.params = params;
1992 :
1993 0 : NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
1994 0 : pkt << id << spec.name << (float) (spec.gain * params.gain)
1995 0 : << (u8) params.type << pos << params.object << params.loop;
1996 :
1997 0 : for(std::vector<u16>::iterator i = dst_clients.begin();
1998 0 : i != dst_clients.end(); i++) {
1999 0 : psound.clients.insert(*i);
2000 0 : m_clients.send(*i, 0, &pkt, true);
2001 : }
2002 0 : return id;
2003 : }
2004 0 : void Server::stopSound(s32 handle)
2005 : {
2006 : // Get sound reference
2007 : std::map<s32, ServerPlayingSound>::iterator i =
2008 0 : m_playing_sounds.find(handle);
2009 0 : if(i == m_playing_sounds.end())
2010 0 : return;
2011 0 : ServerPlayingSound &psound = i->second;
2012 :
2013 0 : NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2014 0 : pkt << handle;
2015 :
2016 0 : for(std::set<u16>::iterator i = psound.clients.begin();
2017 0 : i != psound.clients.end(); i++) {
2018 : // Send as reliable
2019 0 : m_clients.send(*i, 0, &pkt, true);
2020 : }
2021 : // Remove sound reference
2022 0 : m_playing_sounds.erase(i);
2023 : }
2024 :
2025 0 : void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2026 : std::vector<u16> *far_players, float far_d_nodes)
2027 : {
2028 0 : float maxd = far_d_nodes*BS;
2029 0 : v3f p_f = intToFloat(p, BS);
2030 :
2031 0 : NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2032 0 : pkt << p;
2033 :
2034 0 : std::vector<u16> clients = m_clients.getClientIDs();
2035 0 : for(std::vector<u16>::iterator i = clients.begin();
2036 0 : i != clients.end(); ++i) {
2037 0 : if (far_players) {
2038 : // Get player
2039 0 : if(Player *player = m_env->getPlayer(*i)) {
2040 : // If player is far away, only set modified blocks not sent
2041 0 : v3f player_pos = player->getPosition();
2042 0 : if(player_pos.getDistanceFrom(p_f) > maxd) {
2043 0 : far_players->push_back(*i);
2044 0 : continue;
2045 : }
2046 : }
2047 : }
2048 :
2049 : // Send as reliable
2050 0 : m_clients.send(*i, 0, &pkt, true);
2051 : }
2052 0 : }
2053 :
2054 0 : void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2055 : std::vector<u16> *far_players, float far_d_nodes,
2056 : bool remove_metadata)
2057 : {
2058 0 : float maxd = far_d_nodes*BS;
2059 0 : v3f p_f = intToFloat(p, BS);
2060 :
2061 0 : std::vector<u16> clients = m_clients.getClientIDs();
2062 0 : for(std::vector<u16>::iterator i = clients.begin();
2063 0 : i != clients.end(); ++i) {
2064 :
2065 0 : if(far_players) {
2066 : // Get player
2067 0 : if(Player *player = m_env->getPlayer(*i)) {
2068 : // If player is far away, only set modified blocks not sent
2069 0 : v3f player_pos = player->getPosition();
2070 0 : if(player_pos.getDistanceFrom(p_f) > maxd) {
2071 0 : far_players->push_back(*i);
2072 0 : continue;
2073 : }
2074 : }
2075 : }
2076 :
2077 0 : NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2078 0 : m_clients.Lock();
2079 0 : RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2080 0 : if (client != 0) {
2081 0 : pkt << p << n.param0 << n.param1 << n.param2
2082 0 : << (u8) (remove_metadata ? 0 : 1);
2083 :
2084 0 : if (!remove_metadata) {
2085 0 : if (client->net_proto_version <= 21) {
2086 : // Old clients always clear metadata; fix it
2087 : // by sending the full block again.
2088 0 : client->SetBlockNotSent(p);
2089 : }
2090 : }
2091 : }
2092 0 : m_clients.Unlock();
2093 :
2094 : // Send as reliable
2095 0 : if (pkt.getSize() > 0)
2096 0 : m_clients.send(*i, 0, &pkt, true);
2097 : }
2098 0 : }
2099 :
2100 0 : void Server::setBlockNotSent(v3s16 p)
2101 : {
2102 0 : std::vector<u16> clients = m_clients.getClientIDs();
2103 0 : m_clients.Lock();
2104 0 : for(std::vector<u16>::iterator i = clients.begin();
2105 0 : i != clients.end(); ++i) {
2106 0 : RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2107 0 : client->SetBlockNotSent(p);
2108 : }
2109 0 : m_clients.Unlock();
2110 0 : }
2111 :
2112 0 : void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2113 : {
2114 0 : DSTACK(__FUNCTION_NAME);
2115 :
2116 0 : v3s16 p = block->getPos();
2117 :
2118 : /*
2119 : Create a packet with the block in the right format
2120 : */
2121 :
2122 0 : std::ostringstream os(std::ios_base::binary);
2123 0 : block->serialize(os, ver, false);
2124 0 : block->serializeNetworkSpecific(os, net_proto_version);
2125 0 : std::string s = os.str();
2126 :
2127 0 : NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2128 :
2129 0 : pkt << p;
2130 0 : pkt.putRawString(s.c_str(), s.size());
2131 0 : Send(&pkt);
2132 0 : }
2133 :
2134 0 : void Server::SendBlocks(float dtime)
2135 : {
2136 0 : DSTACK(__FUNCTION_NAME);
2137 :
2138 0 : JMutexAutoLock envlock(m_env_mutex);
2139 : //TODO check if one big lock could be faster then multiple small ones
2140 :
2141 0 : ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2142 :
2143 0 : std::vector<PrioritySortedBlockTransfer> queue;
2144 :
2145 0 : s32 total_sending = 0;
2146 :
2147 : {
2148 0 : ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2149 :
2150 0 : std::vector<u16> clients = m_clients.getClientIDs();
2151 :
2152 0 : m_clients.Lock();
2153 0 : for(std::vector<u16>::iterator i = clients.begin();
2154 0 : i != clients.end(); ++i) {
2155 0 : RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2156 :
2157 0 : if (client == NULL)
2158 0 : continue;
2159 :
2160 0 : total_sending += client->SendingCount();
2161 0 : client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2162 : }
2163 0 : m_clients.Unlock();
2164 : }
2165 :
2166 : // Sort.
2167 : // Lowest priority number comes first.
2168 : // Lowest is most important.
2169 0 : std::sort(queue.begin(), queue.end());
2170 :
2171 0 : m_clients.Lock();
2172 0 : for(u32 i=0; i<queue.size(); i++)
2173 : {
2174 : //TODO: Calculate limit dynamically
2175 0 : if(total_sending >= g_settings->getS32
2176 0 : ("max_simultaneous_block_sends_server_total"))
2177 0 : break;
2178 :
2179 0 : PrioritySortedBlockTransfer q = queue[i];
2180 :
2181 0 : MapBlock *block = NULL;
2182 : try
2183 : {
2184 0 : block = m_env->getMap().getBlockNoCreate(q.pos);
2185 : }
2186 0 : catch(InvalidPositionException &e)
2187 : {
2188 0 : continue;
2189 : }
2190 :
2191 0 : RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2192 :
2193 0 : if(!client)
2194 0 : continue;
2195 :
2196 0 : SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2197 :
2198 0 : client->SentBlock(q.pos);
2199 0 : total_sending++;
2200 : }
2201 0 : m_clients.Unlock();
2202 0 : }
2203 :
2204 0 : void Server::fillMediaCache()
2205 : {
2206 0 : DSTACK(__FUNCTION_NAME);
2207 :
2208 0 : infostream<<"Server: Calculating media file checksums"<<std::endl;
2209 :
2210 : // Collect all media file paths
2211 0 : std::vector<std::string> paths;
2212 0 : for(std::vector<ModSpec>::iterator i = m_mods.begin();
2213 0 : i != m_mods.end(); i++) {
2214 0 : const ModSpec &mod = *i;
2215 0 : paths.push_back(mod.path + DIR_DELIM + "textures");
2216 0 : paths.push_back(mod.path + DIR_DELIM + "sounds");
2217 0 : paths.push_back(mod.path + DIR_DELIM + "media");
2218 0 : paths.push_back(mod.path + DIR_DELIM + "models");
2219 : }
2220 0 : paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2221 :
2222 : // Collect media file information from paths into cache
2223 0 : for(std::vector<std::string>::iterator i = paths.begin();
2224 0 : i != paths.end(); i++) {
2225 0 : std::string mediapath = *i;
2226 0 : std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2227 0 : for (u32 j = 0; j < dirlist.size(); j++) {
2228 0 : if (dirlist[j].dir) // Ignode dirs
2229 0 : continue;
2230 0 : std::string filename = dirlist[j].name;
2231 : // If name contains illegal characters, ignore the file
2232 0 : if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2233 0 : infostream<<"Server: ignoring illegal file name: \""
2234 0 : << filename << "\"" << std::endl;
2235 0 : continue;
2236 : }
2237 : // If name is not in a supported format, ignore it
2238 : const char *supported_ext[] = {
2239 : ".png", ".jpg", ".bmp", ".tga",
2240 : ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2241 : ".ogg",
2242 : ".x", ".b3d", ".md2", ".obj",
2243 : NULL
2244 0 : };
2245 0 : if (removeStringEnd(filename, supported_ext) == ""){
2246 0 : infostream << "Server: ignoring unsupported file extension: \""
2247 0 : << filename << "\"" << std::endl;
2248 0 : continue;
2249 : }
2250 : // Ok, attempt to load the file and add to cache
2251 0 : std::string filepath = mediapath + DIR_DELIM + filename;
2252 : // Read data
2253 0 : std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2254 0 : if (!fis.good()) {
2255 0 : errorstream << "Server::fillMediaCache(): Could not open \""
2256 0 : << filename << "\" for reading" << std::endl;
2257 0 : continue;
2258 : }
2259 0 : std::ostringstream tmp_os(std::ios_base::binary);
2260 0 : bool bad = false;
2261 0 : for(;;) {
2262 : char buf[1024];
2263 0 : fis.read(buf, 1024);
2264 0 : std::streamsize len = fis.gcount();
2265 0 : tmp_os.write(buf, len);
2266 0 : if (fis.eof())
2267 0 : break;
2268 0 : if (!fis.good()) {
2269 0 : bad = true;
2270 0 : break;
2271 : }
2272 : }
2273 0 : if(bad) {
2274 0 : errorstream<<"Server::fillMediaCache(): Failed to read \""
2275 0 : << filename << "\"" << std::endl;
2276 0 : continue;
2277 : }
2278 0 : if(tmp_os.str().length() == 0) {
2279 0 : errorstream << "Server::fillMediaCache(): Empty file \""
2280 0 : << filepath << "\"" << std::endl;
2281 0 : continue;
2282 : }
2283 :
2284 0 : SHA1 sha1;
2285 0 : sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2286 :
2287 0 : unsigned char *digest = sha1.getDigest();
2288 0 : std::string sha1_base64 = base64_encode(digest, 20);
2289 0 : std::string sha1_hex = hex_encode((char*)digest, 20);
2290 0 : free(digest);
2291 :
2292 : // Put in list
2293 0 : m_media[filename] = MediaInfo(filepath, sha1_base64);
2294 0 : verbosestream << "Server: " << sha1_hex << " is " << filename
2295 0 : << std::endl;
2296 : }
2297 : }
2298 0 : }
2299 :
2300 0 : struct SendableMediaAnnouncement
2301 : {
2302 : std::string name;
2303 : std::string sha1_digest;
2304 :
2305 0 : SendableMediaAnnouncement(const std::string &name_="",
2306 : const std::string &sha1_digest_=""):
2307 : name(name_),
2308 0 : sha1_digest(sha1_digest_)
2309 0 : {}
2310 : };
2311 :
2312 0 : void Server::sendMediaAnnouncement(u16 peer_id)
2313 : {
2314 0 : DSTACK(__FUNCTION_NAME);
2315 :
2316 0 : verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
2317 0 : <<std::endl;
2318 :
2319 0 : std::vector<SendableMediaAnnouncement> file_announcements;
2320 :
2321 0 : for (std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2322 0 : i != m_media.end(); i++){
2323 : // Put in list
2324 0 : file_announcements.push_back(
2325 0 : SendableMediaAnnouncement(i->first, i->second.sha1_digest));
2326 : }
2327 :
2328 : // Make packet
2329 0 : std::ostringstream os(std::ios_base::binary);
2330 :
2331 0 : NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2332 0 : pkt << (u16) file_announcements.size();
2333 :
2334 0 : for (std::vector<SendableMediaAnnouncement>::iterator
2335 0 : j = file_announcements.begin();
2336 0 : j != file_announcements.end(); ++j) {
2337 0 : pkt << j->name << j->sha1_digest;
2338 : }
2339 :
2340 0 : pkt << g_settings->get("remote_media");
2341 0 : Send(&pkt);
2342 0 : }
2343 :
2344 0 : struct SendableMedia
2345 : {
2346 : std::string name;
2347 : std::string path;
2348 : std::string data;
2349 :
2350 0 : SendableMedia(const std::string &name_="", const std::string &path_="",
2351 : const std::string &data_=""):
2352 : name(name_),
2353 : path(path_),
2354 0 : data(data_)
2355 0 : {}
2356 : };
2357 :
2358 0 : void Server::sendRequestedMedia(u16 peer_id,
2359 : const std::vector<std::string> &tosend)
2360 : {
2361 0 : DSTACK(__FUNCTION_NAME);
2362 :
2363 0 : verbosestream<<"Server::sendRequestedMedia(): "
2364 0 : <<"Sending files to client"<<std::endl;
2365 :
2366 : /* Read files */
2367 :
2368 : // Put 5kB in one bunch (this is not accurate)
2369 0 : u32 bytes_per_bunch = 5000;
2370 :
2371 0 : std::vector< std::vector<SendableMedia> > file_bunches;
2372 0 : file_bunches.push_back(std::vector<SendableMedia>());
2373 :
2374 0 : u32 file_size_bunch_total = 0;
2375 :
2376 0 : for(std::vector<std::string>::const_iterator i = tosend.begin();
2377 0 : i != tosend.end(); ++i) {
2378 0 : const std::string &name = *i;
2379 :
2380 0 : if(m_media.find(name) == m_media.end()) {
2381 0 : errorstream<<"Server::sendRequestedMedia(): Client asked for "
2382 0 : <<"unknown file \""<<(name)<<"\""<<std::endl;
2383 0 : continue;
2384 : }
2385 :
2386 : //TODO get path + name
2387 0 : std::string tpath = m_media[name].path;
2388 :
2389 : // Read data
2390 0 : std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2391 0 : if(fis.good() == false){
2392 0 : errorstream<<"Server::sendRequestedMedia(): Could not open \""
2393 0 : <<tpath<<"\" for reading"<<std::endl;
2394 0 : continue;
2395 : }
2396 0 : std::ostringstream tmp_os(std::ios_base::binary);
2397 0 : bool bad = false;
2398 0 : for(;;) {
2399 : char buf[1024];
2400 0 : fis.read(buf, 1024);
2401 0 : std::streamsize len = fis.gcount();
2402 0 : tmp_os.write(buf, len);
2403 0 : file_size_bunch_total += len;
2404 0 : if(fis.eof())
2405 0 : break;
2406 0 : if(!fis.good()) {
2407 0 : bad = true;
2408 0 : break;
2409 : }
2410 : }
2411 0 : if(bad) {
2412 0 : errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2413 0 : <<name<<"\""<<std::endl;
2414 0 : continue;
2415 : }
2416 : /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2417 : <<tname<<"\""<<std::endl;*/
2418 : // Put in list
2419 0 : file_bunches[file_bunches.size()-1].push_back(
2420 0 : SendableMedia(name, tpath, tmp_os.str()));
2421 :
2422 : // Start next bunch if got enough data
2423 0 : if(file_size_bunch_total >= bytes_per_bunch) {
2424 0 : file_bunches.push_back(std::vector<SendableMedia>());
2425 0 : file_size_bunch_total = 0;
2426 : }
2427 :
2428 : }
2429 :
2430 : /* Create and send packets */
2431 :
2432 0 : u16 num_bunches = file_bunches.size();
2433 0 : for(u16 i = 0; i < num_bunches; i++) {
2434 : /*
2435 : u16 command
2436 : u16 total number of texture bunches
2437 : u16 index of this bunch
2438 : u32 number of files in this bunch
2439 : for each file {
2440 : u16 length of name
2441 : string name
2442 : u32 length of data
2443 : data
2444 : }
2445 : */
2446 :
2447 0 : NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2448 0 : pkt << num_bunches << i << (u32) file_bunches[i].size();
2449 :
2450 0 : for(std::vector<SendableMedia>::iterator
2451 0 : j = file_bunches[i].begin();
2452 0 : j != file_bunches[i].end(); ++j) {
2453 0 : pkt << j->name;
2454 0 : pkt.putLongString(j->data);
2455 : }
2456 :
2457 0 : verbosestream << "Server::sendRequestedMedia(): bunch "
2458 0 : << i << "/" << num_bunches
2459 0 : << " files=" << file_bunches[i].size()
2460 0 : << " size=" << pkt.getSize() << std::endl;
2461 0 : Send(&pkt);
2462 : }
2463 0 : }
2464 :
2465 0 : void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2466 : {
2467 0 : if(m_detached_inventories.count(name) == 0) {
2468 0 : errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2469 0 : return;
2470 : }
2471 0 : Inventory *inv = m_detached_inventories[name];
2472 0 : std::ostringstream os(std::ios_base::binary);
2473 :
2474 0 : os << serializeString(name);
2475 0 : inv->serialize(os);
2476 :
2477 : // Make data buffer
2478 0 : std::string s = os.str();
2479 :
2480 0 : NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2481 0 : pkt.putRawString(s.c_str(), s.size());
2482 :
2483 0 : if (peer_id != PEER_ID_INEXISTENT) {
2484 0 : Send(&pkt);
2485 : }
2486 : else {
2487 0 : m_clients.sendToAll(0, &pkt, true);
2488 : }
2489 : }
2490 :
2491 0 : void Server::sendDetachedInventories(u16 peer_id)
2492 : {
2493 0 : DSTACK(__FUNCTION_NAME);
2494 :
2495 0 : for(std::map<std::string, Inventory*>::iterator
2496 0 : i = m_detached_inventories.begin();
2497 0 : i != m_detached_inventories.end(); i++) {
2498 0 : const std::string &name = i->first;
2499 : //Inventory *inv = i->second;
2500 0 : sendDetachedInventory(name, peer_id);
2501 : }
2502 0 : }
2503 :
2504 : /*
2505 : Something random
2506 : */
2507 :
2508 0 : void Server::DiePlayer(u16 peer_id)
2509 : {
2510 0 : DSTACK(__FUNCTION_NAME);
2511 :
2512 0 : PlayerSAO *playersao = getPlayerSAO(peer_id);
2513 : assert(playersao);
2514 :
2515 0 : infostream << "Server::DiePlayer(): Player "
2516 0 : << playersao->getPlayer()->getName()
2517 0 : << " dies" << std::endl;
2518 :
2519 0 : playersao->setHP(0);
2520 :
2521 : // Trigger scripted stuff
2522 0 : m_script->on_dieplayer(playersao);
2523 :
2524 0 : SendPlayerHP(peer_id);
2525 0 : SendDeathscreen(peer_id, false, v3f(0,0,0));
2526 0 : }
2527 :
2528 0 : void Server::RespawnPlayer(u16 peer_id)
2529 : {
2530 0 : DSTACK(__FUNCTION_NAME);
2531 :
2532 0 : PlayerSAO *playersao = getPlayerSAO(peer_id);
2533 : assert(playersao);
2534 :
2535 0 : infostream << "Server::RespawnPlayer(): Player "
2536 0 : << playersao->getPlayer()->getName()
2537 0 : << " respawns" << std::endl;
2538 :
2539 0 : playersao->setHP(PLAYER_MAX_HP);
2540 0 : playersao->setBreath(PLAYER_MAX_BREATH);
2541 :
2542 0 : SendPlayerHP(peer_id);
2543 0 : SendPlayerBreath(peer_id);
2544 :
2545 0 : bool repositioned = m_script->on_respawnplayer(playersao);
2546 0 : if(!repositioned){
2547 0 : v3f pos = findSpawnPos();
2548 : // setPos will send the new position to client
2549 0 : playersao->setPos(pos);
2550 : }
2551 0 : }
2552 0 : void Server::DenySudoAccess(u16 peer_id)
2553 : {
2554 0 : DSTACK(__FUNCTION_NAME);
2555 :
2556 0 : NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2557 0 : Send(&pkt);
2558 0 : }
2559 :
2560 0 : void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
2561 : {
2562 0 : DSTACK(__FUNCTION_NAME);
2563 :
2564 0 : SendAccessDenied(peer_id, reason, custom_reason);
2565 0 : m_clients.event(peer_id, CSE_SetDenied);
2566 0 : m_con.DisconnectPeer(peer_id);
2567 0 : }
2568 :
2569 : // 13/03/15: remove this function when protocol version 25 will become
2570 : // the minimum version for MT users, maybe in 1 year
2571 0 : void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
2572 : {
2573 0 : DSTACK(__FUNCTION_NAME);
2574 :
2575 0 : SendAccessDenied_Legacy(peer_id, reason);
2576 0 : m_clients.event(peer_id, CSE_SetDenied);
2577 0 : m_con.DisconnectPeer(peer_id);
2578 0 : }
2579 :
2580 0 : void Server::acceptAuth(u16 peer_id, bool forSudoMode)
2581 : {
2582 0 : DSTACK(__FUNCTION_NAME);
2583 :
2584 0 : if (!forSudoMode) {
2585 0 : RemoteClient* client = getClient(peer_id, CS_Invalid);
2586 :
2587 0 : NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2588 :
2589 : // Right now, the auth mechs don't change between login and sudo mode.
2590 0 : u32 sudo_auth_mechs = client->allowed_auth_mechs;
2591 0 : client->allowed_sudo_mechs = sudo_auth_mechs;
2592 :
2593 0 : resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2594 0 : << g_settings->getFloat("dedicated_server_step")
2595 0 : << sudo_auth_mechs;
2596 :
2597 0 : Send(&resp_pkt);
2598 0 : m_clients.event(peer_id, CSE_AuthAccept);
2599 : } else {
2600 0 : NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2601 :
2602 : // We only support SRP right now
2603 0 : u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2604 :
2605 0 : resp_pkt << sudo_auth_mechs;
2606 0 : Send(&resp_pkt);
2607 0 : m_clients.event(peer_id, CSE_SudoSuccess);
2608 : }
2609 0 : }
2610 :
2611 0 : void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2612 : {
2613 0 : DSTACK(__FUNCTION_NAME);
2614 0 : std::wstring message;
2615 : {
2616 : /*
2617 : Clear references to playing sounds
2618 : */
2619 0 : for(std::map<s32, ServerPlayingSound>::iterator
2620 0 : i = m_playing_sounds.begin();
2621 0 : i != m_playing_sounds.end();)
2622 : {
2623 0 : ServerPlayingSound &psound = i->second;
2624 0 : psound.clients.erase(peer_id);
2625 0 : if(psound.clients.empty())
2626 0 : m_playing_sounds.erase(i++);
2627 : else
2628 0 : i++;
2629 : }
2630 :
2631 0 : Player *player = m_env->getPlayer(peer_id);
2632 :
2633 : // Collect information about leaving in chat
2634 : {
2635 0 : if(player != NULL && reason != CDR_DENY)
2636 : {
2637 0 : std::wstring name = narrow_to_wide(player->getName());
2638 0 : message += L"*** ";
2639 0 : message += name;
2640 0 : message += L" left the game.";
2641 0 : if(reason == CDR_TIMEOUT)
2642 0 : message += L" (timed out)";
2643 : }
2644 : }
2645 :
2646 : /* Run scripts and remove from environment */
2647 : {
2648 0 : if(player != NULL)
2649 : {
2650 0 : PlayerSAO *playersao = player->getPlayerSAO();
2651 : assert(playersao);
2652 :
2653 0 : m_script->on_leaveplayer(playersao);
2654 :
2655 0 : playersao->disconnected();
2656 : }
2657 : }
2658 :
2659 : /*
2660 : Print out action
2661 : */
2662 : {
2663 0 : if(player != NULL && reason != CDR_DENY) {
2664 0 : std::ostringstream os(std::ios_base::binary);
2665 0 : std::vector<u16> clients = m_clients.getClientIDs();
2666 :
2667 0 : for(std::vector<u16>::iterator i = clients.begin();
2668 0 : i != clients.end(); ++i) {
2669 : // Get player
2670 0 : Player *player = m_env->getPlayer(*i);
2671 0 : if(!player)
2672 0 : continue;
2673 :
2674 : // Get name of player
2675 0 : os << player->getName() << " ";
2676 : }
2677 :
2678 0 : actionstream << player->getName() << " "
2679 0 : << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2680 0 : << " List of players: " << os.str() << std::endl;
2681 : }
2682 : }
2683 : {
2684 0 : JMutexAutoLock env_lock(m_env_mutex);
2685 0 : m_clients.DeleteClient(peer_id);
2686 : }
2687 : }
2688 :
2689 : // Send leave chat message to all remaining clients
2690 0 : if(message.length() != 0)
2691 0 : SendChatMessage(PEER_ID_INEXISTENT,message);
2692 0 : }
2693 :
2694 0 : void Server::UpdateCrafting(Player* player)
2695 : {
2696 0 : DSTACK(__FUNCTION_NAME);
2697 :
2698 : // Get a preview for crafting
2699 0 : ItemStack preview;
2700 0 : InventoryLocation loc;
2701 0 : loc.setPlayer(player->getName());
2702 0 : std::vector<ItemStack> output_replacements;
2703 0 : getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2704 0 : m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2705 :
2706 : // Put the new preview in
2707 0 : InventoryList *plist = player->inventory.getList("craftpreview");
2708 0 : sanity_check(plist);
2709 0 : sanity_check(plist->getSize() >= 1);
2710 0 : plist->changeItem(0, preview);
2711 0 : }
2712 :
2713 0 : RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2714 : {
2715 0 : RemoteClient *client = getClientNoEx(peer_id,state_min);
2716 0 : if(!client)
2717 0 : throw ClientNotFoundException("Client not found");
2718 :
2719 0 : return client;
2720 : }
2721 0 : RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2722 : {
2723 0 : return m_clients.getClientNoEx(peer_id, state_min);
2724 : }
2725 :
2726 0 : std::string Server::getPlayerName(u16 peer_id)
2727 : {
2728 0 : Player *player = m_env->getPlayer(peer_id);
2729 0 : if(player == NULL)
2730 0 : return "[id="+itos(peer_id)+"]";
2731 0 : return player->getName();
2732 : }
2733 :
2734 0 : PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2735 : {
2736 0 : Player *player = m_env->getPlayer(peer_id);
2737 0 : if(player == NULL)
2738 0 : return NULL;
2739 0 : return player->getPlayerSAO();
2740 : }
2741 :
2742 0 : std::wstring Server::getStatusString()
2743 : {
2744 0 : std::wostringstream os(std::ios_base::binary);
2745 0 : os<<L"# Server: ";
2746 : // Version
2747 0 : os<<L"version="<<narrow_to_wide(g_version_string);
2748 : // Uptime
2749 0 : os<<L", uptime="<<m_uptime.get();
2750 : // Max lag estimate
2751 0 : os<<L", max_lag="<<m_env->getMaxLagEstimate();
2752 : // Information about clients
2753 0 : bool first = true;
2754 0 : os<<L", clients={";
2755 0 : std::vector<u16> clients = m_clients.getClientIDs();
2756 0 : for(std::vector<u16>::iterator i = clients.begin();
2757 0 : i != clients.end(); ++i) {
2758 : // Get player
2759 0 : Player *player = m_env->getPlayer(*i);
2760 : // Get name of player
2761 0 : std::wstring name = L"unknown";
2762 0 : if(player != NULL)
2763 0 : name = narrow_to_wide(player->getName());
2764 : // Add name to information string
2765 0 : if(!first)
2766 0 : os << L", ";
2767 : else
2768 0 : first = false;
2769 0 : os << name;
2770 : }
2771 0 : os << L"}";
2772 0 : if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2773 0 : os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2774 0 : if(g_settings->get("motd") != "")
2775 0 : os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2776 0 : return os.str();
2777 : }
2778 :
2779 0 : std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2780 : {
2781 0 : std::set<std::string> privs;
2782 0 : m_script->getAuth(name, NULL, &privs);
2783 0 : return privs;
2784 : }
2785 :
2786 0 : bool Server::checkPriv(const std::string &name, const std::string &priv)
2787 : {
2788 0 : std::set<std::string> privs = getPlayerEffectivePrivs(name);
2789 0 : return (privs.count(priv) != 0);
2790 : }
2791 :
2792 0 : void Server::reportPrivsModified(const std::string &name)
2793 : {
2794 0 : if(name == "") {
2795 0 : std::vector<u16> clients = m_clients.getClientIDs();
2796 0 : for(std::vector<u16>::iterator i = clients.begin();
2797 0 : i != clients.end(); ++i) {
2798 0 : Player *player = m_env->getPlayer(*i);
2799 0 : reportPrivsModified(player->getName());
2800 : }
2801 : } else {
2802 0 : Player *player = m_env->getPlayer(name.c_str());
2803 0 : if(!player)
2804 0 : return;
2805 0 : SendPlayerPrivileges(player->peer_id);
2806 0 : PlayerSAO *sao = player->getPlayerSAO();
2807 0 : if(!sao)
2808 0 : return;
2809 0 : sao->updatePrivileges(
2810 0 : getPlayerEffectivePrivs(name),
2811 0 : isSingleplayer());
2812 : }
2813 : }
2814 :
2815 0 : void Server::reportInventoryFormspecModified(const std::string &name)
2816 : {
2817 0 : Player *player = m_env->getPlayer(name.c_str());
2818 0 : if(!player)
2819 0 : return;
2820 0 : SendPlayerInventoryFormspec(player->peer_id);
2821 : }
2822 :
2823 0 : void Server::setIpBanned(const std::string &ip, const std::string &name)
2824 : {
2825 0 : m_banmanager->add(ip, name);
2826 0 : }
2827 :
2828 0 : void Server::unsetIpBanned(const std::string &ip_or_name)
2829 : {
2830 0 : m_banmanager->remove(ip_or_name);
2831 0 : }
2832 :
2833 0 : std::string Server::getBanDescription(const std::string &ip_or_name)
2834 : {
2835 0 : return m_banmanager->getBanDescription(ip_or_name);
2836 : }
2837 :
2838 0 : void Server::notifyPlayer(const char *name, const std::wstring &msg)
2839 : {
2840 0 : Player *player = m_env->getPlayer(name);
2841 0 : if(!player)
2842 0 : return;
2843 :
2844 0 : if (player->peer_id == PEER_ID_INEXISTENT)
2845 0 : return;
2846 :
2847 0 : SendChatMessage(player->peer_id, msg);
2848 : }
2849 :
2850 0 : bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
2851 : {
2852 0 : Player *player = m_env->getPlayer(playername);
2853 :
2854 0 : if(!player)
2855 : {
2856 0 : infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
2857 0 : return false;
2858 : }
2859 :
2860 0 : SendShowFormspecMessage(player->peer_id, formspec, formname);
2861 0 : return true;
2862 : }
2863 :
2864 0 : u32 Server::hudAdd(Player *player, HudElement *form) {
2865 0 : if (!player)
2866 0 : return -1;
2867 :
2868 0 : u32 id = player->addHud(form);
2869 :
2870 0 : SendHUDAdd(player->peer_id, id, form);
2871 :
2872 0 : return id;
2873 : }
2874 :
2875 0 : bool Server::hudRemove(Player *player, u32 id) {
2876 0 : if (!player)
2877 0 : return false;
2878 :
2879 0 : HudElement* todel = player->removeHud(id);
2880 :
2881 0 : if (!todel)
2882 0 : return false;
2883 :
2884 0 : delete todel;
2885 :
2886 0 : SendHUDRemove(player->peer_id, id);
2887 0 : return true;
2888 : }
2889 :
2890 0 : bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
2891 0 : if (!player)
2892 0 : return false;
2893 :
2894 0 : SendHUDChange(player->peer_id, id, stat, data);
2895 0 : return true;
2896 : }
2897 :
2898 0 : bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
2899 0 : if (!player)
2900 0 : return false;
2901 :
2902 0 : SendHUDSetFlags(player->peer_id, flags, mask);
2903 0 : player->hud_flags = flags;
2904 :
2905 0 : PlayerSAO* playersao = player->getPlayerSAO();
2906 :
2907 0 : if (playersao == NULL)
2908 0 : return false;
2909 :
2910 0 : m_script->player_event(playersao, "hud_changed");
2911 0 : return true;
2912 : }
2913 :
2914 0 : bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
2915 0 : if (!player)
2916 0 : return false;
2917 0 : if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
2918 0 : return false;
2919 :
2920 0 : player->setHotbarItemcount(hotbar_itemcount);
2921 0 : std::ostringstream os(std::ios::binary);
2922 0 : writeS32(os, hotbar_itemcount);
2923 0 : SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
2924 0 : return true;
2925 : }
2926 :
2927 0 : s32 Server::hudGetHotbarItemcount(Player *player) {
2928 0 : if (!player)
2929 0 : return 0;
2930 0 : return player->getHotbarItemcount();
2931 : }
2932 :
2933 0 : void Server::hudSetHotbarImage(Player *player, std::string name) {
2934 0 : if (!player)
2935 0 : return;
2936 :
2937 0 : player->setHotbarImage(name);
2938 0 : SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
2939 : }
2940 :
2941 0 : std::string Server::hudGetHotbarImage(Player *player) {
2942 0 : if (!player)
2943 0 : return "";
2944 0 : return player->getHotbarImage();
2945 : }
2946 :
2947 0 : void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
2948 0 : if (!player)
2949 0 : return;
2950 :
2951 0 : player->setHotbarSelectedImage(name);
2952 0 : SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
2953 : }
2954 :
2955 0 : std::string Server::hudGetHotbarSelectedImage(Player *player) {
2956 0 : if (!player)
2957 0 : return "";
2958 :
2959 0 : return player->getHotbarSelectedImage();
2960 : }
2961 :
2962 0 : bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
2963 : {
2964 0 : if (!player)
2965 0 : return false;
2966 :
2967 0 : player->setLocalAnimations(animation_frames, frame_speed);
2968 0 : SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
2969 0 : return true;
2970 : }
2971 :
2972 0 : bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
2973 : {
2974 0 : if (!player)
2975 0 : return false;
2976 :
2977 0 : player->eye_offset_first = first;
2978 0 : player->eye_offset_third = third;
2979 0 : SendEyeOffset(player->peer_id, first, third);
2980 0 : return true;
2981 : }
2982 :
2983 0 : bool Server::setSky(Player *player, const video::SColor &bgcolor,
2984 : const std::string &type, const std::vector<std::string> ¶ms)
2985 : {
2986 0 : if (!player)
2987 0 : return false;
2988 :
2989 0 : player->setSky(bgcolor, type, params);
2990 0 : SendSetSky(player->peer_id, bgcolor, type, params);
2991 0 : return true;
2992 : }
2993 :
2994 0 : bool Server::overrideDayNightRatio(Player *player, bool do_override,
2995 : float ratio)
2996 : {
2997 0 : if (!player)
2998 0 : return false;
2999 :
3000 0 : player->overrideDayNightRatio(do_override, ratio);
3001 0 : SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
3002 0 : return true;
3003 : }
3004 :
3005 0 : void Server::notifyPlayers(const std::wstring &msg)
3006 : {
3007 0 : SendChatMessage(PEER_ID_INEXISTENT,msg);
3008 0 : }
3009 :
3010 0 : void Server::spawnParticle(const char *playername, v3f pos,
3011 : v3f velocity, v3f acceleration,
3012 : float expirationtime, float size, bool
3013 : collisiondetection, bool vertical, std::string texture)
3014 : {
3015 0 : Player *player = m_env->getPlayer(playername);
3016 0 : if(!player)
3017 0 : return;
3018 0 : SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
3019 0 : expirationtime, size, collisiondetection, vertical, texture);
3020 : }
3021 :
3022 0 : void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
3023 : float expirationtime, float size,
3024 : bool collisiondetection, bool vertical, std::string texture)
3025 : {
3026 0 : SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
3027 0 : expirationtime, size, collisiondetection, vertical, texture);
3028 0 : }
3029 :
3030 0 : u32 Server::addParticleSpawner(const char *playername,
3031 : u16 amount, float spawntime,
3032 : v3f minpos, v3f maxpos,
3033 : v3f minvel, v3f maxvel,
3034 : v3f minacc, v3f maxacc,
3035 : float minexptime, float maxexptime,
3036 : float minsize, float maxsize,
3037 : bool collisiondetection, bool vertical, std::string texture)
3038 : {
3039 0 : Player *player = m_env->getPlayer(playername);
3040 0 : if(!player)
3041 0 : return -1;
3042 :
3043 0 : u32 id = 0;
3044 0 : for(;;) // look for unused particlespawner id
3045 : {
3046 0 : id++;
3047 0 : if (std::find(m_particlespawner_ids.begin(),
3048 0 : m_particlespawner_ids.end(), id)
3049 0 : == m_particlespawner_ids.end())
3050 : {
3051 0 : m_particlespawner_ids.push_back(id);
3052 0 : break;
3053 : }
3054 : }
3055 :
3056 0 : SendAddParticleSpawner(player->peer_id, amount, spawntime,
3057 : minpos, maxpos, minvel, maxvel, minacc, maxacc,
3058 : minexptime, maxexptime, minsize, maxsize,
3059 0 : collisiondetection, vertical, texture, id);
3060 :
3061 0 : return id;
3062 : }
3063 :
3064 0 : u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
3065 : v3f minpos, v3f maxpos,
3066 : v3f minvel, v3f maxvel,
3067 : v3f minacc, v3f maxacc,
3068 : float minexptime, float maxexptime,
3069 : float minsize, float maxsize,
3070 : bool collisiondetection, bool vertical, std::string texture)
3071 : {
3072 0 : u32 id = 0;
3073 0 : for(;;) // look for unused particlespawner id
3074 : {
3075 0 : id++;
3076 0 : if (std::find(m_particlespawner_ids.begin(),
3077 0 : m_particlespawner_ids.end(), id)
3078 0 : == m_particlespawner_ids.end())
3079 : {
3080 0 : m_particlespawner_ids.push_back(id);
3081 0 : break;
3082 : }
3083 : }
3084 :
3085 0 : SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
3086 : minpos, maxpos, minvel, maxvel, minacc, maxacc,
3087 : minexptime, maxexptime, minsize, maxsize,
3088 0 : collisiondetection, vertical, texture, id);
3089 :
3090 0 : return id;
3091 : }
3092 :
3093 0 : void Server::deleteParticleSpawner(const char *playername, u32 id)
3094 : {
3095 0 : Player *player = m_env->getPlayer(playername);
3096 0 : if(!player)
3097 0 : return;
3098 :
3099 : m_particlespawner_ids.erase(
3100 : std::remove(m_particlespawner_ids.begin(),
3101 : m_particlespawner_ids.end(), id),
3102 0 : m_particlespawner_ids.end());
3103 0 : SendDeleteParticleSpawner(player->peer_id, id);
3104 : }
3105 :
3106 0 : void Server::deleteParticleSpawnerAll(u32 id)
3107 : {
3108 : m_particlespawner_ids.erase(
3109 : std::remove(m_particlespawner_ids.begin(),
3110 : m_particlespawner_ids.end(), id),
3111 0 : m_particlespawner_ids.end());
3112 0 : SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
3113 0 : }
3114 :
3115 0 : Inventory* Server::createDetachedInventory(const std::string &name)
3116 : {
3117 0 : if(m_detached_inventories.count(name) > 0){
3118 0 : infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3119 0 : delete m_detached_inventories[name];
3120 : } else {
3121 0 : infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3122 : }
3123 0 : Inventory *inv = new Inventory(m_itemdef);
3124 0 : sanity_check(inv);
3125 0 : m_detached_inventories[name] = inv;
3126 : //TODO find a better way to do this
3127 0 : sendDetachedInventory(name,PEER_ID_INEXISTENT);
3128 0 : return inv;
3129 : }
3130 :
3131 : class BoolScopeSet
3132 : {
3133 : public:
3134 : BoolScopeSet(bool *dst, bool val):
3135 : m_dst(dst)
3136 : {
3137 : m_orig_state = *m_dst;
3138 : *m_dst = val;
3139 : }
3140 : ~BoolScopeSet()
3141 : {
3142 : *m_dst = m_orig_state;
3143 : }
3144 : private:
3145 : bool *m_dst;
3146 : bool m_orig_state;
3147 : };
3148 :
3149 : // actions: time-reversed list
3150 : // Return value: success/failure
3151 0 : bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3152 : std::list<std::string> *log)
3153 : {
3154 0 : infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3155 0 : ServerMap *map = (ServerMap*)(&m_env->getMap());
3156 :
3157 : // Fail if no actions to handle
3158 0 : if(actions.empty()){
3159 0 : log->push_back("Nothing to do.");
3160 0 : return false;
3161 : }
3162 :
3163 0 : int num_tried = 0;
3164 0 : int num_failed = 0;
3165 :
3166 0 : for(std::list<RollbackAction>::const_iterator
3167 0 : i = actions.begin();
3168 0 : i != actions.end(); i++)
3169 : {
3170 0 : const RollbackAction &action = *i;
3171 0 : num_tried++;
3172 0 : bool success = action.applyRevert(map, this, this);
3173 0 : if(!success){
3174 0 : num_failed++;
3175 0 : std::ostringstream os;
3176 0 : os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3177 0 : infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3178 0 : if(log)
3179 0 : log->push_back(os.str());
3180 : }else{
3181 0 : std::ostringstream os;
3182 0 : os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3183 0 : infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3184 0 : if(log)
3185 0 : log->push_back(os.str());
3186 : }
3187 : }
3188 :
3189 0 : infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3190 0 : <<" failed"<<std::endl;
3191 :
3192 : // Call it done if less than half failed
3193 0 : return num_failed <= num_tried/2;
3194 : }
3195 :
3196 : // IGameDef interface
3197 : // Under envlock
3198 0 : IItemDefManager* Server::getItemDefManager()
3199 : {
3200 0 : return m_itemdef;
3201 : }
3202 0 : INodeDefManager* Server::getNodeDefManager()
3203 : {
3204 0 : return m_nodedef;
3205 : }
3206 0 : ICraftDefManager* Server::getCraftDefManager()
3207 : {
3208 0 : return m_craftdef;
3209 : }
3210 0 : ITextureSource* Server::getTextureSource()
3211 : {
3212 0 : return NULL;
3213 : }
3214 0 : IShaderSource* Server::getShaderSource()
3215 : {
3216 0 : return NULL;
3217 : }
3218 0 : scene::ISceneManager* Server::getSceneManager()
3219 : {
3220 0 : return NULL;
3221 : }
3222 :
3223 0 : u16 Server::allocateUnknownNodeId(const std::string &name)
3224 : {
3225 0 : return m_nodedef->allocateDummy(name);
3226 : }
3227 0 : ISoundManager* Server::getSoundManager()
3228 : {
3229 0 : return &dummySoundManager;
3230 : }
3231 0 : MtEventManager* Server::getEventManager()
3232 : {
3233 0 : return m_event;
3234 : }
3235 :
3236 0 : IWritableItemDefManager* Server::getWritableItemDefManager()
3237 : {
3238 0 : return m_itemdef;
3239 : }
3240 0 : IWritableNodeDefManager* Server::getWritableNodeDefManager()
3241 : {
3242 0 : return m_nodedef;
3243 : }
3244 0 : IWritableCraftDefManager* Server::getWritableCraftDefManager()
3245 : {
3246 0 : return m_craftdef;
3247 : }
3248 :
3249 0 : const ModSpec* Server::getModSpec(const std::string &modname) const
3250 : {
3251 0 : for(std::vector<ModSpec>::const_iterator i = m_mods.begin();
3252 0 : i != m_mods.end(); i++){
3253 0 : const ModSpec &mod = *i;
3254 0 : if(mod.name == modname)
3255 0 : return &mod;
3256 : }
3257 0 : return NULL;
3258 : }
3259 0 : void Server::getModNames(std::vector<std::string> &modlist)
3260 : {
3261 0 : for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++) {
3262 0 : modlist.push_back(i->name);
3263 : }
3264 0 : }
3265 4 : std::string Server::getBuiltinLuaPath()
3266 : {
3267 4 : return porting::path_share + DIR_DELIM + "builtin";
3268 : }
3269 :
3270 0 : v3f Server::findSpawnPos()
3271 : {
3272 0 : ServerMap &map = m_env->getServerMap();
3273 0 : v3f nodeposf;
3274 0 : if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3275 0 : return nodeposf * BS;
3276 : }
3277 :
3278 : // Default position is static_spawnpoint
3279 : // We will return it if we don't found a good place
3280 0 : v3s16 nodepos(nodeposf.X, nodeposf.Y, nodeposf.Z);
3281 :
3282 0 : s16 water_level = map.getWaterLevel();
3283 :
3284 0 : bool is_good = false;
3285 :
3286 : // Try to find a good place a few times
3287 0 : for(s32 i = 0; i < 1000 && !is_good; i++) {
3288 0 : s32 range = 1 + i;
3289 : // We're going to try to throw the player to this position
3290 : v2s16 nodepos2d = v2s16(
3291 0 : -range + (myrand() % (range * 2)),
3292 0 : -range + (myrand() % (range * 2)));
3293 :
3294 : // Get ground height at point
3295 0 : s16 groundheight = map.findGroundLevel(nodepos2d);
3296 0 : if (groundheight <= water_level) // Don't go underwater
3297 0 : continue;
3298 0 : if (groundheight > water_level + 6) // Don't go to high places
3299 0 : continue;
3300 :
3301 0 : nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
3302 :
3303 0 : s32 air_count = 0;
3304 0 : for (s32 i = 0; i < 10; i++) {
3305 0 : v3s16 blockpos = getNodeBlockPos(nodepos);
3306 0 : map.emergeBlock(blockpos, true);
3307 0 : content_t c = map.getNodeNoEx(nodepos).getContent();
3308 0 : if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3309 0 : air_count++;
3310 0 : if (air_count >= 2){
3311 0 : is_good = true;
3312 0 : break;
3313 : }
3314 : }
3315 0 : nodepos.Y++;
3316 : }
3317 : }
3318 :
3319 0 : return intToFloat(nodepos, BS);
3320 : }
3321 :
3322 0 : PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
3323 : {
3324 0 : bool newplayer = false;
3325 :
3326 : /*
3327 : Try to get an existing player
3328 : */
3329 0 : RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3330 :
3331 : // If player is already connected, cancel
3332 0 : if(player != NULL && player->peer_id != 0)
3333 : {
3334 0 : infostream<<"emergePlayer(): Player already connected"<<std::endl;
3335 0 : return NULL;
3336 : }
3337 :
3338 : /*
3339 : If player with the wanted peer_id already exists, cancel.
3340 : */
3341 0 : if(m_env->getPlayer(peer_id) != NULL)
3342 : {
3343 : infostream<<"emergePlayer(): Player with wrong name but same"
3344 0 : " peer_id already exists"<<std::endl;
3345 0 : return NULL;
3346 : }
3347 :
3348 : // Load player if it isn't already loaded
3349 0 : if (!player) {
3350 0 : player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3351 : }
3352 :
3353 : // Create player if it doesn't exist
3354 0 : if (!player) {
3355 0 : newplayer = true;
3356 0 : player = new RemotePlayer(this, name);
3357 : // Set player position
3358 0 : infostream<<"Server: Finding spawn place for player \""
3359 0 : <<name<<"\""<<std::endl;
3360 0 : v3f pos = findSpawnPos();
3361 0 : player->setPosition(pos);
3362 :
3363 : // Make sure the player is saved
3364 0 : player->setModified(true);
3365 :
3366 : // Add player to environment
3367 0 : m_env->addPlayer(player);
3368 : }
3369 :
3370 : // Create a new player active object
3371 : PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3372 0 : getPlayerEffectivePrivs(player->getName()),
3373 0 : isSingleplayer());
3374 :
3375 : /* Clean up old HUD elements from previous sessions */
3376 0 : player->clearHud();
3377 :
3378 : /* Add object to environment */
3379 0 : m_env->addActiveObject(playersao);
3380 :
3381 : /* Run scripts */
3382 0 : if (newplayer) {
3383 0 : m_script->on_newplayer(playersao);
3384 : }
3385 :
3386 0 : return playersao;
3387 : }
3388 :
3389 0 : void dedicated_server_loop(Server &server, bool &kill)
3390 : {
3391 0 : DSTACK(__FUNCTION_NAME);
3392 :
3393 0 : verbosestream<<"dedicated_server_loop()"<<std::endl;
3394 :
3395 0 : IntervalLimiter m_profiler_interval;
3396 :
3397 0 : for(;;)
3398 : {
3399 0 : float steplen = g_settings->getFloat("dedicated_server_step");
3400 : // This is kind of a hack but can be done like this
3401 : // because server.step() is very light
3402 : {
3403 0 : ScopeProfiler sp(g_profiler, "dedicated server sleep");
3404 0 : sleep_ms((int)(steplen*1000.0));
3405 : }
3406 0 : server.step(steplen);
3407 :
3408 0 : if(server.getShutdownRequested() || kill)
3409 : {
3410 0 : infostream<<"Dedicated server quitting"<<std::endl;
3411 : #if USE_CURL
3412 0 : if(g_settings->getBool("server_announce"))
3413 0 : ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3414 : #endif
3415 0 : break;
3416 : }
3417 :
3418 : /*
3419 : Profiler
3420 : */
3421 : float profiler_print_interval =
3422 0 : g_settings->getFloat("profiler_print_interval");
3423 0 : if(profiler_print_interval != 0)
3424 : {
3425 0 : if(m_profiler_interval.step(steplen, profiler_print_interval))
3426 : {
3427 0 : infostream<<"Profiler:"<<std::endl;
3428 0 : g_profiler->print(infostream);
3429 0 : g_profiler->clear();
3430 : }
3431 : }
3432 : }
3433 3 : }
|