Merge branch 'lua_versions' into main/rendor-staging
[ryzomcore.git] / snowballs2 / server / frontend / src / main.cpp
blob4d9d94ae9666374439d5229e6602c407d5def3ca
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif // HAVE_CONFIG_H
24 #ifndef SNOWBALLS_CONFIG
25 #define SNOWBALLS_CONFIG ""
26 #endif // SNOWBALLS_CONFIG
28 #ifndef SNOWBALLS_LOGS
29 #define SNOWBALLS_LOGS ""
30 #endif // SNOWBALLS_LOGS
32 // This include is mandatory to use NeL. It include NeL types.
33 #include <nel/misc/types_nl.h>
35 #include <nel/misc/vector.h>
37 // We're using the NeL Service framework and layer 5
38 #include <nel/net/service.h>
39 #include <nel/net/login_server.h>
41 #include <map>
42 #include <utility>
44 #ifdef NL_OS_WINDOWS
45 #include <Windows.h>
46 #endif
48 using namespace NLMISC;
49 using namespace NLNET;
50 using namespace std;
52 CCallbackServer *Clients = 0;
54 //TSockId clientfrom;
57 * Keep a list of the players connected to that Frontend. Only map Id
58 * to a Connection
61 struct CPlayer
63 enum PlayerState
65 IDENTIFYING,
66 ONLINE
68 CPlayer(uint32 Id, TSockId Con) : id(Id), con(Con), State(IDENTIFYING) { }
69 uint32 id;
70 TSockId con;
71 PlayerState State;
74 typedef map<uint32, CPlayer> _pmap;
76 _pmap localPlayers;
79 /****************************************************************************
80 * cbChatClient
82 * Receive chat messages from a client and send it to the Chat Service.
83 ****************************************************************************/
84 void cbChatClient ( CMessage& msgin, TSockId from, CCallbackNetBase& clientcb )
86 string message;
88 // Input from the client is stored.
89 msgin.serial (message);
91 // Prepare the message to send to the CHAT service
92 CMessage msgout ("CHAT");
93 msgout.serial (message);
96 * The incomming message from the client is sent to the CHAT service
97 * under the "CHAT" identification.
99 CUnifiedNetwork::getInstance ()->send( "CHAT", msgout );
101 nldebug("SB: Received CHAT message \"%s\" from client \"%s\"", message.c_str(), clientcb.hostAddress(from).asString().c_str());
105 /****************************************************************************
106 * cdChatService
108 * Receive chat messages from the Chat Service to send it to all the clients.
109 ****************************************************************************/
110 void cbChatService (CMessage &msgin, const std::string &serviceName, TServiceId sid)
112 string message;
114 // Input: process the reply of the chat service
115 msgin.serial (message);
117 // Output: send the reply to the client
118 CMessage msgout ("CHAT");
119 msgout.serial (message);
121 // Send the message to all connected clients
122 Clients->send (msgout, InvalidSockId);
124 nldebug( "SB: Sent chat message \"%s\" to all clients", message.c_str());
128 /****************************************************************************
129 * cbPosClient
131 * Receive position messages from a client and send it to the Position Service.
132 ****************************************************************************/
133 void cbPosClient ( CMessage& msgin, TSockId from, CCallbackNetBase& clientcb )
135 uint32 id;
136 CVector pos;
137 float angle;
138 uint32 state;
140 // Input from the client is stored.
141 msgin.serial( id );
142 msgin.serial( pos );
143 msgin.serial( angle );
144 msgin.serial( state );
146 // Prepare the message to send to the Position service
147 CMessage msgout ("ENTITY_POS");
148 msgout.serial( id );
149 msgout.serial( pos );
150 msgout.serial( angle );
151 msgout.serial( state );
154 * The incomming message from the client is sent to the Position service
155 * under the "POS" identification.
157 CUnifiedNetwork::getInstance ()->send( "POS", msgout );
159 //nldebug( "SB: Received ENTITY_POS from the client");
163 /****************************************************************************
164 * cbPosService
166 * Receive position messages from the Position Service to send it to all the
167 * clients.
168 ****************************************************************************/
169 void cbPosService (CMessage &msgin, const std::string &serviceName, TServiceId sid)
171 uint32 id;
172 CVector pos;
173 float angle;
174 uint32 state;
176 // Input: process the reply of the position service
177 msgin.serial( id );
178 msgin.serial( pos );
179 msgin.serial( angle );
180 msgin.serial( state );
182 // Output: send the reply to the client
183 CMessage msgout( "ENTITY_POS" );
184 msgout.serial( id );
185 msgout.serial( pos );
186 msgout.serial( angle );
187 msgout.serial( state );
189 // Send the message to all connected clients
190 Clients->send(msgout, InvalidSockId);
192 //nldebug( "SB: Sent ENTITY_POS message to all the connected clients");
195 /****************************************************************************
196 * cbTeleportService
198 * Test
199 ****************************************************************************/
200 void cbTeleportService (CMessage &msgin, const std::string &serviceName, TServiceId sid)
202 uint32 id;
203 CVector position;
204 msgin.serial(id);
205 msgin.serial(position);
206 CMessage msgout("ENTITY_TP");
207 msgout.serial(id);
208 msgout.serial(position);
209 Clients->send(msgout, InvalidSockId);
210 nldebug("SB: Sent ENTITY_TP message to all the connected clients");
214 /****************************************************************************
215 * cbAddClient
217 * Receive an ADD_ENTITY message from a client and send it to the Position
218 * Service.
219 ****************************************************************************/
220 void cbAddClient ( CMessage& msgin, TSockId from, CCallbackNetBase& clientcb )
222 uint32 id;
223 string name;
224 uint8 race;
225 CVector start(1840.0f + ((float)(rand() % 100) / 10.0f), -970.0f + ((float)(rand() % 100) / 10.0f), -23.0f); // kaetemi_todo: from config
227 // Input from the client is stored.
228 msgin.serial(id);
229 msgin.serial(name);
230 msgin.serial(race);
233 if(from->appId() != 0)
235 CPlayer *p = (CPlayer *)(void *)from->appId();
236 if(id == p->id)
237 p->State = CPlayer::ONLINE;
240 // Prepare the message to send to the Position service
241 CMessage msgout("ADD_ENTITY");
242 msgout.serial(id);
243 msgout.serial(name);
244 msgout.serial(race);
245 msgout.serial(start);
248 * The incoming message from the client is sent to the Position service
249 * under the "POS" identification.
251 CUnifiedNetwork::getInstance()->send("POS", msgout);
253 nldebug("SB: Received ADD_ENTITY from the client");
255 // kaetemi_todo: from config
256 msgout = CMessage("CHAT");
257 std::string chat_msg(std::string(">>>> Welcome to Snowballs, ") + name + std::string("!"));
258 msgout.serial(chat_msg);
259 Clients->send(msgout, from);
263 /****************************************************************************
264 * cdAddService
266 * Receive an ADD_ENTITY messages from the Position Service to send it to all
267 * the clients.
268 ****************************************************************************/
269 void cbAddService (CMessage &msgin, const std::string &serviceName, TServiceId sid)
271 bool all;
272 uint32 to;
273 uint32 id;
274 string name;
275 uint8 race;
276 CVector start;
278 // Input: process the reply of the position service
279 msgin.serial( all );
280 msgin.serial( to );
281 msgin.serial( id );
282 msgin.serial( name );
283 msgin.serial( race );
284 msgin.serial( start );
286 // Output: prepare the reply to the clients
287 CMessage msgout( "ADD_ENTITY" );
288 msgout.serial( id );
289 msgout.serial( name );
290 msgout.serial( race );
291 msgout.serial( start );
293 if ( all == true )
295 // Send the message to all connected clients
296 Clients->send(msgout, InvalidSockId );
298 nldebug( "SB: Sent ADD_ENTITY message to all the connected clients");
300 else
302 // Send the message about a former connected client to the new client
303 _pmap::iterator ItPlayer;
304 ItPlayer = localPlayers.find(to);
305 if ( ItPlayer == localPlayers.end() )
307 nlwarning( "New player id %u not found !", to );
309 else
311 TSockId conToClient = ((*ItPlayer).second).con;
312 Clients->send( msgout, conToClient );
314 nldebug( "SB: Sent ADD_ENTITY about all the connected clients to the new client.");
321 /****************************************************************************
322 * cbRemoveClient
324 * Receive an REMOVE_ENTITY message from a client and send it to the Position
325 * Service.
326 ****************************************************************************/
327 void cbRemoveClient ( CMessage& msgin, TSockId from, CCallbackNetBase& clientcb )
329 uint32 id;
331 // Input from the client is stored.
332 msgin.serial( id );
334 // Prepare the message to send to the Position service
335 CMessage msgout( "REMOVE_ENTITY" );
336 msgout.serial( id );
339 * The incomming message from the client is sent to the Position service
340 * under the "POS" identification.
342 CUnifiedNetwork::getInstance ()->send( "POS", msgout );
344 nldebug( "SB: Received REMOVE_ENTITY from the client");
348 /****************************************************************************
349 * cdRemoveService
351 * Receive an REMOVE_ENTITY messages from the Position Service to send it to all
352 * the clients.
353 ****************************************************************************/
354 void cbRemoveService (CMessage &msgin, const std::string &serviceName, TServiceId sid)
356 uint32 id;
358 // Input: process the reply of the position service
359 msgin.serial( id );
361 // Output: send the reply to the client
362 CMessage msgout( "REMOVE_ENTITY" );
363 msgout.serial( id );
365 // Send the message to all connected clients
366 Clients->send( msgout, InvalidSockId );
368 nldebug( "SB: Sent REMOVE_ENTITY message to all the connected clients");
372 /****************************************************************************
373 * cdSnowballService
375 * Receive an SNOWBALL messages from the Position Service to send it to all
376 * the clients.
377 ****************************************************************************/
378 void cbSnowballService (CMessage &msgin, const std::string &serviceName, TServiceId sid)
380 uint32 id,
381 playerId;
382 CVector start,
383 target;
384 float speed,
385 explosionRadius;
387 // Input: process the reply of the position service
388 msgin.serial( id );
389 msgin.serial( playerId );
390 msgin.serial( start );
391 msgin.serial( target );
392 msgin.serial( speed );
393 msgin.serial( explosionRadius );
395 // Output: send the reply to the client
396 CMessage msgout( "SNOWBALL" );
397 msgout.serial( id );
398 msgout.serial( playerId );
399 msgout.serial( start );
400 msgout.serial( target );
401 msgout.serial( speed );
402 msgout.serial( explosionRadius );
404 // Send the message to all connected clients
405 Clients->send( msgout, InvalidSockId );
407 nldebug( "SB: Sent SNOWBALL message to all the connected clients");
411 /****************************************************************************
412 * cbSnowballClient
414 * Receive an SNOWBALL message from a client and send it to the Position
415 * Service.
416 ****************************************************************************/
417 void cbSnowballClient ( CMessage& msgin, TSockId from, CCallbackNetBase& clientcb )
419 uint32 playerId;
420 CVector start,
421 target;
422 float speed,
423 explosionRadius;
425 // Input from the client is stored.
426 msgin.serial( playerId );
427 msgin.serial( start );
428 msgin.serial( target );
429 msgin.serial( speed );
430 msgin.serial( explosionRadius );
432 // Prepare the message to send to the Position service
433 CMessage msgout( "SNOWBALL" );
434 msgout.serial( playerId );
435 msgout.serial( start );
436 msgout.serial( target );
437 msgout.serial( speed );
438 msgout.serial( explosionRadius );
441 * The incomming message from the client is sent to the Position service
442 * under the "POS" identification.
444 CUnifiedNetwork::getInstance ()->send( "POS", msgout );
446 nldebug( "SB: Received SNOWBALL from the client");
450 /****************************************************************************
451 * cdHitService
453 * Receive an HIT messages from the Position Service to send it to all
454 * the clients.
455 ****************************************************************************/
456 void cbHitService (CMessage &msgin, const std::string &serviceName, TServiceId sid)
458 uint32 snowballId,
459 victimId;
460 bool direct;
462 // Input: process the reply of the position service
463 msgin.serial( snowballId );
464 msgin.serial( victimId );
465 msgin.serial( direct );
467 // Output: send the reply to the client
468 CMessage msgout( "HIT" );
469 msgout.serial( snowballId );
470 msgout.serial( victimId );
471 msgout.serial( direct );
473 // Send the message to all connected clients
474 Clients->send( msgout, InvalidSockId);
476 nldebug( "SB: Sent HIT message to all the connected clients");
481 * Contains all callbacks from client
483 TCallbackItem ClientCallbackArray[] =
485 { "ADD_ENTITY", cbAddClient },
486 { "ENTITY_POS", cbPosClient },
487 { "CHAT", cbChatClient },
488 { "REMOVE_ENTITY", cbRemoveClient },
489 { "SNOWBALL", cbSnowballClient },
494 * Contains *all* callbacks from the shard
496 TUnifiedCallbackItem CallbackArray[] =
498 { "CHAT", cbChatService },
499 { "ADD_ENTITY", cbAddService },
500 { "ENTITY_POS", cbPosService },
501 { "ENTITY_TP", cbTeleportService },
502 { "REMOVE_ENTITY", cbRemoveService },
503 { "SNOWBALL", cbSnowballService },
504 { "HIT", cbHitService },
508 /****************************************************************************
509 * Connection callback for the Chat service
510 ****************************************************************************/
511 void onReconnectChat (const std::string &serviceName, TServiceId sid, void *arg)
513 nldebug( "SB: Chat Service reconnected" );
517 /****************************************************************************
518 * Disconnection callback for the Chat service
519 ****************************************************************************/
520 void onDisconnectChat (const std::string &serviceName, TServiceId sid, void *arg)
522 /* Note: messages already forwarded should get no reply, but it may occure
523 * (e.g. if the server reconnects before the forwarding of a message and
524 * the reconnection callbacks is called after that). Then onReconnectChat()
525 * may send messagess that have already been sent and the front-end may get
526 * the same message twice. This is partially handled in cbChatService.
529 nldebug( "SB: Chat Service disconnecting: messages will be delayed until reconnection" );
533 /****************************************************************************
534 * Connection callback for the Position service
535 ****************************************************************************/
536 void onReconnectPosition (const std::string &serviceName, TServiceId sid, void *arg)
538 nldebug( "SB: Position Service reconnected" );
542 /****************************************************************************
543 * Disconnection callback for the Position service
544 ****************************************************************************/
545 void onDisconnectPosition (const std::string &serviceName, TServiceId sid, void *arg)
547 /* Note: messages already forwarded should get no reply, but it may occure
548 * (e.g. if the server reconnects before the forwarding of a message and
549 * the reconnection callbacks is called after that). Then onReconnectChat()
550 * may send messagess that have already been sent and the front-end may get
551 * the same message twice. This is partially handled in cbPositionService.
554 nldebug( "SB: Position Service disconnecting: messages will be delayed until reconnection" );
558 /****************************************************************************
559 * Connection callback for a client
560 ****************************************************************************/
561 void onConnectionClient (TSockId from, const CLoginCookie &cookie)
563 uint32 id;
565 id = cookie.getUserId();
567 nlinfo( "The client with unique Id %u is connected", id );
569 // Add new client to the list of player managed by this FrontEnd
570 pair<_pmap::iterator, bool> player = localPlayers.insert( make_pair( id, CPlayer( id, from )));
572 // store the player info in appId
574 _pmap::iterator it = player.first;
575 CPlayer *p = &((*it).second);
576 from->setAppId((uint64)(uintptr_t)p);
578 // Output: send the IDENTIFICATION number to the new connected client
579 CMessage msgout( "IDENTIFICATION" );
580 msgout.serial( id );
582 // Send the message to connected client "from"
583 Clients->send( msgout, from );
585 nldebug( "SB: Sent IDENTIFICATION message to the new client");
589 /****************************************************************************
590 * Disconnection callback for a client
591 ****************************************************************************/
592 void onDisconnectClient ( TSockId from, void *arg )
594 uint32 id;
596 uintptr_t i = from->appId();
598 if(i == 0)
599 return;
601 CPlayer *p = (CPlayer *)(void *)i;
602 id = p->id;
604 nlinfo( "A client with unique Id %u has disconnected", id );
606 // tell the login system that this client is disconnected
607 CLoginServer::clientDisconnected ( id );
609 // remove the player from the local player list
610 localPlayers.erase( id );
612 // don't send remove messages for entities that haven't been created.
613 if(p->State == CPlayer::ONLINE)
615 // Output: send the REMOVE_ENTITY to the position manager.
616 CMessage msgout( "REMOVE_ENTITY" );
617 msgout.serial( id );
619 // Send the message to the position manager
620 CUnifiedNetwork::getInstance ()->send( "POS", msgout);
621 nldebug( "SB: Sent REMOVE_ENTITY message to the position manager.");
627 /****************************************************************************
628 * CFrontEndService
629 ****************************************************************************/
630 class CFrontEndService : public IService
632 public:
634 // Initialisation
635 void init()
638 // Create the server where the client must connect into
639 // In a real game, it should be an UDP server with specific protocol to manage packet lost and so on.
641 Clients = new CCallbackServer ();
642 nlassert (Clients != 0);
644 // Set the callbacks for that connection (comming from the Chat service)
645 Clients->addCallbackArray (ClientCallbackArray, sizeof(ClientCallbackArray)/sizeof(ClientCallbackArray[0]));
647 // Set the callbacks for the client disconnection of the Frontend
648 Clients->setDisconnectionCallback (onDisconnectClient, 0);
650 Clients->init (37000);
652 // Connect the frontend to the login system
653 CLoginServer::init( *Clients, onConnectionClient);
656 * Set the callback function when the Chat service reconnect to the
657 * frontend
659 CUnifiedNetwork::getInstance ()->setServiceUpCallback ("CHAT", onReconnectChat, 0);
662 * Set the callback function when the Chat service disconnect from
663 * frontend
665 CUnifiedNetwork::getInstance ()->setServiceDownCallback ("CHAT", onDisconnectChat, 0);
668 * Set the callback function when the Position service reconnect to the
669 * frontend
671 CUnifiedNetwork::getInstance ()->setServiceUpCallback ("POS", onReconnectPosition, 0);
674 * Set the callback function when the Position service disconnect from
675 * frontend
677 CUnifiedNetwork::getInstance ()->setServiceDownCallback ("POS", onDisconnectPosition, 0);
680 bool update()
682 // Manage messages from clients
683 Clients->update ();
685 // we want to continue
686 return true;
689 void release()
691 delete Clients;
692 Clients = NULL;
697 /****************************************************************************
698 * SNOWBALLS FRONTEND SERVICE MAIN Function
700 * This call create a main function for a service:
702 * - based on the "CFrontEndService" class
703 * - having the short name "FS"
704 * - having the long name "frontend_service"
705 * - listening on the port "0" (dynamically determined)
706 * - and shard callback set to "CallbackArray"
708 ****************************************************************************/
709 NLNET_SERVICE_MAIN (CFrontEndService, "FS", "frontend_service", 0, CallbackArray, SNOWBALLS_CONFIG, SNOWBALLS_LOGS)
712 /* end of file */