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) 2014 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/>.
23 #include "world_entity.h"
25 #include "world_position_manager.h"
26 #include "gpm_service.h"
29 using namespace NLMISC
;
30 using namespace NLPACS
;
32 #define DUMP_VAR(var) log->displayNL("%28s: %s", #var, toString(var).c_str());
33 #define DUMP_VARPTR(var) log->displayNL("%28s: %s", #var, toStringPtr(var).c_str());
35 /****************************************************************\
36 ****************************************************************
38 ****************************************************************
39 \****************************************************************/
41 // Static entity allocator
42 CBlockMemory
<CWorldEntity
> CWorldEntity::_EntityAllocator
;
46 void registerEntityProperty(const string
&propertyName
, CMirrorPropValue1DS
<T
> *property
, const CEntityId
&id
)
48 // TODO: optimize: use entity index instead of Id, prop index instead of name
49 property
->init( TheDataset
, id
, propertyName
);
53 /// Creates a new entity (new equivalent). This must be initialised later using init();
54 CWorldEntity
* CWorldEntity::create()
56 CWorldEntity
* entity
= _EntityAllocator
.allocate();
59 entity
->ListIterator
= CWorldPositionManager::_EntityList
.insert(CWorldPositionManager::_EntityList
.end(), entity
);
60 entity
->PrimIterator
= CWorldPositionManager::_PrimitivedList
.end();
65 /// Removes an entity (delete equivalent).
66 void CWorldEntity::remove(CWorldEntity
* entity
)
68 CWorldPositionManager::_EntityList
.erase(entity
->ListIterator
);
69 if (entity
->PrimIterator
!= CWorldPositionManager::_PrimitivedList
.end())
71 CWorldPositionManager::_PrimitivedList
.erase(entity
->PrimIterator
);
73 _EntityAllocator
.freeBlock(entity
);
78 /****************************************************************\
80 \****************************************************************/
81 void CWorldEntity::init( const CEntityId
& id
, const TDataSetRow
&index
)
86 // Keep properties local for invisible group entities (aiVision).
87 // This is obsolete, as aiVision are not used anymore. Because these entities were not
88 // in mirror, their property values always stayed in temp storage. All the code was
89 // the same for aiVision and visible entities, i.e. we used the CMirrorPropValueAlice.
90 // Now the 'Alice' version is not needed anymore, because all entities go into
91 // registerEntityProperty().
92 // if ( Id.getType() != RYZOMID::aiVision )
95 registerEntityProperty("X", &X
, id
);
96 registerEntityProperty("Y", &Y
, id
);
97 registerEntityProperty("Z", &Z
, id
);
98 registerEntityProperty("LocalX", &LocalX
, id
);
99 registerEntityProperty("LocalY", &LocalY
, id
);
100 registerEntityProperty("LocalZ", &LocalZ
, id
);
101 registerEntityProperty("Theta", &Theta
, id
);
102 registerEntityProperty("Sheet", &Sheet
, id
);
103 registerEntityProperty("TickPos", &Tick
, id
);
104 registerEntityProperty("Cell", &Cell
, id
);
105 registerEntityProperty("VisionCounter", &VisionCounter
, id
);
106 registerEntityProperty("WhoSeesMe", &WhoSeesMe
, id
);
109 nlwarning("Entity %s Cell is preset to %d which should be 0 or negative, forced to 0", id
.toString().c_str(), Cell());
116 //IsStaticObject = false;
117 //IsInvisible = false;
120 //IsInvisibleToPlayer = false;
125 TempVisionState
= false;
126 TempControlInVision
= false;
127 TempParentInVision
= false;
141 PosInitialised
= false;
142 Continent
= INVALID_CONTINENT_INDEX
;
143 MoveContainer
= NULL
;
145 UsePrimitive
= false;
146 ForceUsePrimitive
= false;
147 ForceDontUsePrimitive
= false;
149 VisionCounter
= (uint8
)0x0;
151 ClosestPlayer
= NULL
;
157 if (id
.getType() == RYZOMID::object
)
161 else if (id
.getType() == RYZOMID::player
)
165 else if (id
.getType() == RYZOMID::trigger
)
169 else if ((id
.getType() >= RYZOMID::bot_ai_begin
) && (id
.getType() <= RYZOMID::bot_ai_end
))
179 // commented, now set by the EGS
180 //WhoSeesMe = 0xffffffff;
184 } // CWorldEntity constructor
186 /****************************************************************\
187 CWorldEntity destructor
188 \****************************************************************/
189 CWorldEntity::~CWorldEntity()
191 // the Primitive should have been removed in the UMoveContainer, and so is already deleted
193 } // CWorldEntity destructor
200 void CWorldEntity::display(NLMISC::CLog
*log
) const
203 log
->displayNL("CWorldEntity::display called on NULL");
205 log
->displayNL("--- Display Entity %s E%u ---", Id
.toString().c_str(), Index
.getIndex());
217 DUMP_VAR(VisionCounter());
218 DUMP_VAR(WhoSeesMe());
219 DUMP_VAR(PatatEntryIndex
);
220 DUMP_VARPTR(CellPtr
);
221 DUMP_VAR(PosInitialised
);
223 DUMP_VARPTR(Primitive
);
224 DUMP_VARPTR(MoveContainer
);
225 DUMP_VAR(UsePrimitive
);
226 DUMP_VAR(ForceUsePrimitive
);
227 DUMP_VAR(ForceDontUsePrimitive
);
229 DUMP_VARPTR((CWorldEntity
*)Previous
);
230 DUMP_VARPTR((CWorldEntity
*)Next
);
231 DUMP_VARPTR((CWorldEntity
*)Parent
);
232 DUMP_VARPTR((CWorldEntity
*)Control
);
234 DUMP_VAR(CheckMotion
);
235 DUMP_VAR(TempVisionState
);
236 DUMP_VAR(RefCounter
);
238 log
->displayNL("--- End of Display ---");
240 if (PlayerInfos
!= NULL
)
241 PlayerInfos
->display(log
);
245 /****************************************************************\
246 create primitive for fiche type entity
247 \****************************************************************/
248 void CWorldEntity::createPrimitive(NLPACS::UMoveContainer
*pMoveContainer
, uint8 worldImage
)
250 UMovePrimitive
*primitive
;
252 if (PrimIterator
!= CWorldPositionManager::_PrimitivedList
.end())
254 CWorldPositionManager::_PrimitivedList
.erase(PrimIterator
);
255 PrimIterator
= CWorldPositionManager::_PrimitivedList
.end();
258 if (!UsePrimitive
&& !ForceUsePrimitive
)
260 nlwarning("Entity %s asked to create a PACS primitive, whereas shouldn't not, abort", Id
.toString().c_str());
264 if (pMoveContainer
== NULL
)
266 nlwarning("pMoveContainer == NULL in createPrimitive()");
270 // if a primitive already exists
271 if (Primitive
!= NULL
)
273 // previous move container must not be null
274 if (MoveContainer
== NULL
)
276 nlwarning("MoveContainer == NULL in createPrimitive()");
280 // check the previous move container is different (otherwise does not create a primitive)
281 if (MoveContainer
== pMoveContainer
)
284 // depending on the type of the previous primitive, creates a copy of it
285 if (Primitive
->isCollisionable())
287 primitive
= pMoveContainer
->addCollisionablePrimitive(CWorldPositionManager::_FirstDynamicWorldImage
, CWorldPositionManager::_NbDynamicWorldImages
, Primitive
);
291 primitive
= pMoveContainer
->addNonCollisionablePrimitive(Primitive
);
294 // removes previous primitive
295 MoveContainer
->removePrimitive(Primitive
);
297 // and set new one as entity primitive
298 Primitive
= primitive
;
299 MoveContainer
= pMoveContainer
;
301 if (Primitive
== NULL
)
303 MoveContainer
= NULL
;
304 nlwarning("Can't create PACS primitive for entity %s", Id
.toString().c_str());
308 PrimIterator
= CWorldPositionManager::_PrimitivedList
.insert(CWorldPositionManager::_PrimitivedList
.end(), this);
315 MoveContainer
= NULL
;
317 const CGpmSheets::CSheet
*sheet
= CGpmSheets::lookup(CSheetId(Sheet()));
319 float primRadius
= 0.5f
;
320 float primHeight
= 2.0f
;
324 primRadius
= sheet
->Radius
* sheet
->Scale
;
325 primHeight
= sheet
->Height
* sheet
->Scale
;
328 primitive
= pMoveContainer
->addNonCollisionablePrimitive();
330 if (primitive
== NULL
)
332 nlwarning("Can't create PACS primitive for entity %s", Id
.toString().c_str());
335 primitive
->UserData
= ((uint64
)(Index
.getIndex()) << 16);
336 //nldebug("Set entity E%u to %" NL_I64 "d", Index.getIndex(), primitive->UserData);
337 primitive
->setPrimitiveType( UMovePrimitive::_2DOrientedCylinder
);
338 primitive
->setReactionType( UMovePrimitive::Slide
);
339 primitive
->setTriggerType( UMovePrimitive::NotATrigger
);
340 primitive
->setCollisionMask( 0xffffffff );
341 primitive
->setOcclusionMask( 0x00000000 );
342 primitive
->setObstacle( false );
343 primitive
->setAbsorbtion( 0 );
344 primitive
->setHeight( primHeight
);
345 primitive
->setRadius( primRadius
-0.1f
); // decrease primitive usable radius to lessen pacs load (avoid collision test)
347 Primitive
= primitive
;
348 MoveContainer
= pMoveContainer
;
350 PrimIterator
= CWorldPositionManager::_PrimitivedList
.insert(CWorldPositionManager::_PrimitivedList
.end(), this);
353 /****************************************************************\
355 \****************************************************************/
356 void CWorldEntity::removePrimitive()
358 if (PrimIterator
!= CWorldPositionManager::_PrimitivedList
.end())
360 CWorldPositionManager::_PrimitivedList
.erase(PrimIterator
);
361 PrimIterator
= CWorldPositionManager::_PrimitivedList
.end();
364 if (MoveContainer
!= NULL
&& Primitive
!= NULL
)
366 MoveContainer
->removePrimitive(Primitive
);
368 MoveContainer
= NULL
;
370 else if (MoveContainer
!= NULL
&& Primitive
== NULL
|| MoveContainer
== NULL
&& Primitive
!= NULL
)
372 nlwarning("Entity %s asked to remove PACS primitive, unable to continue (MoveContainer=%p, Primitive=%p)", Id
.toString().c_str(), MoveContainer
, Primitive
);
378 /****************************************************************\
379 updatePositionUsingMovePrimitive
380 \****************************************************************/
381 void CWorldEntity::updatePositionUsingMovePrimitive(uint wi
)
383 if (Primitive
== NULL
|| Continent
== INVALID_CONTINENT_INDEX
|| Continent
== NO_CONTINENT_INDEX
)
386 NLPACS::UGlobalRetriever
*retriever
= CWorldPositionManager::getContinentContainer().getRetriever(Continent
);
388 if (retriever
== NULL
)
391 NLPACS::UGlobalPosition gp
;
392 Primitive
->getGlobalPosition(gp
, wi
);
394 bool interior
= retriever
->isInterior(gp
);
395 bool local
= localMotion();
398 bool water
= retriever
->isWaterPosition(gp
, dummy
);
400 NLMISC::CVectorD pos
= Primitive
->getFinalPosition(wi
);
402 setPosition((sint32
)(pos
.x
*1000), (sint32
)(pos
.y
*1000), (sint32
)(pos
.z
*1000), local
, interior
, water
);
409 /****************************************************************\
410 ****************************************************************
412 ****************************************************************
413 \****************************************************************/
415 // Static player allocator
416 CBlockMemory
<CPlayerInfos
> CPlayerInfos::_PlayerAllocator
;
419 void CPlayerInfos::display(CLog
*log
) const
422 log
->displayNL("CPlayerInfos::display called on NULL");
424 log
->displayNL("--- Display PlayerInfos %s E%u ---", _PlayerId
.toString().c_str(), (Entity
!= NULL
? Entity
->Index
.getIndex() : 0));
426 DUMP_VAR(FeId
.get());
427 DUMP_VAR(LastVisionTick
);
428 DUMP_VAR(DelayVision
);
429 DUMP_VAR(ActivateSlot0
);
430 DUMP_VAR(DesactivateSlot0
);
431 DUMP_VAR(Slot0Active
);
432 DUMP_VAR(WhoICanSee
);
434 #ifdef RECORD_LAST_PLAYER_POSITIONS
436 log
->displayNL("Last positions recorded:");
438 for (i
=0; i
<DistanceHistory
.size(); ++i
)
439 log
->displayNL("(%+9.3f,%+9.3f,%+9.3f) %d ticks", DistanceHistory
[i
].first
.x
, DistanceHistory
[i
].first
.y
, DistanceHistory
[i
].first
.z
, DistanceHistory
[i
].second
);
443 log
->displayNL("--- End of Display ---");