Merge branch 'lua_versions' into main/rendor-staging
[ryzomcore.git] / snowballs2 / server / collision / src / collision_service.cpp
blobe4211860123684da798f022478cd69113eee6ea4
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2008 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
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 #include "collision_service.h"
18 #include <nel/3d/u_instance_group.h>
20 #ifdef NL_OS_WINDOWS
21 #include <Windows.h>
22 #endif
24 using namespace SBSERVICE;
25 using namespace NLMISC;
26 using namespace NLNET;
27 using namespace NLPACS;
28 using namespace std;
31 //////////////////////////////////////////////////////////////////////////////
32 /// ///
33 /// VARIABLES ///
34 /// ///
35 //////////////////////////////////////////////////////////////////////////////
37 CCollisionService::CClientMap CCollisionService::_Clients;
38 NLPACS::URetrieverBank *CCollisionService::_RetrieverBank;
39 NLPACS::UGlobalRetriever *CCollisionService::_GlobalRetriever;
40 NLPACS::UMoveContainer *CCollisionService::_MoveContainer;
41 CCollisionService::CMovePrimitiveVector CCollisionService::_StaticMovePrimitives;
42 TTime CCollisionService::_LastTime, CCollisionService::_NewTime, CCollisionService::_DiffTime;
43 double CCollisionService::_DiffTimeSeconds;
44 float CCollisionService::_DiffTimeFloat;
47 //////////////////////////////////////////////////////////////////////////////
48 /// ///
49 /// BASIC FUNCTIONS ///
50 /// ///
51 //////////////////////////////////////////////////////////////////////////////
53 void CCollisionService::commandStart()
58 void CCollisionService::init()
60 // set down callback
61 CUnifiedNetwork::getInstance()->setServiceDownCallback("*", cbDown);
63 // set the data path
64 CPath::addSearchPath(ConfigFile.getVar("DataPath").asString(), true, false);
66 // init the global retriever, the retriever bank, and the move container
67 _RetrieverBank = URetrieverBank::createRetrieverBank(ConfigFile.getVar("RetrieverBankName").asString().c_str());
68 _GlobalRetriever = UGlobalRetriever::createGlobalRetriever(ConfigFile.getVar("GlobalRetrieverName").asString().c_str(), _RetrieverBank);
69 _MoveContainer = UMoveContainer::createMoveContainer(_GlobalRetriever, 100, 100, 6.0);
71 // some silly snowballs specific code to load static instance groups, redo
72 CConfigFile::CVar igv = ConfigFile.getVar("InstanceGroups");
73 for (uint i = 0; i < igv.size(); ++i)
75 NL3D::UInstanceGroup *ig = NL3D::UInstanceGroup::createInstanceGroup(igv.asString(i));
76 if (ig == NULL) nlwarning("Instance group '%s' not found", igv.asString(i).c_str());
77 else
79 for (uint i = 0; i < ig->getNumInstance(); ++i)
81 UMovePrimitive *primitive = _MoveContainer->addCollisionablePrimitive(0, 1);
82 primitive->setPrimitiveType(UMovePrimitive::_2DOrientedCylinder);
83 primitive->setReactionType(UMovePrimitive::DoNothing);
84 primitive->setTriggerType(UMovePrimitive::NotATrigger);
85 primitive->setCollisionMask(2);
86 primitive->setOcclusionMask(1);
87 primitive->setObstacle(true);
89 string name = ig->getShapeName(i);
90 float rad;
91 if (strlwr(name) == "pi_po_igloo_a") rad = 4.5f;
92 else if (strlwr(name) == "pi_po_snowman_a") rad = 1.0f;
93 else if (strlwr(name) == "pi_po_pinetree_a") rad = 2.0f;
94 else if (strlwr(name) == "pi_po_tree_a") rad = 2.0f;
95 else if (strlwr(name) == "pi_po_pingoo_stat_a") rad = 1.0f;
96 else if (strlwr(name) == "pi_po_gnu_stat_a") rad = 1.0f;
97 else
99 rad = 2.0f;
100 nlwarning ("Instance name '%s' doesn't have a good radius for collision", name.c_str());
103 primitive->setRadius(rad);
104 primitive->setHeight(6.0f);
106 primitive->insertInWorldImage(0);
107 CVector pos = ig->getInstancePos(i);
108 primitive->setGlobalPosition(CVectorD(pos.x, pos.y, pos.z - 1.5f), 0);
109 _StaticMovePrimitives.push_back(primitive);
112 delete ig;
115 _NewTime = CTime::getLocalTime();
118 bool CCollisionService::update()
120 _LastTime = _NewTime;
121 _NewTime = CTime::getLocalTime();
122 _DiffTime = _NewTime - _LastTime;
123 _DiffTimeSeconds = (double)_DiffTime / 1000.0;
124 _DiffTimeFloat = (float)_DiffTimeSeconds;
126 for (CClientMap::iterator it = _Clients.begin(); it != _Clients.end(); it++)
127 for (CEntityMap::iterator it2 = it->second.begin(); it2 != it->second.end(); it2++)
129 CEntity &entity = it2->second;
131 if (entity.Moving)
133 // nldebug("entity.Moving");
134 CVector movement = entity.NewClientPosition - entity.OldClientPosition;
135 entity.Distance = movement.norm();
136 if (entity.Distance == 0.0f)
138 entity.Moving = false;
139 entity.Retry = false;
141 CVectorD speed = CVectorD(movement) / _DiffTimeSeconds;
142 entity.MovePrimitive->move(speed, 0);
144 // else nldebug("!entity.Moving");
147 // apparently this thingy does the collision checks
148 _MoveContainer->evalCollision(_DiffTimeSeconds, 0);
150 // check all wrong stuff (use some different way maybe)
151 for (CClientMap::iterator it = _Clients.begin(); it != _Clients.end(); it++)
152 for (CEntityMap::iterator it2 = it->second.begin(); it2 != it->second.end(); it2++)
154 CEntity &entity = it2->second;
156 if (entity.Moving)
158 UGlobalPosition globalPosition;
159 entity.MovePrimitive->getGlobalPosition(globalPosition, 0);
160 CVector serverPosition = _GlobalRetriever->getGlobalPosition(globalPosition);
161 //nlinfo("clientPosition: %f %f %f", entity.NewClientPosition.x, entity.NewClientPosition.y, entity.NewClientPosition.z);
162 //nlinfo("serverPosition: %f %f %f", serverPosition.x, serverPosition.y, serverPosition.z);
164 // Allow the difference between the external client position and the
165 // local server position to be up to half of the traveled distance
166 // plus the entity's height or radius, twice (using Retry).
167 float allowedDifference = entity.Distance * 0.5f;
168 bool move = false;
169 if (abs(entity.NewClientPosition.z - serverPosition.z) > 1.0f + allowedDifference)
171 move = true;
173 else
175 // fake server position has same z as client position if ok
176 serverPosition.z = entity.NewClientPosition.z;
177 if ((serverPosition - entity.NewClientPosition).norm() > entity.MovePrimitive->getRadius() + allowedDifference)
178 move = true;
181 if (move) // Entity moved incorrectly.
183 if (entity.Retry) // If second try.
185 nldebug("entity.Retry");
186 msgPosition(it2->first, serverPosition);
188 else nldebug("!entity.Retry");
189 entity.Retry = !entity.Retry; // Else the entity gets one more chance.
192 // The difference to the new position must be from local server position.
193 entity.OldClientPosition = serverPosition;
197 msgUpdate();
198 return true;
201 void CCollisionService::release()
207 //////////////////////////////////////////////////////////////////////////////
208 /// ///
209 /// OTHER FUNCTIONS ///
210 /// ///
211 //////////////////////////////////////////////////////////////////////////////
213 void CCollisionService::sendMessage(CMessage &msgout)
215 CUnifiedNetwork *instance = CUnifiedNetwork::getInstance();
216 for (CClientMap::iterator it = _Clients.begin(); it != _Clients.end(); it++)
217 CUnifiedNetwork::getInstance()->send(TServiceId(it->first), msgout);
221 //////////////////////////////////////////////////////////////////////////////
222 /// ///
223 /// MESSAGE SENDERS ///
224 /// ///
225 //////////////////////////////////////////////////////////////////////////////
227 /****************************************************************************
228 * Function: msgUpdate
229 * Send CLS_UPDATE message to registered services
231 * Arguments:
232 ****************************************************************************/
233 void CCollisionService::msgUpdate()
235 if (!_Clients.size()) return;
237 static CMessage msgout("CLS_UPDATE");
238 sendMessage(msgout);
239 //nldebug("Sent CLS_UPDATE to %u services", _Clients.size());
242 /****************************************************************************
243 * Function: msgPosition
244 * Send CLS_POSITION message to registered services
246 * Arguments:
247 * - id: entity id
248 * - position: new position
249 ****************************************************************************/
250 void CCollisionService::msgPosition(uint32 id, CVector position)
252 if (!_Clients.size()) return;
254 CMessage msgout("CLS_POSITION");
255 msgout.serial(id, position);
256 sendMessage(msgout);
257 nldebug("Sent CLS_POSITION %u %f %f %f to %u services", id, position.x, position.y, position.z, _Clients.size());
261 //////////////////////////////////////////////////////////////////////////////
262 /// ///
263 /// MESSAGE CALLBACKS ///
264 /// ///
265 //////////////////////////////////////////////////////////////////////////////
267 /****************************************************************************
268 * Function: cbAdd
269 * Receives an "ADD" message.
270 ****************************************************************************/
271 void CCollisionService::cbAdd(CMessage &msgin, const std::string &serviceName, TServiceId sid)
273 // Read incoming message
274 uint32 id;
275 CVector position;
276 float radius;
277 msgin.serial(id, position, radius);
278 nldebug("Received ADD %u %f %f %f %f", id, position.x, position.y, position.z, radius);
280 // Do something with it
281 CEntity &entity = _Clients[sid.get()][id] = CEntity();
282 entity.OldClientPosition = position;
283 entity.NewClientPosition = position;
284 entity.MovePrimitive = _MoveContainer->addCollisionablePrimitive(0, 1);
285 entity.MovePrimitive->setPrimitiveType(UMovePrimitive::_2DOrientedCylinder);
286 entity.MovePrimitive->setReactionType(UMovePrimitive::Slide);
287 entity.MovePrimitive->setTriggerType(UMovePrimitive::NotATrigger);
288 entity.MovePrimitive->setCollisionMask(3);
289 entity.MovePrimitive->setOcclusionMask(2);
290 entity.MovePrimitive->setObstacle(true);
291 entity.MovePrimitive->setRadius(radius);
292 entity.MovePrimitive->setHeight(1.8f);
293 entity.MovePrimitive->insertInWorldImage(0);
294 entity.MovePrimitive->setGlobalPosition(position, 0);
297 /****************************************************************************
298 * Function: cbMove
299 * Receives a "MOVE" message.
300 ****************************************************************************/
301 void CCollisionService::cbMove(CMessage &msgin, const std::string &serviceName, TServiceId sid)
303 // Read incoming message
304 uint32 id;
305 CVector position;
306 msgin.serial(id, position);
307 // nldebug("Received MOVE %u %f %f %f", id, position.x, position.y, position.z);
309 // Do something with it
310 CEntity &entity = _Clients[sid.get()][id];
311 entity.NewClientPosition = position;
312 if (entity.OldClientPosition != position)
313 entity.Moving = true;
316 /****************************************************************************
317 * Function: cbRemove
318 * Receives a "REMOVE" message.
319 ****************************************************************************/
320 void CCollisionService::cbRemove(CMessage &msgin, const std::string &serviceName, TServiceId sid)
322 // Read incoming message
323 uint32 id;
324 msgin.serial(id);
325 nldebug("Received REMOVE %u", id);
327 // Do something with it
328 if (_Clients[sid.get()].find(id) == _Clients[sid.get()].end())
330 nlwarning("Unknown entity %u", id);
331 return;
333 CEntity &entity = _Clients[sid.get()][id];
334 _MoveContainer->removePrimitive(entity.MovePrimitive);
335 _Clients[sid.get()].erase(id);
338 /****************************************************************************
339 * Function: cbRegister
340 * Receives a "REGISTER" message.
341 ****************************************************************************/
342 void CCollisionService::cbRegister(CMessage &msgin, const std::string &serviceName, TServiceId sid)
344 // Read incoming message
345 nldebug("Received REGISTER %s %s", serviceName.c_str(), sid.toString().c_str());
347 // Do something with it
348 _Clients[sid.get()] = CEntityMap();
352 //////////////////////////////////////////////////////////////////////////////
353 /// ///
354 /// NETWORK CALLBACKS ///
355 /// ///
356 //////////////////////////////////////////////////////////////////////////////
358 /****************************************************************************
359 * Function: cbDown
360 * Called when a registered service goes down
361 ****************************************************************************/
362 void CCollisionService::cbDown(const string &serviceName, TServiceId sid, void *arg)
364 CClientMap::iterator it = _Clients.find(sid.get());
365 if (it != _Clients.end())
367 // remove all entities
368 for (CEntityMap::iterator it2 = it->second.begin(); it2 != it->second.end(); it2++)
369 _MoveContainer->removePrimitive(it2->second.MovePrimitive);
370 // erase the client
371 _Clients.erase(it);
376 //////////////////////////////////////////////////////////////////////////////
377 /// ///
378 /// SERVICE CONFIGURATION ///
379 /// ///
380 //////////////////////////////////////////////////////////////////////////////
382 /****************************************************************************
383 * CallbackArray
385 * It define the functions to call when receiving a specific message
386 ****************************************************************************/
387 TUnifiedCallbackItem CallbackArray[] =
389 { "REGISTER", CCollisionService::cbRegister },
390 { "ADD", CCollisionService::cbAdd },
391 { "MOVE", CCollisionService::cbMove },
392 { "REMOVE", CCollisionService::cbRemove },
395 /****************************************************************************
396 * SNOWBALLS COLLISION SERVICE MAIN Function
398 * This call create a main function for the world_service:
400 * - based on the service class CCollisionService inherited from IService
401 * - having the short name "CLS"
402 * - having the long name "collision_service"
403 * - listening on an automatically allocated port (0) by the naming service
404 * - and callback actions set to "CallbackArray"
406 ****************************************************************************/
407 NLNET_SERVICE_MAIN(CCollisionService, "CLS", "collision_service", 0, CallbackArray, "", "")
409 /* end of file */