Merge branch 'lua_versions' into main/rendor-staging
[ryzomcore.git] / snowballs2 / server / position / src / main.cpp
bloba1ea5ceddf577631bb350348ef6f4885c31b9607
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif // HAVE_CONFIG_H
21 #ifndef SNOWBALLS_CONFIG
22 #define SNOWBALLS_CONFIG ""
23 #endif // SNOWBALLS_CONFIG
25 #ifndef SNOWBALLS_LOGS
26 #define SNOWBALLS_LOGS ""
27 #endif // SNOWBALLS_LOGS
29 // This include is mandatory to use NeL. It include NeL types.
30 #include <nel/misc/types_nl.h>
32 #include <nel/misc/vector.h>
34 #include <nel/misc/time_nl.h>
36 // We're using the NeL Service framework, and layer 5
37 #include <nel/net/service.h>
39 #include <map>
40 #include <list>
42 #include "physics.h"
44 #ifdef NL_OS_WINDOWS
45 #include <Windows.h>
46 #endif
48 using namespace NLMISC;
49 using namespace NLNET;
50 using namespace std;
53 #define PLAYER_RADIUS 1.0f
54 #define SNOWBALL_RADIUS 0.1f
55 #define START_SNOW_ID 2000000000
56 #define THROW_ANIM_OFFSET 1000
61 // Define information used for all connected players to the shard.
62 struct _player
64 _player( uint32 Id, string Name, uint8 Race, CVector Position ) :
65 id( Id ), name( Name ), race( Race ), position( Position ) { }
66 uint32 id;
67 string name;
68 uint8 race;
69 CVector position;
72 // List of all the players connected to the shard.
73 typedef map<uint32, _player> _pmap;
74 _pmap playerList;
76 // Define information used for the snowballs management
77 struct _snowball
79 _snowball( uint32 Id, uint32 Owner, CTrajectory Traj, float ExplosionRadius ) :
80 id( Id ), owner( Owner ), traj( Traj ), explosionRadius( ExplosionRadius ) { }
81 uint32 id;
82 uint32 owner;
83 CTrajectory traj;
84 float explosionRadius;
87 // List of all the games snowballs
88 list<_snowball> snoList;
93 class CCLSClient
95 private:
96 struct _entity
98 _entity() { }
99 _entity(CVector position, float radius)
100 : Position(position), Radius(radius) { }
101 CVector Position;
102 float Radius;
105 static map<uint32, _entity> adds;
106 static map<uint32, CVector> positions;
107 static map<uint32, CVector> moves;
108 static map<uint32, float> radiuses;
109 static map<uint32, uint8> removes;
110 public:
111 static void cbUpdate(CMessage &msgin, const std::string &serviceName, TServiceId sid)
113 // nldebug("Received CLS_UPDATE, %s %s", serviceName.c_str(), sid.toString().c_str());
115 for (map<uint32, _entity>::iterator it = adds.begin(); it != adds.end(); it++)
117 CMessage msgout("ADD");
118 msgout.serial((uint32 &)it->first);
119 msgout.serial(it->second.Position);
120 msgout.serial(it->second.Radius);
121 CUnifiedNetwork::getInstance()->send(sid, msgout);
123 adds.clear();
125 for (map<uint32, CVector>::iterator it = positions.begin(); it != positions.end(); it++)
127 CMessage msgout("POSITION");
128 msgout.serial((uint32 &)it->first);
129 msgout.serial((NLMISC::CVector &)it->second);
130 CUnifiedNetwork::getInstance()->send(sid, msgout);
132 positions.clear();
134 for (map<uint32, CVector>::iterator it = moves.begin(); it != moves.end(); it++)
136 CMessage msgout("MOVE");
137 msgout.serial((uint32 &)it->first);
138 msgout.serial((NLMISC::CVector &)it->second);
139 CUnifiedNetwork::getInstance()->send(sid, msgout);
141 moves.clear();
143 for (map<uint32, float>::iterator it = radiuses.begin(); it != radiuses.end(); it++)
145 CMessage msgout("RADIUS");
146 msgout.serial((uint32 &)it->first);
147 msgout.serial((float &)it->second);
148 CUnifiedNetwork::getInstance()->send(sid, msgout);
150 radiuses.clear();
152 for (map<uint32, uint8>::iterator it = removes.begin(); it != removes.end(); it++)
154 CMessage msgout("REMOVE");
155 msgout.serial((uint32 &)it->first);
156 CUnifiedNetwork::getInstance()->send(sid, msgout);
158 removes.clear();
161 static void cbPosition(CMessage &msgin, const std::string &serviceName, TServiceId sid)
166 static void addEntity(uint32 id, CVector position, float radius)
168 adds[id] = _entity(position, radius);
171 static void removeEntity(uint32 id)
173 if (positions.find(id) != positions.end()) positions.erase(id);
174 if (moves.find(id) != moves.end()) moves.erase(id);
175 if (radiuses.find(id) != radiuses.end()) radiuses.erase(id);
176 if (adds.find(id) == adds.end()) removes[id] = 1;
177 else adds.erase(id);
180 static void movePosition(uint32 id, CVector position)
182 moves[id] = position;
185 static void setPosition(uint32 id, CVector position)
187 if (moves.find(id) != moves.end()) moves.erase(id);
188 if (adds.find(id) == adds.end()) positions[id] = position;
189 else adds[id].Position = position;
192 static void setRadius(uint32 id, float radius)
194 if (adds.find(id) == adds.end()) radiuses[id] = radius;
195 else adds[id].Radius = radius;
198 static void msgRegister(TServiceId sid)
200 CMessage msgout("REGISTER");
201 CUnifiedNetwork::getInstance()->send(sid, msgout);
204 static void clear()
206 adds.clear();
207 positions.clear();
208 moves.clear();
209 radiuses.clear();
210 removes.clear();
213 map<uint32, CCLSClient::_entity> CCLSClient::adds;
214 map<uint32, CVector> CCLSClient::positions;
215 map<uint32, CVector> CCLSClient::moves;
216 map<uint32, float> CCLSClient::radiuses;
217 map<uint32, uint8> CCLSClient::removes;
219 class CCLSClientPOS : public CCLSClient
221 public:
222 static void cbPosition(CMessage &msgin, const std::string &serviceName, TServiceId sid)
224 // temp
225 uint32 id;
226 CVector position;
227 msgin.serial(id);
228 msgin.serial(position);
229 nldebug("Received CLS_POSITION, %s %s", serviceName.c_str(), sid.toString().c_str());
231 // Update position information in the player list
232 _pmap::iterator ItPlayer;
233 ItPlayer = playerList.find( id );
234 if ( ItPlayer == playerList.end() )
236 nlwarning( "Player id %u not found !", id );
238 else
240 ((*ItPlayer).second).position = position;
241 //nldebug( "SB: Player position updated" );
244 CMessage msgout("ENTITY_TP");
245 msgout.serial(id);
246 msgout.serial(position);
247 CUnifiedNetwork::getInstance()->send("FS", msgout);
250 /****************************************************************************
251 * Connection callback for the collision service
252 ****************************************************************************/
253 static void cbCollisionServiceUp(const std::string &serviceName, TServiceId sid, void *arg)
255 nldebug("SB: Collision Service UP, %s %s", serviceName.c_str(), sid.toString().c_str());
256 clear();
257 msgRegister(sid);
258 for (_pmap::iterator it = playerList.begin(); it != playerList.end(); it++)
259 addEntity(it->second.id, it->second.position, 1.0f);
269 /****************************************************************************
270 * Function: cbAddEntity
271 * Callback function called when the Position Service receive a
272 * "ADD_ENTITY" message
273 ****************************************************************************/
274 void cbAddEntity (CMessage &msgin, const std::string &serviceName, TServiceId sid)
276 bool all;
277 uint32 id;
278 string name;
279 uint8 race;
280 CVector startPoint;
282 // Extract the incomming message content from the Frontend and print it
283 msgin.serial( id );
284 msgin.serial( name );
285 msgin.serial( race );
286 msgin.serial( startPoint );
287 nldebug( "SB: Received ADD_ENTITY line." );
289 // Prepare to send back the message.
290 all = true;
291 CMessage msgout( "ADD_ENTITY" );
292 msgout.serial( all );
293 msgout.serial( id );
294 msgout.serial( id );
295 msgout.serial( name );
296 msgout.serial( race );
297 msgout.serial( startPoint );
300 * Send the message to all the connected Frontend. If we decide to send
301 * it back to the sender, that last argument should be 'from' inteed of '0'
303 CUnifiedNetwork::getInstance ()->send( "FS", msgout );
305 CCLSClientPOS::addEntity(id, startPoint, /* 10.0f, */ 1.0f);
307 nldebug( "SB: Send back ADD_ENTITY line." );
309 // Send ADD_ENTITY message about all already connected client to the new one.
310 all = false;
311 _pmap::iterator ItPlayer;
312 for (ItPlayer = playerList.begin(); ItPlayer != playerList.end(); ++ItPlayer)
314 CMessage msgout( "ADD_ENTITY" );
315 msgout.serial( all );
316 msgout.serial( id );
317 msgout.serial( ((*ItPlayer).second).id );
318 msgout.serial( ((*ItPlayer).second).name );
319 msgout.serial( ((*ItPlayer).second).race );
320 msgout.serial( ((*ItPlayer).second).position );
322 CUnifiedNetwork::getInstance ()->send( sid, msgout);
325 nldebug( "SB: Send ADD_ENTITY line about all already connected clients to the new one." );
327 // ADD the current added entity in the player list.
328 playerList.insert( make_pair( id, _player( id, name, race, startPoint ) ));
332 /****************************************************************************
333 * Function: cbPosition
334 * Callback function called when the Position Service receive a
335 * "ENTITY_POS" message
336 ****************************************************************************/
337 void cbPosition (CMessage &msgin, const std::string &serviceName, TServiceId sid)
339 uint32 id;
340 CVector pos;
341 float angle;
342 uint32 state;
344 // Extract the incomming message content from the Frontend and print it
345 msgin.serial( id );
346 msgin.serial( pos );
347 msgin.serial( angle );
348 msgin.serial( state );
349 //nldebug( "SB: Received ENTITY_POS line." );
351 // Update position information in the player list
352 _pmap::iterator ItPlayer;
353 ItPlayer = playerList.find( id );
354 if ( ItPlayer == playerList.end() )
356 nlwarning( "Player id %u not found !", id );
358 else
360 ((*ItPlayer).second).position = pos;
361 //nldebug( "SB: Player position updated" );
364 // Prepare to send back the message.
365 CMessage msgout( "ENTITY_POS" );
366 msgout.serial( id );
367 msgout.serial( pos );
368 msgout.serial( angle );
369 msgout.serial( state );
372 * Send the message to all the connected Frontend.
374 CUnifiedNetwork::getInstance ()->send( "FS", msgout );
376 CCLSClientPOS::movePosition(id, pos);
378 //nldebug( "SB: Send back ENTITY_POS line." );
382 /****************************************************************************
383 * Function: cbRemoveEntity
384 * Callback function called when the Position Service receive a
385 * "REMOVE_ENTITY" message
386 ****************************************************************************/
387 void cbRemoveEntity (CMessage &msgin, const std::string &serviceName, TServiceId sid)
389 uint32 id;
391 // Extract the incomming message content from the Frontend and print it
392 msgin.serial( id );
393 nldebug( "SB: Received REMOVE_ENTITY line." );
395 // Prepare to send back the message.
396 CMessage msgout( "REMOVE_ENTITY" );
397 msgout.serial( id );
400 * Send the message to all the connected Frontend.
402 CUnifiedNetwork::getInstance ()->send( "FS", msgout );
404 // Remove player form the player list.
405 playerList.erase( id );
407 CCLSClientPOS::removeEntity(id);
409 nldebug( "SB: Send back REMOVE_ENTITY line. %d players left ...",
410 playerList.size() );
414 /****************************************************************************
415 * Function: cbSnowball
416 * Callback function called when the Position Service receive a
417 * "SNOWBALL" message
418 ****************************************************************************/
419 void cbSnowball (CMessage &msgin, const std::string &serviceName, TServiceId sid)
421 static uint32 snowballId = START_SNOW_ID;
423 uint32 playerId;
424 CVector start,
425 target;
426 float speed,
427 explosionRadius;
429 // Extract the incomming message content from the Frontend and print it
430 msgin.serial( playerId );
431 msgin.serial( start );
432 msgin.serial( target );
433 msgin.serial( speed );
434 msgin.serial( explosionRadius );
435 nldebug( "SB: Received SNOWBALL line." );
437 // Store new snowballs information
438 CTrajectory traj;
439 traj.init( start, target, speed, CTime::getLocalTime() + THROW_ANIM_OFFSET );
440 _snowball snowball = _snowball( snowballId, playerId, traj, explosionRadius );
441 snoList.push_front( snowball );
443 // Prepare to send back the message.
444 CMessage msgout( "SNOWBALL" );
445 msgout.serial( snowballId );
446 msgout.serial( playerId );
447 msgout.serial( start );
448 msgout.serial( target );
449 msgout.serial( speed );
450 msgout.serial( explosionRadius );
452 snowballId++;
455 * Send the message to all the connected Frontend.
457 CUnifiedNetwork::getInstance ()->send( "FS", msgout );
459 nldebug( "SB: Send back SNOWBALL line." );
463 /****************************************************************************
464 * CallbackArray
466 * It define the functions to call when receiving a specific message
467 ****************************************************************************/
468 TUnifiedCallbackItem CallbackArray[] =
470 { "ADD_ENTITY", cbAddEntity },
471 { "ENTITY_POS", cbPosition },
472 { "REMOVE_ENTITY", cbRemoveEntity },
473 { "SNOWBALL", cbSnowball },
474 { "CLS_UPDATE", CCLSClientPOS::cbUpdate },
475 { "CLS_POSITION", CCLSClientPOS::cbPosition }
479 /****************************************************************************
480 * Function: SendHITMsg
481 * Send HIT message to all clients
483 * Arguments:
484 * - snowball: snowball id
485 * - victim: player touched by the snowball
486 * - direct: define if the hit is direct or by the explosion
487 * area
488 ****************************************************************************/
489 void SendHITMsg ( uint32 snowball, uint32 victim, bool direct )
491 CMessage msgout( "HIT" );
493 msgout.serial( snowball );
494 msgout.serial( victim );
495 msgout.serial( direct );
497 CUnifiedNetwork::getInstance ()->send( "FS", msgout );
500 /****************************************************************************
501 * CPositionService
502 ****************************************************************************/
503 class CPositionService : public IService
505 public:
507 void init()
509 CUnifiedNetwork::getInstance()->setServiceUpCallback("CLS", CCLSClientPOS::cbCollisionServiceUp, 0);
512 // Update fonction, called at every frames
513 bool update()
515 //_snowball snowball;
516 CVector snoPos;
517 float distance;
518 bool removeSnowball;
520 // Get the Current time
521 TTime currentTime = CTime::getLocalTime();
522 list<_snowball>::iterator ItSnowball;
524 // Check collision of snowballs with players
525 ItSnowball = snoList.begin();
526 while ( ItSnowball != snoList.end() )
528 removeSnowball = false;
530 list<_snowball>::iterator ItSb = ItSnowball++;
531 _snowball snowball = (*ItSb);
533 // Test collision (direct and explosion with players)
534 _pmap::iterator ItPlayer;
535 for (ItPlayer = playerList.begin(); ItPlayer != playerList.end(); ++ItPlayer)
537 _player player = (*ItPlayer).second;
540 * Snowballs can't touch the guy which throw it, Like that
541 * players could not kill them self (intentionally or not :-)
543 if ( player.id == snowball.owner )
545 continue;
548 // Get the current snowball position
549 snoPos = snowball.traj.eval( currentTime );
551 // Test direct collision with players
552 distance = (player.position - snoPos).norm();
553 if ( distance < ( PLAYER_RADIUS + SNOWBALL_RADIUS ) )
555 nldebug( "SB: HIT on player %u by player %u.",
556 player.id, snowball.owner );
558 // Send HIT message
559 SendHITMsg( snowball.id, player.id, true );
561 // Flag the snowball to be removed from the list
562 removeSnowball = true;
565 // Snowballs touch his stop Position
566 if ( snowball.traj.getStopTime() < currentTime )
568 // Test for explosion victims
569 distance = (player.position - snoPos).norm();
570 if ( distance < ( PLAYER_RADIUS + snowball.explosionRadius ) )
572 nldebug( "SB: Explosion hit on player %u by player %u.",
573 player.id, snowball.owner );
575 // Send HIT message
576 SendHITMsg( snowball.id, player.id, false );
579 // Flag the snowball to be removed from the list
580 removeSnowball = true;
585 // Removed if flaged snowball
586 if ( removeSnowball )
588 snoList.erase( ItSb );
589 nldebug( "SB: Removed outdated SNOWBALL id %u.", snowball.id );
594 return true;
600 /****************************************************************************
601 * SNOWBALLS POSITION SERVICE MAIN Function
603 * This call create a main function for the POSITION service:
605 * - based on the base service class "IService", no need to inherit from it
606 * - having the short name "POSITION"
607 * - having the long name "position_service"
608 * - listening on an automatically allocated port (0) by the naming service
609 * - and callback actions set to "CallbackArray"
611 ****************************************************************************/
612 NLNET_SERVICE_MAIN( CPositionService, "POS", "position_service", 0, CallbackArray, SNOWBALLS_CONFIG, SNOWBALLS_LOGS )
615 /* end of file */