Added spawnCrystalItem
[ryzomcore.git] / ryzom / client / src / ig_callback.cpp
blobe59c844aab2f2a128b3e3e604749eb876520bb8d
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2020 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/>.
22 #include "stdpch.h"
26 #include "nel/misc/path.h"
27 #include "nel/misc/matrix.h"
28 #include "nel/misc/vector.h"
29 #include "nel/misc/vectord.h"
30 #include "nel/misc/sheet_id.h"
32 #include "nel/pacs/u_primitive_block.h"
33 #include "nel/pacs/u_move_container.h"
34 #include "nel/pacs/u_move_primitive.h"
35 #include "nel/pacs/u_global_position.h"
37 #include "nel/3d/u_scene.h"
38 #include "nel/3d/u_instance.h"
41 #include "ig_callback.h"
42 #include "fix_season_data.h"
43 #include "sheet_manager.h"
44 #include "ig_enum.h"
45 #include "weather.h"
46 #include "pacs_client.h"
47 // Client Sheets
48 #include "client_sheets/plant_sheet.h"
49 #include <memory>
51 #ifdef DEBUG_NEW
52 #define new DEBUG_NEW
53 #endif
55 #define RZ_PRIM_ZEXT_BLOCK_AVOIDANCE 2.0f
58 H_AUTO_DECL(RZ_IGCallback)
60 ///===================================================================================
61 CIGCallback::CIGCallback() : _MoveContainer(NULL)
63 H_AUTO_USE(RZ_IGCallback)
64 //nlinfo("**** YOYO: CREATING IG CALLBACK: %x", this);
67 ///===================================================================================
68 CIGCallback::~CIGCallback()
70 //nlinfo("**** YOYO: DELETING IG CALLBACK: %x", this);
71 H_AUTO_USE(RZ_IGCallback)
72 deleteIGs();
75 ///===================================================================================
76 void CIGCallback::resetContainer()
78 H_AUTO_USE(RZ_IGCallback)
79 if (!_MoveContainer) return;
80 deleteIGs();
81 _MoveContainer = NULL;
84 ///===================================================================================
85 void CIGCallback::setMoveContainer(NLPACS::UMoveContainer *mc)
87 H_AUTO_USE(RZ_IGCallback)
88 nlassert(!_MoveContainer);
89 _MoveContainer = mc;
92 ///===================================================================================
93 void CIGCallback::addIG(NL3D::UInstanceGroup *ig)
95 H_AUTO_USE(RZ_IGCallback)
96 nlassert(_MoveContainer);
97 CIGInstance *igi;
98 try
100 igi = new CIGInstance(ig, this);
101 _IGInstances.push_back(igi);
102 ig->setAddRemoveInstanceCallback(igi);
103 ig->setTransformNameCallback(igi);
104 ig->setIGAddBeginCallback(igi);
106 catch(...)
108 delete igi;
109 throw;
113 ///===================================================================================
114 void CIGCallback::addIGWithNumZC(NL3D::UInstanceGroup *ig, sint numZC)
116 H_AUTO_USE(RZ_IGCallback)
117 // Check the ig is valid.
118 if(ig == 0)
119 return;
121 nlassert(_MoveContainer);
122 CIGInstance *igi;
125 igi = new CIGInstance(ig, this);
126 igi->numZC(numZC);
127 _IGInstances.push_back(igi);
128 ig->setAddRemoveInstanceCallback(igi);
129 ig->setTransformNameCallback(igi);
130 ig->setIGAddBeginCallback(igi);
132 catch(...)
134 delete igi;
135 throw;
140 ///===================================================================================
141 void CIGCallback::addIGs(const std::vector<NL3D::UInstanceGroup *> &igs)
143 H_AUTO_USE(RZ_IGCallback)
144 _IGInstances.reserve(_IGInstances.size() + igs.size());
145 for(uint k = 0; k < igs.size(); ++k)
147 addIG(igs[k]);
151 //-----------------------------------------------
152 // addIGsWithNumZC :
153 // Add a vector of instance groups with the num ZC associated.
154 //-----------------------------------------------
155 void CIGCallback::addIGsWithNumZC(std::vector<std::pair<NL3D::UInstanceGroup *, sint> > &igs)
157 H_AUTO_USE(RZ_IGCallback)
158 _IGInstances.reserve(_IGInstances.size() + igs.size());
159 for(uint k = 0; k < igs.size(); ++k)
161 addIGWithNumZC(igs[k].first, igs[k].second);
166 ///===================================================================================
167 CIGCallback::CIGInstance::CIGInstance(NL3D::UInstanceGroup *ig, CIGCallback *owner)
168 : _Owner(owner), _IG(ig), _HasManagedFXs(false)
170 H_AUTO_USE(RZ_IGCallback)
171 nlassert(owner);
172 nlassert(ig);
175 ///===================================================================================
176 CIGCallback::CIGInstance::~CIGInstance()
178 H_AUTO_USE(RZ_IGCallback)
179 releaseMovePrimitives();
180 if (_HasManagedFXs)
182 CTimedFXManager::getInstance().remove(_ManagedFXHandle);
184 if (_IG)
186 _IG->setAddRemoveInstanceCallback(NULL);
187 _IG->setTransformNameCallback(NULL);
188 _IG->setIGAddBeginCallback(NULL);
192 ///===================================================================================
193 void CIGCallback::CIGInstance::instanceGroupAdded()
195 H_AUTO_USE(RZ_IGCallback)
196 // Check the pointer on the IG.
197 nlassert(_IG);
198 nlassert(_Owner);
200 // See what objects need collisions primitives
201 if (!_MovePrimitives.empty()) return; // already added
202 std::vector<NLPACS::UMovePrimitive *> addedPrims;
203 uint numInstances = _IG->getNumInstance();
204 for(uint k = 0; k < numInstances; ++k)
206 TPacsPrimMap::iterator pbIt = PacsPrims.find(NLMISC::toLowerAscii(NLMISC::CFile::getFilenameWithoutExtension(_IG->getShapeName(k))));
207 if (pbIt != PacsPrims.end())
209 // compute orientation and position
210 NLMISC::CMatrix instanceMatrix;
211 _IG->getInstanceMatrix(k, instanceMatrix);
212 NLMISC::CVector pos;
213 float angle;
214 NLMISC::CVector scale = _IG->getInstanceScale(k);
215 NLPACS::UMoveContainer::getPACSCoordsFromMatrix(pos, angle, instanceMatrix);
216 // insert the matching primitive block
217 addedPrims.clear();
218 _Owner->_MoveContainer->addCollisionnablePrimitiveBlock(pbIt->second, 0, 1, &addedPrims, angle, pos, true, scale);
219 // Yoyo: For each primitive, increment its height, to avoid blocking bugs
220 for(uint i=0;i<addedPrims.size();i++)
222 // do it only for obstacle, non trigerrable(?) prims
223 if(addedPrims[i] && addedPrims[i]->getObstacle() && addedPrims[i]->getTriggerType()==NLPACS::UMovePrimitive::NotATrigger)
225 addedPrims[i]->setHeight(addedPrims[i]->getHeight() + RZ_PRIM_ZEXT_BLOCK_AVOIDANCE);
228 // for future remove
229 _MovePrimitives.insert(_MovePrimitives.end(), addedPrims.begin(), addedPrims.end());
232 // update additionnal datas from sheets
233 updateFromSheets();
234 updateManagedFXs();
235 // free mem for sheet pointers
236 NLMISC::contReset(_EntitySheets);
237 _Owner->notifyIGAdded(_IG);
240 ///===================================================================================
241 void CIGCallback::CIGInstance::instanceGroupRemoved()
243 H_AUTO_USE(RZ_IGCallback)
244 // If this zone is a ZC.
245 releaseMovePrimitives();
246 if (_HasManagedFXs)
248 CTimedFXManager::getInstance().remove(_ManagedFXHandle);
249 _HasManagedFXs = false;
254 ///===================================================================================
255 void CIGCallback::CIGInstance::releaseMovePrimitives()
257 H_AUTO_USE(RZ_IGCallback)
258 nlassert(_Owner);
259 // remove all primitives from the move container
260 nlassert(_Owner->_MoveContainer);
261 for(TMovePrimitiveVect::iterator it = _MovePrimitives.begin(); it != _MovePrimitives.end(); ++it)
263 _Owner->_MoveContainer->removePrimitive(*it);
265 NLMISC::contReset(_MovePrimitives);
268 ///===================================================================================
269 void CIGCallback::deleteIGs()
271 H_AUTO_USE(RZ_IGCallback)
272 for(TIGInstanceList::iterator it = _IGInstances.begin(); it != _IGInstances.end(); ++it)
274 delete *it;
276 _IGInstances.clear();
279 ///===================================================================================
280 void CIGCallback::forceAddAll()
282 H_AUTO_USE(RZ_IGCallback)
283 for(TIGInstanceList::iterator it = _IGInstances.begin(); it != _IGInstances.end(); ++it)
285 (*it)->forceAdd();
289 ///===================================================================================
290 void CIGCallback::CIGInstance::startAddingIG(uint numInstances)
292 H_AUTO_USE(RZ_IGCallback)
293 // make room for sheets ptr
294 _EntitySheets.resize(numInstances);
295 std::fill(_EntitySheets.begin(), _EntitySheets.end(), (CEntitySheet *) NULL);
298 ///===================================================================================
299 void CIGCallback::CIGInstance::buildSheetVector()
301 H_AUTO_USE(RZ_IGCallback)
302 uint numInstances = _IG->getNumInstance();
303 _EntitySheets.resize(numInstances);
304 for(uint k = 0; k < numInstances; ++k)
306 _EntitySheets[k] = NULL;
307 const std::string &name = _IG->getInstanceName(k);
308 if (NLMISC::nlstricmp(NLMISC::CFile::getExtension(name), "plant") == 0)
310 NLMISC::CSheetId sheetId;
311 if (sheetId.buildSheetId(name))
313 _EntitySheets[k] = SheetMngr.get(sheetId);
319 ///===================================================================================
320 void CIGCallback::CIGInstance::eraseSheetVector()
322 H_AUTO_USE(RZ_IGCallback)
323 NLMISC::contReset(_EntitySheets);
326 ///===================================================================================
327 std::string CIGCallback::CIGInstance::transformName(uint instanceIndex, const std::string &instanceName, const std::string &shapeName)
329 H_AUTO_USE(RZ_IGCallback)
330 /** we look if there'is a matching form for this instance name
331 * If this is the case we can choose the shape we want to instanciate
334 string ext = NLMISC::CFile::getExtension(instanceName);
335 if (NLMISC::nlstricmp(ext, "pacs_prim") == 0)
337 return ""; // Don't instanciate pacs_prim
339 if (NLMISC::nlstricmp(ext, "plant") != 0)
341 return shapeName; // if there's no attached sheet, use the shape name
343 // We cache the last id
344 static std::string lastName;
345 static CEntitySheet *lastSheet = NULL;
346 CEntitySheet *sh;
347 if (instanceName == lastName)
349 sh = lastSheet;
351 else
353 NLMISC::CSheetId sheetId;
354 if (sheetId.buildSheetId(instanceName))
356 sh = SheetMngr.get(sheetId);
357 lastSheet = sh;
358 lastName = instanceName;
360 else
362 return shapeName;
365 if (!sh) return shapeName;
366 if (sh->type() == CEntitySheet::PLANT)
368 // store sheet in the sheet list
369 _EntitySheets[instanceIndex] = sh;
370 return ((CPlantSheet *) sh)->getShapeName();
372 else
374 return shapeName;
378 ///===================================================================================
379 void CIGCallback::CIGInstance::updateFromSheets()
381 H_AUTO_USE(RZ_IGCallback)
382 nlassert(_EntitySheets.size() == _IG->getNumInstance());
383 // See for which objects distance should be overriden (object which use a .PLANT sheet)
384 uint numInstances = (uint)_EntitySheets.size();
385 for(uint k = 0; k < numInstances; ++k)
387 if (_EntitySheets[k] && _EntitySheets[k]->Type == CEntitySheet::PLANT)
389 CPlantSheet *ps = NLMISC::safe_cast<CPlantSheet *>(_EntitySheets[k]);
390 if (ps->getMaxDist() != -1) _IG->setDistMax(k, ps->getMaxDist());
391 if (ps->getCoarseMeshDist() != -1) _IG->setCoarseMeshDist(k, ps->getCoarseMeshDist());
396 ///===================================================================================
397 void CIGCallback::CIGInstance::shutDownFXs()
399 H_AUTO_USE(RZ_IGCallback)
400 if (!_HasManagedFXs) return;
401 CTimedFXManager::getInstance().shutDown(_ManagedFXHandle);
402 _HasManagedFXs = false;
405 ///===================================================================================
406 void CIGCallback::CIGInstance::updateManagedFXs()
408 H_AUTO_USE(RZ_IGCallback)
409 nlassert(_EntitySheets.size() == _IG->getNumInstance());
410 // See for which objects distance should be overriden (object which use a .PLANT sheet)
411 uint numInstances = (uint)_EntitySheets.size();
412 // vector of fx that should be managed by the dedicated manager. static for malloc perf
413 static std::vector<CTimedFX> timedFXs;
414 timedFXs.clear();
415 for(uint k = 0; k < numInstances; ++k)
417 if (_EntitySheets[k] && _EntitySheets[k]->Type == CEntitySheet::PLANT)
419 CPlantSheet *ps = NLMISC::safe_cast<CPlantSheet *>(_EntitySheets[k]);
420 // check for managed fxs for the current season
421 if (CurrSeason < EGSPD::CSeason::Invalid)
423 if (!ps->getFXSheet(CurrSeason).FXName.empty())
425 timedFXs.push_back(CTimedFX());
426 timedFXs.back().SpawnPosition = _IG->getInstancePos(k);
427 timedFXs.back().Rot = _IG->getInstanceRot(k);
428 timedFXs.back().Scale = _IG->getInstanceScale(k);
429 timedFXs.back().FXSheet = &ps->getFXSheet(CurrSeason);
434 if (!timedFXs.empty())
436 _ManagedFXHandle = CTimedFXManager::getInstance().add(timedFXs, CurrSeason);
437 _HasManagedFXs = true;
443 ///===================================================================================
444 bool CIGCallback::enumIGs(IIGEnum *callback)
446 H_AUTO_USE(RZ_IGCallback)
447 nlassert(callback);
448 for(TIGInstanceList::iterator it = _IGInstances.begin(); it != _IGInstances.end(); ++it)
450 if ((*it)->getIG() != NULL && (*it)->getIG() != (NL3D::UInstanceGroup *)-1)
452 bool res = callback->enumIG((*it)->getIG());
453 if (!res) return false;
456 return true;
459 ///===================================================================================
460 void CIGCallback::changeSeason()
462 H_AUTO_USE(RZ_IGCallback)
463 // for now, this only update managed fxs so that they are displayed the same way on both clients
464 for(TIGInstanceList::iterator it = _IGInstances.begin(); it != _IGInstances.end(); ++it)
466 if ((*it)->getIG() != NULL && (*it)->getIG() != (NL3D::UInstanceGroup *)-1)
468 (*it)->buildSheetVector(); // the sheet vector is deleted after use, so need to rebuild it
469 (*it)->shutDownFXs();
470 (*it)->updateManagedFXs();
471 (*it)->eraseSheetVector();
476 ///===================================================================================
477 ///===================================================================================
480 void createInstancesFromMoveContainer(NL3D::UScene *scene, NLPACS::UMoveContainer *mc, std::vector<NL3D::UInstance> *instances /*=NULL*/)
482 H_AUTO_USE(RZ_IGCallback)
483 nlassert(scene);
484 nlassert(mc);
485 mc->evalCollision(0.1f, 0);
486 // get the primitives
487 std::vector<const NLPACS::UMovePrimitive *> prims;
488 mc->getPrimitives(prims);
489 if (instances)
491 instances->reserve(prims.size());
493 for(uint k = 0; k < prims.size(); ++k)
495 NL3D::UInstance newInstance;
496 float angle = 0.f;
497 NLMISC::CVector scale;
498 switch(prims[k]->getPrimitiveType())
500 case NLPACS::UMovePrimitive::_2DOrientedBox:
501 newInstance = scene->createInstance("unit_box.shape");
502 angle = (float) prims[k]->getOrientation(prims[k]->getFirstWorldImageV());
503 prims[k]->getSize(scale.x, scale.y);
504 break;
505 case NLPACS::UMovePrimitive::_2DOrientedCylinder:
506 newInstance = scene->createInstance("unit_cylinder.shape");
507 scale.x = scale.y = prims[k]->getRadius();
508 break;
509 default:
510 nlwarning("createInstancesFromMoveContainer : unsupported type encountered");
511 continue;
512 break;
514 if (!newInstance.empty())
516 scale.z = prims[k]->getHeight();
517 NLMISC::CVectorD worldPos = prims[k]->getFinalPosition(prims[k]->getFirstWorldImageV());
518 newInstance.setPos(NLMISC::CVector((float) worldPos.x, (float) worldPos.y, (float) worldPos.z));
519 newInstance.setScale(scale);
520 newInstance.setRotQuat(NLMISC::CQuat(NLMISC::CVector::K, angle));
521 if (instances)
523 instances->push_back(newInstance);
526 else
528 nlwarning("createInstancesFromMoveContainer : couldn't create shape");