1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
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/>.
24 #include "door_manager.h"
25 #include "pacs_client.h"
26 #include "time_client.h"
27 #include "entity_cl.h"
30 #include "nel/pacs/u_primitive_block.h"
31 #include "nel/pacs/u_move_container.h"
32 #include "nel/pacs/u_move_primitive.h"
33 #include "nel/pacs/u_global_position.h"
34 #include "nel/pacs/u_collision_desc.h"
36 using namespace NLMISC
;
37 using namespace NLPACS
;
42 CIGDoorAddedCallback IGDoorCallback
;
44 CDoorManager
*CDoorManager::_Instance
= NULL
;
46 extern CEntityManager EntitiesMngr
;
48 uint32
CDoorManager::s_nextId
= 0;
50 // ***************************************************************************
51 void CDoorManager::releaseInstance()
58 // ***************************************************************************
60 // ***************************************************************************
62 #define TIME_OPEN_CLOSE_DOOR 0.7f
63 #define SIZE_DOOR 3.0f
64 #define SIZE_DOOR_3PARTS_LR 1.0f
65 #define SIZE_DOOR_3PARTS_DN 1.5f
66 #define SIZE_DOOR_2PARTS_LR 1.0f
68 // ***************************************************************************
69 void CDoorManager::SDoor::anim()
74 case Matis3PartBourgeon
:
76 if (Instances
[0] != 0xFFFFFFFF) // Left Part
78 UInstance inst
= InstanceGroup
->getInstance(Instances
[0]);
81 CMatrix mat
= InstMat
[0];
82 if (AnimType
== Matis3Part
)
83 mat
.setPos (mat
.getPos()+ OCState
*mat
.getK()*SIZE_DOOR_3PARTS_LR
84 + OCState
*mat
.getJ()*SIZE_DOOR_3PARTS_LR
);
86 mat
.setPos (mat
.getPos()+ OCState
*mat
.getK()*SIZE_DOOR_3PARTS_LR
87 - OCState
*mat
.getI()*SIZE_DOOR_3PARTS_LR
);
92 if (Instances
[1] != 0xFFFFFFFF) // Right Part
94 UInstance inst
= InstanceGroup
->getInstance(Instances
[1]);
97 CMatrix mat
= InstMat
[1];
98 if (AnimType
== Matis3Part
)
99 mat
.setPos (mat
.getPos()+ OCState
*mat
.getK()*SIZE_DOOR_3PARTS_LR
100 - OCState
*mat
.getJ()*SIZE_DOOR_3PARTS_LR
);
102 mat
.setPos (mat
.getPos()+ OCState
*mat
.getK()*SIZE_DOOR_3PARTS_LR
103 + OCState
*mat
.getI()*SIZE_DOOR_3PARTS_LR
);
108 if (Instances
[2] != 0xFFFFFFFF) // Down Part
110 UInstance inst
= InstanceGroup
->getInstance(Instances
[2]);
113 CMatrix mat
= InstMat
[2];
114 mat
.setPos (mat
.getPos() - OCState
*mat
.getK()*SIZE_DOOR_3PARTS_DN
);
123 if (Instances
[0] != 0xFFFFFFFF) // Left Part
125 UInstance inst
= InstanceGroup
->getInstance(Instances
[0]);
128 CMatrix mat
= InstMat
[0];
129 mat
.setPos (mat
.getPos()- OCState
*mat
.getI()*SIZE_DOOR_2PARTS_LR
);
134 if (Instances
[1] != 0xFFFFFFFF) // Right Part
136 UInstance inst
= InstanceGroup
->getInstance(Instances
[1]);
139 CMatrix mat
= InstMat
[1];
140 mat
.setPos (mat
.getPos()+ OCState
*mat
.getI()*SIZE_DOOR_2PARTS_LR
);
150 for (uint i
= 0; i
< Instances
.size(); ++i
)
152 UInstance inst
= InstanceGroup
->getInstance(Instances
[i
]);
155 CMatrix mat
= InstMat
[i
];
156 mat
.setPos(mat
.getPos()+OCState
*mat
.getK()*SIZE_DOOR
);
165 // ***************************************************************************
166 bool CDoorManager::SDoor::open()
168 if (OCState
>= 1.0f
) return true;
172 InstanceGroup
->setDynamicPortal (Name
, true);
176 OCState
+= DT
/ TIME_OPEN_CLOSE_DOOR
;
177 if (OCState
> 1.0f
) OCState
= 1.0f
;
183 // ***************************************************************************
184 bool CDoorManager::SDoor::close()
186 if (OCState
<= 0.0f
) return true;
188 OCState
-= DT
/ TIME_OPEN_CLOSE_DOOR
;
194 InstanceGroup
->setDynamicPortal (Name
, false);
203 // ***************************************************************************
204 void CDoorManager::SDoor::entityCollide(CEntityCL
*pE
)
206 for (uint i
= 0; i
< Entities
.size(); ++i
)
207 if (Entities
[i
] == pE
)
209 // The entity has moved in the trigger
210 EntitiesMoved
[i
] = 1;
213 // New entity entered the trigger
214 Entities
.push_back(pE
);
215 EntitiesMoved
.push_back(1);
218 // ***************************************************************************
219 void CDoorManager::SDoor::checkToClose()
221 for (sint i
= 0; i
< (sint
)Entities
.size(); ++i
)
223 if (EntitiesMoved
[i
] == 0) // No trigger moved
225 if (Entities
[i
]->hasMoved()) // But the entity has moved (so not in the trigger)
227 // The entity has leaved the trigger
228 Entities
.erase(Entities
.begin()+i
);
229 EntitiesMoved
.erase(EntitiesMoved
.begin()+i
);
233 else // Trigger move ok lets reset for next update
235 EntitiesMoved
[i
] = EntitiesMoved
[i
] - 1;
239 if (Entities
.empty())
246 // ***************************************************************************
248 // ***************************************************************************
250 // ***************************************************************************
251 std::string
CDoorManager::transformName (uint
/* index */, const std::string
&/* instanceName */, const std::string
&shapeName
)
253 if (shapeName
.rfind('.') == string::npos
) return shapeName
;
254 string sExt
= toLowerAscii(shapeName
.substr(shapeName
.rfind('.')+1,shapeName
.size()));
255 if (sExt
!= "pacs_prim") return shapeName
;
256 return ""; // Do not load a pacs prim as a mesh...
259 // ***************************************************************************
260 void CDoorManager::loadedCallback (NL3D::UInstanceGroup
*ig
)
263 // Check all instances and look if there are some pacs_prim to instanciate
264 uint numInstances
= ig
->getNumInstance();
265 for(uint k
= 0; k
< numInstances
; ++k
)
267 // Check if the shape name is a pacs_prim
268 string sShapeName
= ig
->getShapeName(k
);
269 if (sShapeName
.rfind('.') == string::npos
) continue;
271 string sExt
= toLowerAscii(sShapeName
.substr(sShapeName
.rfind('.')+1,sShapeName
.size()));
272 if (sExt
!= "pacs_prim") continue;
274 // Check if the pacs_prim is a door detection
276 sShapeName
= CPath::lookup(sShapeName
,false);
277 if (!sShapeName
.empty())
279 CUniquePtr
<NLPACS::UPrimitiveBlock
> pb(NLPACS::UPrimitiveBlock::createPrimitiveBlockFromFile(sShapeName
));
280 NLPACS::UPrimitiveBlock
*pPB
= pb
.release();
282 bool bDoorDetectPresent
= false;
283 for (i
= 0; i
< pPB
->getNbPrimitive(); ++i
)
285 if ((pPB
->getUserData(i
) & 0xffff) == UserDataDoor
)
287 bDoorDetectPresent
= true;
292 if (!bDoorDetectPresent
)
298 // Instanciate the pacs_prim and create a door structure associated
299 SDoor
*pDoor
= new SDoor
;
300 pDoor
->InstanceGroup
= ig
;
301 // compute orientation and position
302 NLMISC::CMatrix instanceMatrix
;
303 ig
->getInstanceMatrix(k
, instanceMatrix
);
306 NLMISC::CVector scale
= ig
->getInstanceScale(k
);
307 NLPACS::UMoveContainer::getPACSCoordsFromMatrix(pos
, angle
, instanceMatrix
);
308 PACS
->addCollisionnablePrimitiveBlock(pPB
, 0, 1, &pDoor
->Prims
, angle
, pos
, true, scale
);
310 // Complete the user data of all the 'door primitives' with a pointer to the door structure
311 for (i
= 0; i
< pDoor
->Prims
.size(); ++i
)
313 UMovePrimitive
*pPrim
= pDoor
->Prims
[i
];
314 if ((pPrim
->UserData
&0xffff) == UserDataDoor
)
316 // First byte is for type (2 for door 1 for ascensor)
317 pPrim
->UserData
|= ((uint64
)pDoor
->ID
<< 16);
321 // Link with all door 3d objects (depending on the structure of the door)
322 pDoor
->Name
= ig
->getInstanceName(k
);
323 pDoor
->AnimType
= SDoor::Normal
;
325 if (strnicmp(pDoor
->Name
.c_str(),"ma_asc_3portes_bourgeons",24)==0)
327 pDoor
->AnimType
= SDoor::Matis3PartBourgeon
;
328 pDoor
->Instances
.resize(3, 0xFFFFFFFF);
330 else if (strnicmp(pDoor
->Name
.c_str(),"ma_asc_3portes",14)==0)
332 pDoor
->AnimType
= SDoor::Matis3Part
;
333 pDoor
->Instances
.resize(3, 0xFFFFFFFF);
335 else if (strnicmp(pDoor
->Name
.c_str(),"zo_asc_2portes",14)==0)
337 pDoor
->AnimType
= SDoor::Zorai2Part
;
338 pDoor
->Instances
.resize(2, 0xFFFFFFFF);
341 for(i
= 0; i
< numInstances
; ++i
)
344 string sInstName
= ig
->getInstanceName(i
);
345 if (sInstName
== pDoor
->Name
)
347 switch (pDoor
->AnimType
)
349 case SDoor::Matis3Part
:
350 case SDoor::Matis3PartBourgeon
:
352 string sDebug
= ig
->getShapeName(i
);
353 sDebug
= toLowerAscii(sDebug
.substr(sDebug
.rfind('_')+1,sDebug
.size()));
354 if (sDebug
== "gauche")
355 pDoor
->Instances
[0] = i
;
356 else if (sDebug
== "droite")
357 pDoor
->Instances
[1] = i
;
358 else if (sDebug
== "bas")
359 pDoor
->Instances
[2] = i
;
363 case SDoor::Zorai2Part
:
365 string sDebug
= ig
->getShapeName(i
);
366 sDebug
= toLowerAscii(sDebug
.substr(sDebug
.rfind('_')+1,sDebug
.size()));
367 if (sDebug
== "gauche")
368 pDoor
->Instances
[0] = i
;
369 else if (sDebug
== "droite")
370 pDoor
->Instances
[1] = i
;
377 string sDebug
= ig
->getShapeName(i
);
378 pDoor
->Instances
.push_back(i
);
385 bool bAllInit
= true;
386 for (i
= 0; i
< pDoor
->Instances
.size(); ++i
)
387 if (pDoor
->Instances
[i
] == 0xFFFFFFFF)
392 nlwarning("All the door part are not well initialized");
393 for (sint j
= 0; j
< (sint
)pDoor
->Prims
.size(); ++j
)
396 PACS
->removePrimitive(pDoor
->Prims
[j
]);
398 nlwarning("PACS should not be NULL at this point");
405 pDoor
->InstMat
.resize(pDoor
->Instances
.size());
406 for (i
= 0; i
< pDoor
->Instances
.size(); ++i
)
409 ig
->getInstanceMatrix (pDoor
->Instances
[i
], mat
);
410 pDoor
->InstMat
[i
] = mat
;
413 // Close the door/portal by default
414 pDoor
->Opened
= false;
415 ig
->setDynamicPortal(pDoor
->Name
, false);
417 // Add the door to the door manager
418 _Doors
.push_back(pDoor
);
419 ig
->setTransformNameCallback(this);
425 // ***************************************************************************
426 void CDoorManager::addedCallback (NL3D::UInstanceGroup
*ig
)
429 for (i
= 0; i
< (sint
)_Doors
.size(); ++i
)
431 SDoor
*pDoor
= _Doors
[i
];
432 if (pDoor
->InstanceGroup
== ig
)
434 for (j
= 0; j
< (sint
)pDoor
->Instances
.size(); ++j
)
436 UInstance inst
= pDoor
->InstanceGroup
->getInstance(pDoor
->Instances
[j
]);
440 inst
.setTransformMode(UInstance::DirectMatrix
);
447 // ***************************************************************************
448 void CDoorManager::removedCallback (NL3D::UInstanceGroup
*ig
)
450 // Remove all doors corresponding to the instance group ig
452 for (i
= 0; i
< (sint
)_Doors
.size(); ++i
)
454 SDoor
*pDoor
= _Doors
[i
];
455 if (pDoor
->InstanceGroup
== ig
)
458 for (j
= 0; j
< (sint
)pDoor
->Prims
.size(); ++j
)
461 PACS
->removePrimitive(pDoor
->Prims
[j
]);
463 nlwarning("PACS should not be NULL at this point");
466 _Doors
.erase(_Doors
.begin()+i
);
472 // Copy triggers to be used in update
473 // ***************************************************************************
474 void CDoorManager::getPACSTriggers()
476 uint nNbTrig
= PACS
->getNumTriggerInfo();
477 for (uint i
= 0; i
< nNbTrig
; ++i
)
479 const UTriggerInfo
&rTI
= PACS
->getTriggerInfo(i
);
480 // Does one of the 2 objects is a door detection object
481 if (((rTI
.Object0
& 0xffff) == UserDataDoor
) || ((rTI
.Object1
& 0xffff) == UserDataDoor
))
483 uint64 nUserDataDoor
= 0;
484 uint64 nUserDataEntity
= 0;
485 if ((rTI
.Object0
& 0xffff) == UserDataDoor
)
487 nUserDataDoor
= rTI
.Object0
;
488 nUserDataEntity
= rTI
.Object1
;
491 if ((rTI
.Object1
& 0xffff) == UserDataDoor
)
493 nUserDataDoor
= rTI
.Object1
;
494 nUserDataEntity
= rTI
.Object0
;
497 if (rTI
.CollisionType
!= UTriggerInfo::Inside
)
500 // Retrieve the door pointer
502 CEntityCL
*pEntity
= NULL
;
504 uint32 doorId
= ((nUserDataDoor
>> 16) & 0xffffffff);
505 uint32 entityId
= ((nUserDataEntity
>> 16) & 0xffffffff);
507 for(uint i
= 0; i
< _Doors
.size(); ++i
)
511 if (pDoor
&& pDoor
->ID
== doorId
)
513 pEntity
= EntitiesMngr
.getEntityByCompressedIndex(entityId
);
516 pDoor
->entityCollide(pEntity
);
525 // ***************************************************************************
526 void CDoorManager::update ()
528 // Check all doors if we have to close
529 for (uint i
= 0; i
< _Doors
.size(); ++i
)
531 SDoor
*pDoor
= _Doors
[i
];
532 pDoor
->checkToClose();