Line data Source code
1 : /*
2 : Minetest
3 : Copyright (C) 2010-2014 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 <sstream>
21 :
22 : #include "clientiface.h"
23 : #include "util/numeric.h"
24 : #include "util/mathconstants.h"
25 : #include "player.h"
26 : #include "settings.h"
27 : #include "mapblock.h"
28 : #include "network/connection.h"
29 : #include "environment.h"
30 : #include "map.h"
31 : #include "emerge.h"
32 : #include "serverobject.h" // TODO this is used for cleanup of only
33 : #include "log.h"
34 : #include "util/srp.h"
35 :
36 : const char *ClientInterface::statenames[] = {
37 : "Invalid",
38 : "Disconnecting",
39 : "Denied",
40 : "Created",
41 : "InitSent",
42 : "InitDone",
43 : "DefinitionsSent",
44 : "Active"
45 : };
46 :
47 :
48 :
49 0 : std::string ClientInterface::state2Name(ClientState state)
50 : {
51 0 : return statenames[state];
52 : }
53 :
54 0 : void RemoteClient::ResendBlockIfOnWire(v3s16 p)
55 : {
56 : // if this block is on wire, mark it for sending again as soon as possible
57 0 : if (m_blocks_sending.find(p) != m_blocks_sending.end()) {
58 0 : SetBlockNotSent(p);
59 : }
60 0 : }
61 :
62 0 : void RemoteClient::GetNextBlocks (
63 : ServerEnvironment *env,
64 : EmergeManager * emerge,
65 : float dtime,
66 : std::vector<PrioritySortedBlockTransfer> &dest)
67 : {
68 0 : DSTACK(__FUNCTION_NAME);
69 :
70 :
71 : // Increment timers
72 0 : m_nothing_to_send_pause_timer -= dtime;
73 0 : m_nearest_unsent_reset_timer += dtime;
74 :
75 0 : if(m_nothing_to_send_pause_timer >= 0)
76 0 : return;
77 :
78 0 : Player *player = env->getPlayer(peer_id);
79 : // This can happen sometimes; clients and players are not in perfect sync.
80 0 : if(player == NULL)
81 0 : return;
82 :
83 : // Won't send anything if already sending
84 0 : if(m_blocks_sending.size() >= g_settings->getU16
85 0 : ("max_simultaneous_block_sends_per_client"))
86 : {
87 : //infostream<<"Not sending any blocks, Queue full."<<std::endl;
88 0 : return;
89 : }
90 :
91 0 : v3f playerpos = player->getPosition();
92 0 : v3f playerspeed = player->getSpeed();
93 0 : v3f playerspeeddir(0,0,0);
94 0 : if(playerspeed.getLength() > 1.0*BS)
95 0 : playerspeeddir = playerspeed / playerspeed.getLength();
96 : // Predict to next block
97 0 : v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
98 :
99 0 : v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
100 :
101 0 : v3s16 center = getNodeBlockPos(center_nodepos);
102 :
103 : // Camera position and direction
104 0 : v3f camera_pos = player->getEyePosition();
105 0 : v3f camera_dir = v3f(0,0,1);
106 0 : camera_dir.rotateYZBy(player->getPitch());
107 0 : camera_dir.rotateXZBy(player->getYaw());
108 :
109 : /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
110 : <<camera_dir.Z<<")"<<std::endl;*/
111 :
112 : /*
113 : Get the starting value of the block finder radius.
114 : */
115 :
116 0 : if(m_last_center != center)
117 : {
118 0 : m_nearest_unsent_d = 0;
119 0 : m_last_center = center;
120 : }
121 :
122 : /*infostream<<"m_nearest_unsent_reset_timer="
123 : <<m_nearest_unsent_reset_timer<<std::endl;*/
124 :
125 : // Reset periodically to workaround for some bugs or stuff
126 0 : if(m_nearest_unsent_reset_timer > 20.0)
127 : {
128 0 : m_nearest_unsent_reset_timer = 0;
129 0 : m_nearest_unsent_d = 0;
130 : //infostream<<"Resetting m_nearest_unsent_d for "
131 : // <<server->getPlayerName(peer_id)<<std::endl;
132 : }
133 :
134 : //s16 last_nearest_unsent_d = m_nearest_unsent_d;
135 0 : s16 d_start = m_nearest_unsent_d;
136 :
137 : //infostream<<"d_start="<<d_start<<std::endl;
138 :
139 : u16 max_simul_sends_setting = g_settings->getU16
140 0 : ("max_simultaneous_block_sends_per_client");
141 0 : u16 max_simul_sends_usually = max_simul_sends_setting;
142 :
143 : /*
144 : Check the time from last addNode/removeNode.
145 :
146 : Decrease send rate if player is building stuff.
147 : */
148 0 : m_time_from_building += dtime;
149 0 : if(m_time_from_building < g_settings->getFloat(
150 : "full_block_send_enable_min_time_from_building"))
151 : {
152 : max_simul_sends_usually
153 0 : = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
154 : }
155 :
156 : /*
157 : Number of blocks sending + number of blocks selected for sending
158 : */
159 0 : u32 num_blocks_selected = m_blocks_sending.size();
160 :
161 : /*
162 : next time d will be continued from the d from which the nearest
163 : unsent block was found this time.
164 :
165 : This is because not necessarily any of the blocks found this
166 : time are actually sent.
167 : */
168 0 : s32 new_nearest_unsent_d = -1;
169 :
170 0 : const s16 full_d_max = g_settings->getS16("max_block_send_distance");
171 0 : s16 d_max = full_d_max;
172 0 : s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
173 :
174 : // Don't loop very much at a time
175 0 : s16 max_d_increment_at_time = 2;
176 0 : if(d_max > d_start + max_d_increment_at_time)
177 0 : d_max = d_start + max_d_increment_at_time;
178 :
179 0 : s32 nearest_emerged_d = -1;
180 0 : s32 nearest_emergefull_d = -1;
181 0 : s32 nearest_sent_d = -1;
182 : //bool queue_is_full = false;
183 :
184 : s16 d;
185 0 : for(d = d_start; d <= d_max; d++) {
186 : /*
187 : Get the border/face dot coordinates of a "d-radiused"
188 : box
189 : */
190 0 : std::vector<v3s16> list = FacePositionCache::getFacePositions(d);
191 :
192 0 : std::vector<v3s16>::iterator li;
193 0 : for(li = list.begin(); li != list.end(); ++li) {
194 0 : v3s16 p = *li + center;
195 :
196 : /*
197 : Send throttling
198 : - Don't allow too many simultaneous transfers
199 : - EXCEPT when the blocks are very close
200 :
201 : Also, don't send blocks that are already flying.
202 : */
203 :
204 : // Start with the usual maximum
205 0 : u16 max_simul_dynamic = max_simul_sends_usually;
206 :
207 : // If block is very close, allow full maximum
208 0 : if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
209 0 : max_simul_dynamic = max_simul_sends_setting;
210 :
211 : // Don't select too many blocks for sending
212 0 : if(num_blocks_selected >= max_simul_dynamic)
213 : {
214 : //queue_is_full = true;
215 0 : goto queue_full_break;
216 : }
217 :
218 : // Don't send blocks that are currently being transferred
219 0 : if(m_blocks_sending.find(p) != m_blocks_sending.end())
220 0 : continue;
221 :
222 : /*
223 : Do not go over-limit
224 : */
225 0 : if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
226 0 : || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
227 0 : || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
228 0 : || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
229 0 : || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
230 0 : || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
231 0 : continue;
232 :
233 : // If this is true, inexistent block will be made from scratch
234 0 : bool generate = d <= d_max_gen;
235 :
236 : {
237 : /*// Limit the generating area vertically to 2/3
238 : if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
239 : generate = false;*/
240 :
241 : // Limit the send area vertically to 1/2
242 0 : if(abs(p.Y - center.Y) > full_d_max / 2)
243 0 : continue;
244 : }
245 :
246 : /*
247 : Don't generate or send if not in sight
248 : FIXME This only works if the client uses a small enough
249 : FOV setting. The default of 72 degrees is fine.
250 : */
251 :
252 0 : float camera_fov = (72.0*M_PI/180) * 4./3.;
253 0 : if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
254 : {
255 0 : continue;
256 : }
257 :
258 : /*
259 : Don't send already sent blocks
260 : */
261 : {
262 0 : if(m_blocks_sent.find(p) != m_blocks_sent.end())
263 : {
264 0 : continue;
265 : }
266 : }
267 :
268 : /*
269 : Check if map has this block
270 : */
271 0 : MapBlock *block = env->getMap().getBlockNoCreateNoEx(p);
272 :
273 0 : bool surely_not_found_on_disk = false;
274 0 : bool block_is_invalid = false;
275 0 : if(block != NULL)
276 : {
277 : // Reset usage timer, this block will be of use in the future.
278 0 : block->resetUsageTimer();
279 :
280 : // Block is dummy if data doesn't exist.
281 : // It means it has been not found from disk and not generated
282 0 : if(block->isDummy())
283 : {
284 0 : surely_not_found_on_disk = true;
285 : }
286 :
287 : // Block is valid if lighting is up-to-date and data exists
288 0 : if(block->isValid() == false)
289 : {
290 0 : block_is_invalid = true;
291 : }
292 :
293 0 : if(block->isGenerated() == false)
294 0 : block_is_invalid = true;
295 :
296 : /*
297 : If block is not close, don't send it unless it is near
298 : ground level.
299 :
300 : Block is near ground level if night-time mesh
301 : differs from day-time mesh.
302 : */
303 0 : if(d >= 4)
304 : {
305 0 : if(block->getDayNightDiff() == false)
306 0 : continue;
307 : }
308 : }
309 :
310 : /*
311 : If block has been marked to not exist on disk (dummy)
312 : and generating new ones is not wanted, skip block.
313 : */
314 0 : if(generate == false && surely_not_found_on_disk == true)
315 : {
316 : // get next one.
317 0 : continue;
318 : }
319 :
320 : /*
321 : Add inexistent block to emerge queue.
322 : */
323 0 : if(block == NULL || surely_not_found_on_disk || block_is_invalid)
324 : {
325 0 : if (emerge->enqueueBlockEmerge(peer_id, p, generate)) {
326 0 : if (nearest_emerged_d == -1)
327 0 : nearest_emerged_d = d;
328 : } else {
329 0 : if (nearest_emergefull_d == -1)
330 0 : nearest_emergefull_d = d;
331 0 : goto queue_full_break;
332 : }
333 :
334 : // get next one.
335 0 : continue;
336 : }
337 :
338 0 : if(nearest_sent_d == -1)
339 0 : nearest_sent_d = d;
340 :
341 : /*
342 : Add block to send queue
343 : */
344 0 : PrioritySortedBlockTransfer q((float)d, p, peer_id);
345 :
346 0 : dest.push_back(q);
347 :
348 0 : num_blocks_selected += 1;
349 : }
350 : }
351 : queue_full_break:
352 :
353 : // If nothing was found for sending and nothing was queued for
354 : // emerging, continue next time browsing from here
355 0 : if(nearest_emerged_d != -1){
356 0 : new_nearest_unsent_d = nearest_emerged_d;
357 0 : } else if(nearest_emergefull_d != -1){
358 0 : new_nearest_unsent_d = nearest_emergefull_d;
359 : } else {
360 0 : if(d > g_settings->getS16("max_block_send_distance")){
361 0 : new_nearest_unsent_d = 0;
362 0 : m_nothing_to_send_pause_timer = 2.0;
363 : } else {
364 0 : if(nearest_sent_d != -1)
365 0 : new_nearest_unsent_d = nearest_sent_d;
366 : else
367 0 : new_nearest_unsent_d = d;
368 : }
369 : }
370 :
371 0 : if(new_nearest_unsent_d != -1)
372 0 : m_nearest_unsent_d = new_nearest_unsent_d;
373 : }
374 :
375 0 : void RemoteClient::GotBlock(v3s16 p)
376 : {
377 0 : if(m_blocks_sending.find(p) != m_blocks_sending.end())
378 0 : m_blocks_sending.erase(p);
379 : else
380 : {
381 0 : m_excess_gotblocks++;
382 : }
383 0 : m_blocks_sent.insert(p);
384 0 : }
385 :
386 0 : void RemoteClient::SentBlock(v3s16 p)
387 : {
388 0 : if(m_blocks_sending.find(p) == m_blocks_sending.end())
389 0 : m_blocks_sending[p] = 0.0;
390 : else
391 : infostream<<"RemoteClient::SentBlock(): Sent block"
392 0 : " already in m_blocks_sending"<<std::endl;
393 0 : }
394 :
395 0 : void RemoteClient::SetBlockNotSent(v3s16 p)
396 : {
397 0 : m_nearest_unsent_d = 0;
398 :
399 0 : if(m_blocks_sending.find(p) != m_blocks_sending.end())
400 0 : m_blocks_sending.erase(p);
401 0 : if(m_blocks_sent.find(p) != m_blocks_sent.end())
402 0 : m_blocks_sent.erase(p);
403 0 : }
404 :
405 0 : void RemoteClient::SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks)
406 : {
407 0 : m_nearest_unsent_d = 0;
408 :
409 0 : for(std::map<v3s16, MapBlock*>::iterator
410 0 : i = blocks.begin();
411 0 : i != blocks.end(); ++i)
412 : {
413 0 : v3s16 p = i->first;
414 :
415 0 : if(m_blocks_sending.find(p) != m_blocks_sending.end())
416 0 : m_blocks_sending.erase(p);
417 0 : if(m_blocks_sent.find(p) != m_blocks_sent.end())
418 0 : m_blocks_sent.erase(p);
419 : }
420 0 : }
421 :
422 0 : void RemoteClient::notifyEvent(ClientStateEvent event)
423 : {
424 0 : std::ostringstream myerror;
425 0 : switch (m_state)
426 : {
427 : case CS_Invalid:
428 : //intentionally do nothing
429 0 : break;
430 : case CS_Created:
431 0 : switch (event) {
432 : case CSE_Hello:
433 0 : m_state = CS_HelloSent;
434 0 : break;
435 : case CSE_InitLegacy:
436 0 : m_state = CS_AwaitingInit2;
437 0 : break;
438 : case CSE_Disconnect:
439 0 : m_state = CS_Disconnecting;
440 0 : break;
441 : case CSE_SetDenied:
442 0 : m_state = CS_Denied;
443 0 : break;
444 : /* GotInit2 SetDefinitionsSent SetMediaSent */
445 : default:
446 0 : myerror << "Created: Invalid client state transition! " << event;
447 0 : throw ClientStateError(myerror.str());
448 : }
449 0 : break;
450 : case CS_Denied:
451 : /* don't do anything if in denied state */
452 0 : break;
453 : case CS_HelloSent:
454 0 : switch(event)
455 : {
456 : case CSE_AuthAccept:
457 0 : m_state = CS_AwaitingInit2;
458 0 : if ((chosen_mech == AUTH_MECHANISM_SRP)
459 0 : || (chosen_mech == AUTH_MECHANISM_LEGACY_PASSWORD))
460 0 : srp_verifier_delete((SRPVerifier *) auth_data);
461 0 : chosen_mech = AUTH_MECHANISM_NONE;
462 0 : break;
463 : case CSE_Disconnect:
464 0 : m_state = CS_Disconnecting;
465 0 : break;
466 : case CSE_SetDenied:
467 0 : m_state = CS_Denied;
468 0 : if ((chosen_mech == AUTH_MECHANISM_SRP)
469 0 : || (chosen_mech == AUTH_MECHANISM_LEGACY_PASSWORD))
470 0 : srp_verifier_delete((SRPVerifier *) auth_data);
471 0 : chosen_mech = AUTH_MECHANISM_NONE;
472 0 : break;
473 : default:
474 0 : myerror << "HelloSent: Invalid client state transition! " << event;
475 0 : throw ClientStateError(myerror.str());
476 : }
477 0 : break;
478 : case CS_AwaitingInit2:
479 0 : switch(event)
480 : {
481 : case CSE_GotInit2:
482 0 : confirmSerializationVersion();
483 0 : m_state = CS_InitDone;
484 0 : break;
485 : case CSE_Disconnect:
486 0 : m_state = CS_Disconnecting;
487 0 : break;
488 : case CSE_SetDenied:
489 0 : m_state = CS_Denied;
490 0 : break;
491 :
492 : /* Init SetDefinitionsSent SetMediaSent */
493 : default:
494 0 : myerror << "InitSent: Invalid client state transition! " << event;
495 0 : throw ClientStateError(myerror.str());
496 : }
497 0 : break;
498 :
499 : case CS_InitDone:
500 0 : switch(event)
501 : {
502 : case CSE_SetDefinitionsSent:
503 0 : m_state = CS_DefinitionsSent;
504 0 : break;
505 : case CSE_Disconnect:
506 0 : m_state = CS_Disconnecting;
507 0 : break;
508 : case CSE_SetDenied:
509 0 : m_state = CS_Denied;
510 0 : break;
511 :
512 : /* Init GotInit2 SetMediaSent */
513 : default:
514 0 : myerror << "InitDone: Invalid client state transition! " << event;
515 0 : throw ClientStateError(myerror.str());
516 : }
517 0 : break;
518 : case CS_DefinitionsSent:
519 0 : switch(event)
520 : {
521 : case CSE_SetClientReady:
522 0 : m_state = CS_Active;
523 0 : break;
524 : case CSE_Disconnect:
525 0 : m_state = CS_Disconnecting;
526 0 : break;
527 : case CSE_SetDenied:
528 0 : m_state = CS_Denied;
529 0 : break;
530 : /* Init GotInit2 SetDefinitionsSent */
531 : default:
532 0 : myerror << "DefinitionsSent: Invalid client state transition! " << event;
533 0 : throw ClientStateError(myerror.str());
534 : }
535 0 : break;
536 : case CS_Active:
537 0 : switch(event)
538 : {
539 : case CSE_SetDenied:
540 0 : m_state = CS_Denied;
541 0 : break;
542 : case CSE_Disconnect:
543 0 : m_state = CS_Disconnecting;
544 0 : break;
545 : case CSE_SudoSuccess:
546 0 : m_state = CS_SudoMode;
547 0 : if ((chosen_mech == AUTH_MECHANISM_SRP)
548 0 : || (chosen_mech == AUTH_MECHANISM_LEGACY_PASSWORD))
549 0 : srp_verifier_delete((SRPVerifier *) auth_data);
550 0 : chosen_mech = AUTH_MECHANISM_NONE;
551 0 : break;
552 : /* Init GotInit2 SetDefinitionsSent SetMediaSent SetDenied */
553 : default:
554 0 : myerror << "Active: Invalid client state transition! " << event;
555 0 : throw ClientStateError(myerror.str());
556 : break;
557 : }
558 0 : break;
559 : case CS_SudoMode:
560 0 : switch(event)
561 : {
562 : case CSE_SetDenied:
563 0 : m_state = CS_Denied;
564 0 : break;
565 : case CSE_Disconnect:
566 0 : m_state = CS_Disconnecting;
567 0 : break;
568 : case CSE_SudoLeave:
569 0 : m_state = CS_Active;
570 0 : break;
571 : default:
572 0 : myerror << "Active: Invalid client state transition! " << event;
573 0 : throw ClientStateError(myerror.str());
574 : break;
575 : }
576 0 : break;
577 : case CS_Disconnecting:
578 : /* we are already disconnecting */
579 0 : break;
580 : }
581 0 : }
582 :
583 0 : u32 RemoteClient::uptime()
584 : {
585 0 : return getTime(PRECISION_SECONDS) - m_connection_time;
586 : }
587 :
588 0 : ClientInterface::ClientInterface(con::Connection* con)
589 : :
590 : m_con(con),
591 : m_env(NULL),
592 0 : m_print_info_timer(0.0)
593 : {
594 :
595 0 : }
596 0 : ClientInterface::~ClientInterface()
597 : {
598 : /*
599 : Delete clients
600 : */
601 : {
602 0 : JMutexAutoLock clientslock(m_clients_mutex);
603 :
604 0 : for(std::map<u16, RemoteClient*>::iterator
605 0 : i = m_clients.begin();
606 0 : i != m_clients.end(); ++i)
607 : {
608 :
609 : // Delete client
610 0 : delete i->second;
611 : }
612 : }
613 0 : }
614 :
615 0 : std::vector<u16> ClientInterface::getClientIDs(ClientState min_state)
616 : {
617 0 : std::vector<u16> reply;
618 0 : JMutexAutoLock clientslock(m_clients_mutex);
619 :
620 0 : for(std::map<u16, RemoteClient*>::iterator
621 0 : i = m_clients.begin();
622 0 : i != m_clients.end(); ++i)
623 : {
624 0 : if (i->second->getState() >= min_state)
625 0 : reply.push_back(i->second->peer_id);
626 : }
627 :
628 0 : return reply;
629 : }
630 :
631 0 : std::vector<std::string> ClientInterface::getPlayerNames()
632 : {
633 0 : return m_clients_names;
634 : }
635 :
636 :
637 0 : void ClientInterface::step(float dtime)
638 : {
639 0 : m_print_info_timer += dtime;
640 0 : if(m_print_info_timer >= 30.0)
641 : {
642 0 : m_print_info_timer = 0.0;
643 0 : UpdatePlayerList();
644 : }
645 0 : }
646 :
647 0 : void ClientInterface::UpdatePlayerList()
648 : {
649 0 : if (m_env != NULL)
650 : {
651 0 : std::vector<u16> clients = getClientIDs();
652 0 : m_clients_names.clear();
653 :
654 :
655 0 : if(!clients.empty())
656 0 : infostream<<"Players:"<<std::endl;
657 :
658 0 : for(std::vector<u16>::iterator
659 0 : i = clients.begin();
660 0 : i != clients.end(); ++i) {
661 0 : Player *player = m_env->getPlayer(*i);
662 :
663 0 : if (player == NULL)
664 0 : continue;
665 :
666 0 : infostream << "* " << player->getName() << "\t";
667 :
668 : {
669 0 : JMutexAutoLock clientslock(m_clients_mutex);
670 0 : RemoteClient* client = lockedGetClientNoEx(*i);
671 0 : if(client != NULL)
672 0 : client->PrintInfo(infostream);
673 : }
674 :
675 0 : m_clients_names.push_back(player->getName());
676 : }
677 : }
678 0 : }
679 :
680 0 : void ClientInterface::send(u16 peer_id, u8 channelnum,
681 : NetworkPacket* pkt, bool reliable)
682 : {
683 0 : m_con->Send(peer_id, channelnum, pkt, reliable);
684 0 : }
685 :
686 0 : void ClientInterface::sendToAll(u16 channelnum,
687 : NetworkPacket* pkt, bool reliable)
688 : {
689 0 : JMutexAutoLock clientslock(m_clients_mutex);
690 0 : for(std::map<u16, RemoteClient*>::iterator
691 0 : i = m_clients.begin();
692 0 : i != m_clients.end(); ++i) {
693 0 : RemoteClient *client = i->second;
694 :
695 0 : if (client->net_proto_version != 0) {
696 0 : m_con->Send(client->peer_id, channelnum, pkt, reliable);
697 : }
698 : }
699 0 : }
700 :
701 0 : RemoteClient* ClientInterface::getClientNoEx(u16 peer_id, ClientState state_min)
702 : {
703 0 : JMutexAutoLock clientslock(m_clients_mutex);
704 0 : std::map<u16, RemoteClient*>::iterator n;
705 0 : n = m_clients.find(peer_id);
706 : // The client may not exist; clients are immediately removed if their
707 : // access is denied, and this event occurs later then.
708 0 : if(n == m_clients.end())
709 0 : return NULL;
710 :
711 0 : if (n->second->getState() >= state_min)
712 0 : return n->second;
713 : else
714 0 : return NULL;
715 : }
716 :
717 0 : RemoteClient* ClientInterface::lockedGetClientNoEx(u16 peer_id, ClientState state_min)
718 : {
719 0 : std::map<u16, RemoteClient*>::iterator n;
720 0 : n = m_clients.find(peer_id);
721 : // The client may not exist; clients are immediately removed if their
722 : // access is denied, and this event occurs later then.
723 0 : if(n == m_clients.end())
724 0 : return NULL;
725 :
726 0 : if (n->second->getState() >= state_min)
727 0 : return n->second;
728 : else
729 0 : return NULL;
730 : }
731 :
732 0 : ClientState ClientInterface::getClientState(u16 peer_id)
733 : {
734 0 : JMutexAutoLock clientslock(m_clients_mutex);
735 0 : std::map<u16, RemoteClient*>::iterator n;
736 0 : n = m_clients.find(peer_id);
737 : // The client may not exist; clients are immediately removed if their
738 : // access is denied, and this event occurs later then.
739 0 : if(n == m_clients.end())
740 0 : return CS_Invalid;
741 :
742 0 : return n->second->getState();
743 : }
744 :
745 0 : void ClientInterface::setPlayerName(u16 peer_id,std::string name)
746 : {
747 0 : JMutexAutoLock clientslock(m_clients_mutex);
748 0 : std::map<u16, RemoteClient*>::iterator n;
749 0 : n = m_clients.find(peer_id);
750 : // The client may not exist; clients are immediately removed if their
751 : // access is denied, and this event occurs later then.
752 0 : if(n != m_clients.end())
753 0 : n->second->setName(name);
754 0 : }
755 :
756 0 : void ClientInterface::DeleteClient(u16 peer_id)
757 : {
758 0 : JMutexAutoLock conlock(m_clients_mutex);
759 :
760 : // Error check
761 0 : std::map<u16, RemoteClient*>::iterator n;
762 0 : n = m_clients.find(peer_id);
763 : // The client may not exist; clients are immediately removed if their
764 : // access is denied, and this event occurs later then.
765 0 : if(n == m_clients.end())
766 0 : return;
767 :
768 : /*
769 : Mark objects to be not known by the client
770 : */
771 : //TODO this should be done by client destructor!!!
772 0 : RemoteClient *client = n->second;
773 : // Handle objects
774 0 : for(std::set<u16>::iterator
775 0 : i = client->m_known_objects.begin();
776 0 : i != client->m_known_objects.end(); ++i)
777 : {
778 : // Get object
779 0 : u16 id = *i;
780 0 : ServerActiveObject* obj = m_env->getActiveObject(id);
781 :
782 0 : if(obj && obj->m_known_by_count > 0)
783 0 : obj->m_known_by_count--;
784 : }
785 :
786 : // Delete client
787 0 : delete m_clients[peer_id];
788 0 : m_clients.erase(peer_id);
789 : }
790 :
791 0 : void ClientInterface::CreateClient(u16 peer_id)
792 : {
793 0 : JMutexAutoLock conlock(m_clients_mutex);
794 :
795 : // Error check
796 0 : std::map<u16, RemoteClient*>::iterator n;
797 0 : n = m_clients.find(peer_id);
798 : // The client shouldn't already exist
799 0 : if(n != m_clients.end()) return;
800 :
801 : // Create client
802 0 : RemoteClient *client = new RemoteClient();
803 0 : client->peer_id = peer_id;
804 0 : m_clients[client->peer_id] = client;
805 : }
806 :
807 0 : void ClientInterface::event(u16 peer_id, ClientStateEvent event)
808 : {
809 : {
810 0 : JMutexAutoLock clientlock(m_clients_mutex);
811 :
812 : // Error check
813 0 : std::map<u16, RemoteClient*>::iterator n;
814 0 : n = m_clients.find(peer_id);
815 :
816 : // No client to deliver event
817 0 : if (n == m_clients.end())
818 0 : return;
819 0 : n->second->notifyEvent(event);
820 : }
821 :
822 0 : if ((event == CSE_SetClientReady) ||
823 0 : (event == CSE_Disconnect) ||
824 : (event == CSE_SetDenied))
825 : {
826 0 : UpdatePlayerList();
827 : }
828 : }
829 :
830 0 : u16 ClientInterface::getProtocolVersion(u16 peer_id)
831 : {
832 0 : JMutexAutoLock conlock(m_clients_mutex);
833 :
834 : // Error check
835 0 : std::map<u16, RemoteClient*>::iterator n;
836 0 : n = m_clients.find(peer_id);
837 :
838 : // No client to get version
839 0 : if (n == m_clients.end())
840 0 : return 0;
841 :
842 0 : return n->second->net_proto_version;
843 : }
844 :
845 0 : void ClientInterface::setClientVersion(u16 peer_id, u8 major, u8 minor, u8 patch, std::string full)
846 : {
847 0 : JMutexAutoLock conlock(m_clients_mutex);
848 :
849 : // Error check
850 0 : std::map<u16, RemoteClient*>::iterator n;
851 0 : n = m_clients.find(peer_id);
852 :
853 : // No client to set versions
854 0 : if (n == m_clients.end())
855 0 : return;
856 :
857 0 : n->second->setVersionInfo(major,minor,patch,full);
858 3 : }
|