1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
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.
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/>.
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>
48 using namespace NLMISC
;
49 using namespace NLNET
;
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.
64 _player( uint32 Id
, string Name
, uint8 Race
, CVector Position
) :
65 id( Id
), name( Name
), race( Race
), position( Position
) { }
72 // List of all the players connected to the shard.
73 typedef map
<uint32
, _player
> _pmap
;
76 // Define information used for the snowballs management
79 _snowball( uint32 Id
, uint32 Owner
, CTrajectory Traj
, float ExplosionRadius
) :
80 id( Id
), owner( Owner
), traj( Traj
), explosionRadius( ExplosionRadius
) { }
84 float explosionRadius
;
87 // List of all the games snowballs
88 list
<_snowball
> snoList
;
99 _entity(CVector position
, float radius
)
100 : Position(position
), Radius(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
;
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
);
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
);
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
);
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
);
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
);
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;
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
);
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
222 static void cbPosition(CMessage
&msgin
, const std::string
&serviceName
, TServiceId sid
)
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
);
240 ((*ItPlayer
).second
).position
= position
;
241 //nldebug( "SB: Player position updated" );
244 CMessage
msgout("ENTITY_TP");
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());
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
)
282 // Extract the incomming message content from the Frontend and print it
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.
291 CMessage
msgout( "ADD_ENTITY" );
292 msgout
.serial( all
);
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.
311 _pmap::iterator ItPlayer
;
312 for (ItPlayer
= playerList
.begin(); ItPlayer
!= playerList
.end(); ++ItPlayer
)
314 CMessage
msgout( "ADD_ENTITY" );
315 msgout
.serial( all
);
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
)
344 // Extract the incomming message content from the Frontend and print it
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
);
360 ((*ItPlayer
).second
).position
= pos
;
361 //nldebug( "SB: Player position updated" );
364 // Prepare to send back the message.
365 CMessage
msgout( "ENTITY_POS" );
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
)
391 // Extract the incomming message content from the Frontend and print it
393 nldebug( "SB: Received REMOVE_ENTITY line." );
395 // Prepare to send back the message.
396 CMessage
msgout( "REMOVE_ENTITY" );
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 ...",
414 /****************************************************************************
415 * Function: cbSnowball
416 * Callback function called when the Position Service receive a
418 ****************************************************************************/
419 void cbSnowball (CMessage
&msgin
, const std::string
&serviceName
, TServiceId sid
)
421 static uint32 snowballId
= START_SNOW_ID
;
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
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
);
455 * Send the message to all the connected Frontend.
457 CUnifiedNetwork::getInstance ()->send( "FS", msgout
);
459 nldebug( "SB: Send back SNOWBALL line." );
463 /****************************************************************************
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
484 * - snowball: snowball id
485 * - victim: player touched by the snowball
486 * - direct: define if the hit is direct or by the explosion
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 /****************************************************************************
502 ****************************************************************************/
503 class CPositionService
: public IService
509 CUnifiedNetwork::getInstance()->setServiceUpCallback("CLS", CCLSClientPOS::cbCollisionServiceUp
, 0);
512 // Update fonction, called at every frames
515 //_snowball snowball;
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
)
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
);
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
);
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
);
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
)