1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
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 #ifndef RY_ENTITY_MATRIX_H
20 #define RY_ENTITY_MATRIX_H
22 #include "entity_list_link.h"
23 #include "area_geometry.h"
24 #include "phrase_manager/phrase_utilities_functions.h"
25 #include "entity_manager/entity_base.h"
28 /***************************
31 This system was designed as a template to support special entities such as harvest deposit explosions,...
32 In fact, it is only used with CEntityBase. As special features had to be included in it, we use a lot of methods very specific to CEntityBase
33 So This class must be reworked when the new EGS classes will be designed.
35 trap 14.12.2004 : I have deleted the template argument of the CEntityMatrix class. This class is no more template.
37 ****************************/
41 /// helper for coords conversion
42 /// convert world coords to matrix coords ( >> 14 is approximatively /16000 but faster )
43 inline static uint16
WorldtoMatrixDistance( uint32 dist
)
45 return uint16(dist
>> 14);
47 inline static uint8
WorldXtoMatrixX( sint32 x
)
49 return uint8(x
>> 14);
51 inline static uint8
WorldYtoMatrixY( sint32 y
)
53 return uint8((-y
) >> 14);
56 /*************************************************************
59 They represent an area of an entity matrix to be scanned
60 Linear pattern tables use a better RAM access patern than random access tables and should be used whenever possible
61 For template use, all pattern class must present the following method:
62 - uint16 size() : return the size in rows of the pattern
63 - uint16 runLength(uint row) : return the runLength of the specified row
64 - sint16 startDx(uint row) : return a value to add to an X coord to go to the beginning of the current row from the end of the previous
66 **************************************************************/
69 /// This class uses a vector of horizontal run lengths to represent a pattern
70 /// The pattern represented by the data is assumed to be symetrical in both x and y.
71 /// it is based on linear tables. To avoid the generation of too many tables, the choice of the best iterator is done with only 1 parameter
72 /// So it is perfect for circles, but not for most other patterns ( rectangles for example are better selected by width and length )
73 class CEntityMatrixPatternSymetrical
76 /// ctor, used during init only
77 inline CEntityMatrixPatternSymetrical(uint32
*runLengths
,uint32 count
)
80 for(uint i
=0;i
<count
;++i
)
82 _Rows
.push_back(CRow(runLengths
[i
],lastRun
));
83 lastRun
=runLengths
[i
];
87 static void initMatrixPatterns();
88 /// find the best Disc pattern according to the distance chosen
89 inline static CEntityMatrixPatternSymetrical
* bestDiscPattern( uint16 distInMeters
)
92 nlassert(distInMeters
< _DiscPatterns
.size());
94 return _DiscPatterns
[ distInMeters
];
98 inline uint16
size() const{ return (uint16
)_Rows
.size(); }
99 inline sint16
startDx(uint row
) const
102 nlassert( row
< _Rows
.size() );
104 return _Rows
[row
].StartDx
;
106 inline uint16
runLength(uint row
) const
109 nlassert( row
< _Rows
.size() );
111 return _Rows
[row
].RunLength
;
115 /// struct representing a row in our pattern
119 inline CRow(uint32 runLength
, sint32 previousRunLength
)
121 RunLength
=(uint16
)(runLength
-1); // we assume all runs are at least 1 unit long - this is the excess
122 StartDx
=(sint16
)(-(previousRunLength
/2)-(((sint32
)runLength
)/2));
125 nlassert(runLength
>0); // runs must be at least 1 unit long
126 nlassert(runLength
<32768); // this is the limit where StartDx runs out of bits
127 nlassert(previousRunLength
>=0);
128 nlassert(previousRunLength
<32768);
131 // length of a run in this row
133 // dx to add to the last x of the previous line to go to the beginning of this row
137 /// the rows of the pattern
138 std::vector
<CRow
> _Rows
;
140 /// the table of disc patterns
141 static std::vector
<CEntityMatrixPatternSymetrical
*> _DiscPatterns
;
144 /// This pattern represents a rectangle aligned with The X and Y axis
145 /// the width is the norm of the side on the X axis
146 /// the height is the norm of the side on the Y axis
147 /// These pattern are built "on the fly", no tables are needed
148 class CEntityMatrixPatternRect
151 inline CEntityMatrixPatternRect( uint32 width
, uint32 height
)
153 // first get the width in matrix coords
154 _RunLength
= WorldtoMatrixDistance( width
);
155 // if the runlength is even, add 3 ( 1 cell for the center cell and 2 because we dont know where the center is in the cell. Remove 1 because we just want the excess )
156 if ( (_RunLength
& 1) == 0 )
158 // if the runlength is odd, add 2( 2 because we dont know where the center is in the cell. We alredy have a center. Remove 1 because we just want the excess )
163 _Size
= WorldtoMatrixDistance( height
);
164 if ( (_Size
& 1) == 0 )
169 _StartDx
= - (sint16
)_RunLength
;
173 inline uint16
size() const
177 inline sint16
startDx(uint row
) const
181 inline uint16
runLength(uint row
) const
195 /// This pattern represents a square border aligned with The X and Y axis :
204 /// the cellWidth is the width in cell of the border
205 /// These pattern are built "on the fly", no tables are needed
206 class CEntityMatrixPatternBorder
209 inline CEntityMatrixPatternBorder( uint8 cellSide
)
212 _StartDx
= sint16(1) - (sint16
)_Side
;
216 inline uint16
size() const
220 inline sint16
startDx(uint row
) const
224 inline uint16
runLength(uint row
) const
226 if ( row
== 0 || row
== uint ( _Side
-1) )
239 * Matrix used to dispatch all the entities in its entries
240 * The matrix size is 256*256. Each entry contains a linked list of entities ( see CEntityListLink )
241 * This way it is much faster to get all the entities which are within a specific distance from a point
242 * Entities position in the matrix must be periodically updated
243 * \author Nicolas Brigand
244 * \author Nevrax France
251 /// iterator used to iterate through an entity matrix cells using a specific pattern
252 /// TEntity is the entity type
253 /// TPattern is the used pattern type
254 template <class TPattern
>
259 /// ctor only used before operator = in STL-like for loops
260 inline CCellIterator(){}
262 /// matrix is the observed matrix, pattern is the pattern used to iterate
263 /// x and y are the world coords of the center point
264 inline CCellIterator( CEntityMatrix
*matrix
,TPattern
*pattern
,sint32 x
, sint32 y
)
265 :_Matrix(matrix
),_Pattern(pattern
)
268 nlassert(_Pattern
!=NULL
);
269 nlassert(_Pattern
->size()>0);
270 nlassert(_Pattern
->size()<32768); // a numeric over-run limit
271 nlassert(_Matrix
!=NULL
);
273 // setup the iterator to point to the start of the pattern and setup properties accordingly
275 _RunLengthRemaining
= _Pattern
->runLength(0);
276 _X
= uint8( WorldXtoMatrixX(x
) - (sint16
)(pattern
->runLength(0)/2) );
277 _Y
= uint8( WorldYtoMatrixY(y
) - (sint16
)(pattern
->size()/2) );
281 inline CEntityListLink
<CEntityBase
>*operator*()
283 return & ( (*_Matrix
)[_Y
][_X
] );
285 inline CCellIterator
&operator++()
288 // make sure we aren'TEntity trying to access an uninitialised iterator
289 nlassert(_IndexInPattern
< _Pattern
->size());
291 // if we're not at the end of the current run continue run else move on to next line
292 if (_RunLengthRemaining
!=0)
294 --_RunLengthRemaining
;
300 // check if end not reached
301 if ( _IndexInPattern
< _Pattern
->size() )
303 _RunLengthRemaining
= _Pattern
->runLength(_IndexInPattern
);
304 _X
= uint8( _X
+ _Pattern
->startDx(_IndexInPattern
) );
312 inline bool end() const
314 return _IndexInPattern
>= _Pattern
->size();
318 /// coords of the current cells in the matrix
321 // matrix used by the iterator
322 CEntityMatrix
* _Matrix
;
323 /// current pattern used
325 /// iterator in the used pattern (used to see in which row of the pattern we are)
326 uint32 _IndexInPattern
;
327 /// remaining run length
328 uint32 _RunLengthRemaining
;
331 template <class TPattern
>
332 class CCellIteratorBorder
: public CCellIterator
<TPattern
>
335 /// ctor only used before operator = in STL-like for loops
336 inline CCellIteratorBorder(){}
338 /// matrix is the observed matrix, pattern is the pattern used to iterate
339 /// x and y are the world coords of the center point
340 inline CCellIteratorBorder( CEntityMatrix
*matrix
,TPattern
*pattern
,sint32 x
, sint32 y
)
341 :CCellIterator
<TPattern
>(matrix
,pattern
,x
,y
)
344 nlassert(this->_Pattern
!=NULL
);
345 nlassert(this->_Pattern
->size()>0);
346 nlassert(this->_Pattern
->size()<32768); // a numeric over-run limit
347 nlassert(this->_Matrix
!=NULL
);
349 // setup the iterator to point to the start of the pattern and setup properties accordingly
350 this->_IndexInPattern
= 0;
351 this->_RunLengthRemaining
= this->_Pattern
->runLength(0);
352 this->_X
= uint8( WorldXtoMatrixX(x
) - (sint16
)(pattern
->runLength(0)/2) );
353 this->_Y
= uint8( WorldYtoMatrixY(y
) - (sint16
)(pattern
->size()/2) );
355 inline CCellIteratorBorder
&operator++()
358 // make sure we aren'TEntity trying to access an uninitialised iterator
359 nlassert(this->_IndexInPattern
< this->_Pattern
->size());
362 if ( this->_RunLengthRemaining
!=0 )
364 if ( this->_Pattern
->runLength(this->_IndexInPattern
) == 1 )
366 --this->_RunLengthRemaining
;
367 this->_X
+= this->_Pattern
->size() - 1;
371 --this->_RunLengthRemaining
;
377 ++this->_IndexInPattern
;
378 // check if end not reached
379 if ( this->_IndexInPattern
< this->_Pattern
->size() )
381 this->_RunLengthRemaining
= this->_Pattern
->runLength(this->_IndexInPattern
);
382 this->_X
= uint8( this->_X
+ this->_Pattern
->startDx(this->_IndexInPattern
) );
395 -----------------------------------------------------------------------------------------------------
396 class CAIEntityMatrix<T>::CEntityIteratorTemplate
397 class CAIEntityMatrix<T>::CEntityIteratorLinear
398 class CAIEntityMatrix<T>::CEntityIteratorRandom
400 This class provides an iterator for iterating across the entities listed in the cells of a matrix
401 '_matrix' following the pattern described by '_Pattern'
403 The class is composed of a CCellIterator' _CellIt' responsible for iterating across the matrix
404 and an entity pointer '_Entity' used for iterating over the entities in each matrix cell
406 Note that unlinking, moving or deleting the entity refferenced by a CEntityIteratorLinear iterator
408 -----------------------------------------------------------------------------------------------------
410 template <class TPattern
, class TCellIt
>
411 class CEntityIteratorTemplate
414 inline CEntityIteratorTemplate(){}
415 inline CEntityIteratorTemplate(CEntityMatrix
*matrix
,
419 : _CellIt(matrix
,pattern
,centerX
,centerY
),_CenterPosX(double(centerX
)/1000.0),_CenterPosY(double(centerY
)/1000.0)
421 // get a pointer to the list link
426 inline CEntityBase
&operator*()
429 // make sure we aren't trying to access passed the end of list
432 CEntityBase
* entity
= dynamic_cast<CEntityBase
*>(_Entity
->entity());
437 inline const CEntityIteratorTemplate
&operator++()
440 // if you are on a breakpoint here it is because you've tried to do a ++ on an iterator
441 nlassert(!_CellIt
.end());
443 // repeat the following loop until either we come to the end of the cell iterator or we find a valid entity
446 // try to get the next entity in the cell
447 _Entity
=_Entity
->next();
448 if (_Entity
==*_CellIt
)
450 // we're at the end of the entity list for this cell so try to find another cell with a valid entity
455 while ( !_CellIt
.end()
456 && (*_CellIt
)->unlinked());
458 _Entity
=(*_CellIt
)->next();
461 while ( !_CellIt
.end()
462 && ( _Entity
->unlinked()
463 || ! testValidity(_Entity
->entity()) ) );
464 // as cells are tiled over the world, we need to check if our entity have a real good match with the scanned position.
467 // method for testing iterator for end of current sequence
470 // the following can only happen if there are no more entites in cell and no more deltas in cell iterator tbl
471 return _CellIt
.end();
473 inline float getDistance(){return _Distance
;}
476 /// test the validity of an entity
477 virtual bool testValidity( CEntityBase
* entity
) = 0;
479 TCellIt _CellIt
; // the cell iterator
480 const CEntityListLink
<CEntityBase
>* _Entity
; // which entity are we pointing at (within the cell)
485 // distance to center
489 /// iterator used to get entities in a disc around a point
490 class CEntityIteratorDisc
: public CEntityIteratorTemplate
<CEntityMatrixPatternSymetrical
, CCellIterator
<CEntityMatrixPatternSymetrical
> >
493 inline CEntityIteratorDisc(){}
494 inline CEntityIteratorDisc(CEntityMatrix
*matrix
,CEntityMatrixPatternSymetrical
*pattern
,
498 :CEntityIteratorTemplate
<CEntityMatrixPatternSymetrical
, CCellIterator
<CEntityMatrixPatternSymetrical
> >
504 _RadiusSquare(radiusSquare
){}
508 inline bool testValidity( CEntityBase
* entity
)
512 nlwarning("CEntityIteratorDisc::testValidity entity == 0 !!");
515 double dx
= double(entity
->getState().X
) /1000.0 - _CenterPosX
;
516 double dy
= double(entity
->getState().Y
) /1000.0 - _CenterPosY
;
517 double distanceSquare
= dx
* dx
+ dy
* dy
;
518 if ( distanceSquare
<= _RadiusSquare
)
520 _Distance
= (float)sqrt(distanceSquare
);
528 double _RadiusSquare
;
531 /// iterator used to get entities in a truncated cone ( a trapezoid in fact )
532 class CEntityIteratorCone
: public CEntityIteratorTemplate
<CEntityMatrixPatternRect
, CCellIterator
<CEntityMatrixPatternRect
> >
535 inline CEntityIteratorCone(){}
536 inline CEntityIteratorCone(CEntityMatrix
*matrix
,
537 CEntityMatrixPatternRect
*pattern
,
538 const CAreaQuad
<sint32
> * cone
,
539 const CAreaCoords
<sint32
> & center
,
540 const CEntityBase
* mainTarget
)
541 :CEntityIteratorTemplate
<CEntityMatrixPatternRect
, CCellIterator
<CEntityMatrixPatternRect
> >
548 _MainTarget(mainTarget
)
556 inline bool testValidity( CEntityBase
* entity
)
560 nlwarning("CEntityIteratorCone::testValidity entity == 0 !!");
564 if ( entity
!= _MainTarget
&& _Cone
->contains( CAreaCoords
<sint32
>(entity
->getState().X
,entity
->getState().Y
) ) )
566 double dx
= double(entity
->getState().X
) /1000.0 - _CenterPosX
;
567 double dy
= double(entity
->getState().Y
) /1000.0 - _CenterPosY
;
568 double distanceSquare
= dx
* dx
+ dy
* dy
;
569 _Distance
= (float)sqrt(distanceSquare
);
574 const CAreaQuad
<sint32
> * _Cone
;
575 const CEntityBase
* _MainTarget
;
578 /// iterator used to get entities in a disc around a point
579 class CEntityIteratorChainCenter
: public CEntityIteratorDisc
582 inline CEntityIteratorChainCenter(){}
583 inline CEntityIteratorChainCenter(CEntityMatrix
*matrix
,
584 CEntityMatrixPatternSymetrical
*pattern
,
588 const std::vector
<CEntityBase
*> * addedEntities
,
589 ACTNATURE::TActionNature nature
,
590 const TDataSetRow
& actor
,
591 const CEntityBase
* mainTarget
593 :CEntityIteratorDisc(matrix
,pattern
,posX
,posY
,radiusSquare
),
594 _AddedEntities(addedEntities
),_ActorRowId(actor
),_Nature(nature
),_MainTarget(mainTarget
){}
598 inline bool testValidity( CEntityBase
* entity
)
602 nlwarning("CEntityIteratorChainCenter::testValidity entity == 0 !!");
606 for ( uint i
= 0; i
< _AddedEntities
->size(); i
++ )
608 if ( (*_AddedEntities
)[i
] == entity
)
612 const bool mainTarget
= (entity
== _MainTarget
);
617 case ACTNATURE::FIGHT
:
618 if ( ! PHRASE_UTILITIES::testOffensiveActionAllowed(_ActorRowId
, entity
->getEntityRowId(), dummy
, mainTarget
) )
624 case ACTNATURE::OFFENSIVE_MAGIC
:
625 case ACTNATURE::CURATIVE_MAGIC
:
626 if ( ! PHRASE_UTILITIES::validateSpellTarget(_ActorRowId
, entity
->getEntityRowId(), _Nature
, dummy
, mainTarget
) )
633 nlwarning("<CEntityIteratorChainCenter::testValidity> bad action nature: %s", ACTNATURE::toString(_Nature
).c_str());
636 return CEntityIteratorDisc::testValidity( entity
);
639 const std::vector
<CEntityBase
*>* _AddedEntities
;
640 ACTNATURE::TActionNature _Nature
;
641 TDataSetRow _ActorRowId
;
642 const CEntityBase
* _MainTarget
;
647 /// iterator used to get entities in a disc around a point
648 class CEntityIteratorChainBorder
: public CEntityIteratorTemplate
<CEntityMatrixPatternBorder
, CCellIteratorBorder
<CEntityMatrixPatternBorder
> >
651 inline CEntityIteratorChainBorder(){}
652 inline CEntityIteratorChainBorder(CEntityMatrix
*matrix
,
653 CEntityMatrixPatternBorder
*pattern
,
657 const std::vector
<CEntityBase
*> * entities
,
658 ACTNATURE::TActionNature nature
,
659 const TDataSetRow
& actor
,
660 const CEntityBase
* mainTarget
662 :CEntityIteratorTemplate
<CEntityMatrixPatternBorder
, CCellIteratorBorder
<CEntityMatrixPatternBorder
> >
668 _RadiusSquare(radiusSquare
),_AddedEntities(entities
),_ActorRowId(actor
),_Nature(nature
),_MainTarget(mainTarget
){}
672 inline bool testValidity( CEntityBase
* entity
)
676 nlwarning("CEntityIteratorChainBorder::testValidity entity == 0 !!");
680 for ( uint i
= 0; i
< _AddedEntities
->size(); i
++ )
682 if ( (*_AddedEntities
)[i
] == entity
)
686 const bool mainTarget
= (entity
== _MainTarget
);
691 case ACTNATURE::FIGHT
:
692 if ( ! PHRASE_UTILITIES::testOffensiveActionAllowed(_ActorRowId
, entity
->getEntityRowId(), dummy
, mainTarget
) )
698 case ACTNATURE::OFFENSIVE_MAGIC
:
699 case ACTNATURE::CURATIVE_MAGIC
:
700 if ( ! PHRASE_UTILITIES::validateSpellTarget(_ActorRowId
, entity
->getEntityRowId(), _Nature
, dummy
, mainTarget
) )
707 nlwarning("<CEntityIteratorChainBorder::testValidity> bad action nature: %s", ACTNATURE::toString(_Nature
).c_str());
710 double dx
= double(entity
->getState().X
) /1000.0 - _CenterPosX
;
711 double dy
= double(entity
->getState().Y
) /1000.0 - _CenterPosY
;
712 double distanceSquare
= dx
* dx
+ dy
* dy
;
713 if ( distanceSquare
<= _RadiusSquare
)
715 _Distance
= (float)sqrt(distanceSquare
);
724 double _RadiusSquare
;
725 const std::vector
<CEntityBase
*> * _AddedEntities
;
726 ACTNATURE::TActionNature _Nature
;
727 TDataSetRow _ActorRowId
;
728 const CEntityBase
* _MainTarget
;
737 /// A line of the matrix
741 /// one and only accessor
742 inline CEntityListLink
<CEntityBase
> &operator[](uint8 x
) { return Line
[x
]; }
745 CEntityListLink
<CEntityBase
> Line
[256];
749 /// link an entity to the matrix
750 inline void linkToMatrix(sint32 x
, sint32 y
, CEntityListLink
<CEntityBase
> & link
)
752 // too slow H_AUTO(linkToMatrix);
753 link
.link(_Matrix
[(uint8
)WorldYtoMatrixY(y
)] [(uint8
)WorldXtoMatrixX(x
)]);
757 inline CEntityIteratorDisc
beginEntitiesInDisc(CEntityMatrixPatternSymetrical
* pattern
,sint32 x
, sint32 y
,double radiusSquare
)
759 CEntityIteratorDisc
newIt(this,pattern
,x
,y
,radiusSquare
);
764 inline CEntityIteratorCone
beginEntitiesInCone(CEntityMatrixPatternRect
* pattern
, const CAreaQuad
<sint32
> * cone
, const CAreaCoords
<sint32
> & center
, const CEntityBase
* mainTarget
)
766 CEntityIteratorCone
newIt(this,pattern
, cone
, center
, mainTarget
);
771 inline CEntityIteratorChainCenter
beginEntitiesInChainCenter(CEntityMatrixPatternSymetrical
* pattern
,sint32 x
, sint32 y
,double radiusSquare
, const std::vector
<CEntityBase
*> *addedEntities
, ACTNATURE::TActionNature nature
, const TDataSetRow
& actor
, const CEntityBase
* mainTarget
)
773 CEntityIteratorChainCenter
newIt(this,pattern
,x
,y
,radiusSquare
,addedEntities
, nature
, actor
, mainTarget
);
778 inline CEntityIteratorChainBorder
beginEntitiesInChainBorder(CEntityMatrixPatternBorder
* pattern
,sint32 x
, sint32 y
,double radiusSquare
, const std::vector
<CEntityBase
*> *addedEntities
, ACTNATURE::TActionNature nature
, const TDataSetRow
& actor
, const CEntityBase
* mainTarget
)
780 CEntityIteratorChainBorder
newIt(this,pattern
,x
,y
,radiusSquare
,addedEntities
, nature
, actor
, mainTarget
);
786 // table lookup operator - should be used as myMatrix[y][x]
787 inline CMatrixLine
& operator[](uint8 y
)
793 /// the matrix data. WARNING acces is _Matrix[y][x]
794 CMatrixLine _Matrix
[256];
798 extern CEntityMatrix EntityMatrix
;
800 #endif // RY_ENTITY_MATRIX_H
802 /* End of entity_matrix.h */