khanat-code-old/code/ryzom/server/src/gpm_service/world_entity.cpp

440 lines
13 KiB
C++

// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "stdpch.h"
#include "world_entity.h"
#include "sheets.h"
#include "world_position_manager.h"
#include "gpm_service.h"
using namespace std;
using namespace NLMISC;
using namespace NLPACS;
#define DUMP_VAR(var) log->displayNL("%28s: %s", #var, toString(var).c_str());
#define DUMP_VARPTR(var) log->displayNL("%28s: %s", #var, toStringPtr(var).c_str());
/****************************************************************\
****************************************************************
CWorldEntity
****************************************************************
\****************************************************************/
// Static entity allocator
CBlockMemory<CWorldEntity> CWorldEntity::_EntityAllocator;
template<class T>
void registerEntityProperty(const string &propertyName, CMirrorPropValue1DS<T> *property, const CEntityId &id)
{
// TODO: optimize: use entity index instead of Id, prop index instead of name
property->init( TheDataset, id, propertyName );
}
/// Creates a new entity (new equivalent). This must be initialised later using init();
CWorldEntity* CWorldEntity::create()
{
CWorldEntity* entity = _EntityAllocator.allocate();
if (entity != NULL)
{
entity->ListIterator = CWorldPositionManager::_EntityList.insert(CWorldPositionManager::_EntityList.end(), entity);
entity->PrimIterator = CWorldPositionManager::_PrimitivedList.end();
}
return entity;
}
/// Removes an entity (delete equivalent).
void CWorldEntity::remove(CWorldEntity* entity)
{
CWorldPositionManager::_EntityList.erase(entity->ListIterator);
if (entity->PrimIterator != CWorldPositionManager::_PrimitivedList.end())
{
CWorldPositionManager::_PrimitivedList.erase(entity->PrimIterator);
}
_EntityAllocator.free(entity);
}
/****************************************************************\
init
\****************************************************************/
void CWorldEntity::init( const CEntityId& id, const TDataSetRow &index )
{
Id = id;
Index = index;
// Keep properties local for invisible group entities (aiVision).
// This is obsolete, as aiVision are not used anymore. Because these entities were not
// in mirror, their property values always stayed in temp storage. All the code was
// the same for aiVision and visible entities, i.e. we used the CMirrorPropValueAlice.
// Now the 'Alice' version is not needed anymore, because all entities go into
// registerEntityProperty().
// if ( Id.getType() != RYZOMID::aiVision )
// {
registerEntityProperty("X", &X, id);
registerEntityProperty("Y", &Y, id);
registerEntityProperty("Z", &Z, id);
registerEntityProperty("LocalX", &LocalX, id);
registerEntityProperty("LocalY", &LocalY, id);
registerEntityProperty("LocalZ", &LocalZ, id);
registerEntityProperty("Theta", &Theta, id);
registerEntityProperty("Sheet", &Sheet, id);
registerEntityProperty("TickPos", &Tick, id);
registerEntityProperty("Cell", &Cell, id);
registerEntityProperty("VisionCounter", &VisionCounter, id);
registerEntityProperty("WhoSeesMe", &WhoSeesMe, id);
if (Cell > 0)
{
nlwarning("Entity %s Cell is preset to %d which should be 0 or negative, forced to 0", id.toString().c_str(), Cell());
Cell = 0;
}
// }
// else
// Cell = -1;
//IsStaticObject = false;
//IsInvisible = false;
//IsAgent = false;
//IsTrigger = false;
//IsInvisibleToPlayer = false;
RefCounter = 0;
TickLock = 0;
TempVisionState = false;
TempControlInVision = false;
TempParentInVision = false;
HasVision = false;
Previous = NULL;
Next = NULL;
PlayerInfos = NULL;
Parent = NULL;
Control = NULL;
PosInitialised = false;
Continent = INVALID_CONTINENT_INDEX;
MoveContainer = NULL;
Primitive = NULL;
UsePrimitive = false;
ForceUsePrimitive = false;
ForceDontUsePrimitive = false;
VisionCounter = (uint8)0x0;
PlayersSeeingMe = 0;
ClosestPlayer = NULL;
CellPtr = NULL;
PatatEntryIndex = 0;
if (id.getType() == RYZOMID::object )
{
_Type = Object;
}
else if (id.getType() == RYZOMID::player)
{
_Type = Player;
}
else if (id.getType() == RYZOMID::trigger)
{
_Type = Trigger;
}
else if ( (id.getType() >= RYZOMID::npc ) || ( id.getType() <= RYZOMID::flora) )
{
_Type = AI;
}
else
{
_Type = Unknown;
}
// commented, now set by the EGS
//WhoSeesMe = 0xffffffff;
CheckMotion = true;
} // CWorldEntity constructor
/****************************************************************\
CWorldEntity destructor
\****************************************************************/
CWorldEntity::~CWorldEntity()
{
// the Primitive should have been removed in the UMoveContainer, and so is already deleted
} // CWorldEntity destructor
/**
* Display debug
*/
void CWorldEntity::display(NLMISC::CLog *log) const
{
if (this == NULL)
log->displayNL("CWorldEntity::display called on NULL");
log->displayNL("--- Display Entity %s E%u ---", Id.toString().c_str(), Index.getIndex());
DUMP_VAR(X());
DUMP_VAR(Y());
DUMP_VAR(Z());
DUMP_VAR(LocalX());
DUMP_VAR(LocalY());
DUMP_VAR(LocalZ());
DUMP_VAR(Theta());
DUMP_VAR(Sheet());
DUMP_VAR(Tick());
DUMP_VAR(Cell());
DUMP_VAR(VisionCounter());
DUMP_VAR(WhoSeesMe());
DUMP_VAR(PatatEntryIndex);
DUMP_VARPTR(CellPtr);
DUMP_VAR(PosInitialised);
DUMP_VAR(Continent);
DUMP_VARPTR(Primitive);
DUMP_VARPTR(MoveContainer);
DUMP_VAR(UsePrimitive);
DUMP_VAR(ForceUsePrimitive);
DUMP_VAR(ForceDontUsePrimitive);
DUMP_VAR(TickLock);
DUMP_VARPTR((CWorldEntity*)Previous);
DUMP_VARPTR((CWorldEntity*)Next);
DUMP_VARPTR((CWorldEntity*)Parent);
DUMP_VARPTR((CWorldEntity*)Control);
DUMP_VAR(HasVision);
DUMP_VAR(CheckMotion);
DUMP_VAR(TempVisionState);
DUMP_VAR(RefCounter);
log->displayNL("--- End of Display ---");
if (PlayerInfos != NULL)
PlayerInfos->display(log);
}
/****************************************************************\
create primitive for fiche type entity
\****************************************************************/
void CWorldEntity::createPrimitive(NLPACS::UMoveContainer *pMoveContainer, uint8 worldImage)
{
UMovePrimitive *primitive;
if (PrimIterator != CWorldPositionManager::_PrimitivedList.end())
{
CWorldPositionManager::_PrimitivedList.erase(PrimIterator);
PrimIterator = CWorldPositionManager::_PrimitivedList.end();
}
if (!UsePrimitive && !ForceUsePrimitive)
{
nlwarning("Entity %s asked to create a PACS primitive, whereas shouldn't not, abort", Id.toString().c_str());
return;
}
if (pMoveContainer == NULL)
{
nlwarning("pMoveContainer == NULL in createPrimitive()");
return;
}
// if a primitive already exists
if (Primitive != NULL)
{
// previous move container must not be null
if (MoveContainer == NULL)
{
nlwarning("MoveContainer == NULL in createPrimitive()");
return;
}
// check the previous move container is different (otherwise does not create a primitive)
if (MoveContainer == pMoveContainer)
return;
// depending on the type of the previous primitive, creates a copy of it
if (Primitive->isCollisionable())
{
primitive = pMoveContainer->addCollisionablePrimitive(CWorldPositionManager::_FirstDynamicWorldImage, CWorldPositionManager::_NbDynamicWorldImages, Primitive);
}
else
{
primitive = pMoveContainer->addNonCollisionablePrimitive(Primitive);
}
// removes previous primitive
MoveContainer->removePrimitive(Primitive);
// and set new one as entity primitive
Primitive = primitive;
MoveContainer = pMoveContainer;
if (Primitive == NULL)
{
MoveContainer = NULL;
nlwarning("Can't create PACS primitive for entity %s", Id.toString().c_str());
return;
}
PrimIterator = CWorldPositionManager::_PrimitivedList.insert(CWorldPositionManager::_PrimitivedList.end(), this);
// and leave...
return;
}
Primitive = NULL;
MoveContainer = NULL;
const CSheets::CSheet *sheet = CSheets::lookup(CSheetId(Sheet()));
float primRadius = 0.5f;
float primHeight = 2.0f;
if (sheet != NULL)
{
primRadius = sheet->Radius * sheet->Scale;
primHeight = sheet->Height * sheet->Scale;
}
primitive = pMoveContainer->addNonCollisionablePrimitive();
if (primitive == NULL)
{
nlwarning("Can't create PACS primitive for entity %s", Id.toString().c_str());
return;
}
primitive->UserData = ((uint64)(Index.getIndex()) << 16);
//nldebug("Set entity E%u to %"NL_I64"d", Index.getIndex(), primitive->UserData);
primitive->setPrimitiveType( UMovePrimitive::_2DOrientedCylinder );
primitive->setReactionType( UMovePrimitive::Slide );
primitive->setTriggerType( UMovePrimitive::NotATrigger );
primitive->setCollisionMask( 0xffffffff );
primitive->setOcclusionMask( 0x00000000 );
primitive->setObstacle( false );
primitive->setAbsorbtion( 0 );
primitive->setHeight( primHeight );
primitive->setRadius( primRadius-0.1f ); // decrease primitive usable radius to lessen pacs load (avoid collision test)
Primitive = primitive;
MoveContainer = pMoveContainer;
PrimIterator = CWorldPositionManager::_PrimitivedList.insert(CWorldPositionManager::_PrimitivedList.end(), this);
}
/****************************************************************\
removePrimitive
\****************************************************************/
void CWorldEntity::removePrimitive()
{
if (PrimIterator != CWorldPositionManager::_PrimitivedList.end())
{
CWorldPositionManager::_PrimitivedList.erase(PrimIterator);
PrimIterator = CWorldPositionManager::_PrimitivedList.end();
}
if (MoveContainer != NULL && Primitive != NULL)
{
MoveContainer->removePrimitive(Primitive);
Primitive = NULL;
MoveContainer = NULL;
}
else if (MoveContainer != NULL && Primitive == NULL || MoveContainer == NULL && Primitive != NULL)
{
nlwarning("Entity %s asked to remove PACS primitive, unable to continue (MoveContainer=%p, Primitive=%p)", Id.toString().c_str(), MoveContainer, Primitive);
}
}
/****************************************************************\
updatePositionUsingMovePrimitive
\****************************************************************/
void CWorldEntity::updatePositionUsingMovePrimitive(uint wi)
{
if (Primitive == NULL || Continent == INVALID_CONTINENT_INDEX || Continent == NO_CONTINENT_INDEX)
return;
NLPACS::UGlobalRetriever *retriever = CWorldPositionManager::getContinentContainer().getRetriever(Continent);
if (retriever == NULL)
return;
NLPACS::UGlobalPosition gp;
Primitive->getGlobalPosition(gp, wi);
bool interior = retriever->isInterior(gp);
bool local = localMotion();
float dummy;
bool water = retriever->isWaterPosition(gp, dummy);
NLMISC::CVectorD pos = Primitive->getFinalPosition(wi);
setPosition((sint32)(pos.x*1000), (sint32)(pos.y*1000), (sint32)(pos.z*1000), local, interior, water);
}
/****************************************************************\
****************************************************************
CPlayerInfos
****************************************************************
\****************************************************************/
// Static player allocator
CBlockMemory<CPlayerInfos> CPlayerInfos::_PlayerAllocator;
void CPlayerInfos::display(CLog *log) const
{
if (this == NULL)
log->displayNL("CPlayerInfos::display called on NULL");
log->displayNL("--- Display PlayerInfos %s E%u ---", _PlayerId.toString().c_str(), (Entity != NULL ? Entity->Index.getIndex() : 0));
DUMP_VAR(FeId.get());
DUMP_VAR(LastVisionTick);
DUMP_VAR(DelayVision);
DUMP_VAR(ActivateSlot0);
DUMP_VAR(DesactivateSlot0);
DUMP_VAR(Slot0Active);
DUMP_VAR(WhoICanSee);
#ifdef RECORD_LAST_PLAYER_POSITIONS
log->displayNL("Last positions recorded:");
uint i;
for (i=0; i<DistanceHistory.size(); ++i)
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);
#endif
log->displayNL("--- End of Display ---");
}