mirror of
https://github.com/ENSL/NS.git
synced 2024-12-20 17:51:07 +00:00
322 lines
9.3 KiB
C++
322 lines
9.3 KiB
C++
|
//======== (C) Copyright 2002 Charles G. Cleveland All rights reserved. =========
|
||
|
//
|
||
|
// The copyright to the contents herein is the property of Charles G. Cleveland.
|
||
|
// The contents may be used and/or copied only with the written permission of
|
||
|
// Charles G. Cleveland, or in accordance with the terms and conditions stipulated in
|
||
|
// the agreement/contract under which the contents have been supplied.
|
||
|
//
|
||
|
// Purpose:
|
||
|
//
|
||
|
// $Workfile: AvHEntityHierarchy.cpp $
|
||
|
// $Date: 2002/10/16 00:53:31 $
|
||
|
//
|
||
|
//-------------------------------------------------------------------------------
|
||
|
// $Log: AvHEntityHierarchy.cpp,v $
|
||
|
// Revision 1.10 2002/10/16 00:53:31 Flayra
|
||
|
// - Updated with new infinite loop data
|
||
|
//
|
||
|
// Revision 1.9 2002/07/25 16:57:59 flayra
|
||
|
// - Linux changes
|
||
|
//
|
||
|
// Revision 1.8 2002/07/24 21:16:36 Flayra
|
||
|
// - Linux issues
|
||
|
//
|
||
|
// Revision 1.7 2002/07/24 20:05:22 Flayra
|
||
|
// - Linux issues
|
||
|
//
|
||
|
// Revision 1.6 2002/07/24 19:44:05 Flayra
|
||
|
// - Linux issues
|
||
|
//
|
||
|
// Revision 1.5 2002/07/24 18:55:52 Flayra
|
||
|
// - Linux case sensitivity stuff
|
||
|
//
|
||
|
// Revision 1.4 2002/07/08 16:56:12 Flayra
|
||
|
// - Workaround to infinite loop encountered during playtest: look into this more
|
||
|
//
|
||
|
// Revision 1.3 2002/06/25 17:55:49 Flayra
|
||
|
// - Quick fix during playtesting...why is this happening?
|
||
|
//
|
||
|
//===============================================================================
|
||
|
#include "util/nowarnings.h"
|
||
|
#include "mod/AvHEntityHierarchy.h"
|
||
|
#include "mod/AvHNetworkMessages.h"
|
||
|
|
||
|
#ifdef AVH_SERVER
|
||
|
#include "dlls/extdll.h"
|
||
|
#include "dlls/util.h"
|
||
|
#include "mod/AvHPlayer.h"
|
||
|
#include "mod/AvHTeam.h"
|
||
|
#include "mod/AvHServerUtil.h"
|
||
|
#include "mod/AvHGamerules.h"
|
||
|
#include "mod/AvHMarineEquipment.h"
|
||
|
#include "mod/AvHSharedUtil.h"
|
||
|
#include "util/MathUtil.h"
|
||
|
#endif
|
||
|
|
||
|
#ifdef AVH_CLIENT
|
||
|
#include "cl_dll/chud.h"
|
||
|
#include "cl_dll/cl_util.h"
|
||
|
#endif
|
||
|
|
||
|
////////////
|
||
|
// Shared //
|
||
|
////////////
|
||
|
AvHEntityHierarchy::AvHEntityHierarchy()
|
||
|
{
|
||
|
this->Clear();
|
||
|
}
|
||
|
|
||
|
void AvHEntityHierarchy::Clear()
|
||
|
{
|
||
|
this->mEntityList.clear();
|
||
|
}
|
||
|
|
||
|
bool AvHEntityHierarchy::operator!=(const AvHEntityHierarchy& inHierarchy) const
|
||
|
{
|
||
|
return !this->operator==(inHierarchy);
|
||
|
}
|
||
|
|
||
|
bool AvHEntityHierarchy::operator==(const AvHEntityHierarchy& inHierarchy) const
|
||
|
{
|
||
|
bool theAreEqual = false;
|
||
|
|
||
|
// NOTE: This could cause problems if entity hierarchy is stored in a hash or something
|
||
|
if(this->mEntityList == inHierarchy.mEntityList)
|
||
|
{
|
||
|
theAreEqual = true;
|
||
|
}
|
||
|
|
||
|
return theAreEqual;
|
||
|
}
|
||
|
|
||
|
// Gets a list of all entity infos, with each one being a muxed entity index and flags
|
||
|
void AvHEntityHierarchy::GetEntityInfoList(MapEntityMap& outList) const
|
||
|
{
|
||
|
outList = mEntityList;
|
||
|
}
|
||
|
|
||
|
////////////////
|
||
|
// end shared //
|
||
|
////////////////
|
||
|
|
||
|
|
||
|
////////////
|
||
|
// Server //
|
||
|
////////////
|
||
|
#ifdef AVH_SERVER
|
||
|
|
||
|
int GetHotkeyGroupContainingPlayer(AvHPlayer* player)
|
||
|
{
|
||
|
|
||
|
AvHTeam* theTeam = player->GetTeamPointer();
|
||
|
if(theTeam)
|
||
|
{
|
||
|
for (int i = 0; i < kNumHotkeyGroups; ++i)
|
||
|
{
|
||
|
|
||
|
EntityListType theGroup = theTeam->GetGroup(i);
|
||
|
|
||
|
for (int j = 0; j < (signed)theGroup.size(); ++j)
|
||
|
{
|
||
|
if (theGroup[j] == player->entindex())
|
||
|
{
|
||
|
return i;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return -1;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
void AvHEntityHierarchy::BuildFromTeam(const AvHTeam* inTeam, BaseEntityListType& inBaseEntityList)
|
||
|
{
|
||
|
|
||
|
this->Clear();
|
||
|
|
||
|
if (inTeam->GetTeamType() == AVH_CLASS_TYPE_MARINE ||
|
||
|
inTeam->GetTeamType() == AVH_CLASS_TYPE_ALIEN)
|
||
|
{
|
||
|
|
||
|
// Loop through all entities in the world
|
||
|
for(BaseEntityListType::iterator theIter = inBaseEntityList.begin(); theIter != inBaseEntityList.end(); theIter++)
|
||
|
{
|
||
|
|
||
|
CBaseEntity* theBaseEntity = *theIter;
|
||
|
|
||
|
int theEntityIndex = theBaseEntity->entindex();
|
||
|
bool theEntityIsVisible = (theBaseEntity->pev->team == (int)(inTeam->GetTeamNumber())) ||
|
||
|
GetHasUpgrade(theBaseEntity->pev->iuser4, MASK_VIS_SIGHTED);
|
||
|
bool theEntityIsDetected = GetHasUpgrade(theBaseEntity->pev->iuser4, MASK_VIS_DETECTED);
|
||
|
|
||
|
// Don't send ammo, health, weapons, or scans
|
||
|
bool theIsTransient = ((AvHUser3)(theBaseEntity->pev->iuser3) == AVH_USER3_MARINEITEM) || (theBaseEntity->pev->classname == MAKE_STRING(kwsScan));
|
||
|
|
||
|
MapEntity mapEntity;
|
||
|
|
||
|
mapEntity.mX = theBaseEntity->pev->origin.x;
|
||
|
mapEntity.mY = theBaseEntity->pev->origin.y;
|
||
|
mapEntity.mUser3 = (AvHUser3)(theBaseEntity->pev->iuser3);
|
||
|
|
||
|
// Don't draw detected blips as their real selves
|
||
|
if(!theEntityIsVisible && theEntityIsDetected)
|
||
|
mapEntity.mUser3 = AVH_USER3_UNKNOWN;
|
||
|
|
||
|
mapEntity.mAngle = theBaseEntity->pev->angles[1];
|
||
|
mapEntity.mTeam = (AvHTeamNumber)(theBaseEntity->pev->team);
|
||
|
mapEntity.mSquadNumber = 0;
|
||
|
|
||
|
bool sendEntity = false;
|
||
|
|
||
|
if (mapEntity.mUser3 == AVH_USER3_HIVE)
|
||
|
{
|
||
|
if (!theEntityIsVisible)
|
||
|
{
|
||
|
mapEntity.mTeam = TEAM_IND;
|
||
|
}
|
||
|
sendEntity = true;
|
||
|
}
|
||
|
else if (mapEntity.mUser3 == AVH_USER3_WELD)
|
||
|
{
|
||
|
vec3_t theEntityOrigin = AvHSHUGetRealLocation(theBaseEntity->pev->origin, theBaseEntity->pev->mins, theBaseEntity->pev->maxs);
|
||
|
mapEntity.mX = theEntityOrigin.x;
|
||
|
mapEntity.mY = theEntityOrigin.y;
|
||
|
sendEntity = true;
|
||
|
}
|
||
|
else if (mapEntity.mUser3 == AVH_USER3_FUNC_RESOURCE)
|
||
|
{
|
||
|
sendEntity = true;
|
||
|
}
|
||
|
else if ((theEntityIsVisible || theEntityIsDetected) && !(theBaseEntity->pev->effects & EF_NODRAW) && !theIsTransient)
|
||
|
{
|
||
|
|
||
|
AvHPlayer* thePlayer = dynamic_cast<AvHPlayer*>(theBaseEntity);
|
||
|
|
||
|
if (thePlayer)
|
||
|
{
|
||
|
ASSERT(theEntityIndex > 0);
|
||
|
ASSERT(theEntityIndex <= 32);
|
||
|
mapEntity.mSquadNumber = GetHotkeyGroupContainingPlayer(thePlayer) + 1;
|
||
|
|
||
|
if ((thePlayer->GetPlayMode() == PLAYMODE_PLAYING) && !thePlayer->GetIsSpectator())
|
||
|
{
|
||
|
|
||
|
sendEntity = true;
|
||
|
|
||
|
// If the player has the heavy armor upgrade switch the
|
||
|
// user3 to something that will let us reconstruct that later.
|
||
|
|
||
|
if (thePlayer->pev->iuser3 == AVH_USER3_MARINE_PLAYER &&
|
||
|
GetHasUpgrade(thePlayer->pev->iuser4, MASK_UPGRADE_13))
|
||
|
{
|
||
|
mapEntity.mUser3 = AVH_USER3_HEAVY;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (mapEntity.mUser3 != AVH_USER3_HEAVY)
|
||
|
{
|
||
|
sendEntity = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
if (sendEntity)
|
||
|
{
|
||
|
|
||
|
const AvHMapExtents& theMapExtents = GetGameRules()->GetMapExtents();
|
||
|
// commented this out here, commented out corresponding shift in AvHOverviewMap::Draw at line 771
|
||
|
// float theMinMapX = theMapExtents.GetMinMapX();
|
||
|
// float theMinMapY = theMapExtents.GetMinMapY();
|
||
|
|
||
|
// mapEntity.mX -= theMinMapX;
|
||
|
// mapEntity.mY -= theMinMapY;
|
||
|
|
||
|
mEntityList[theEntityIndex] = mapEntity;
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
// Returns true when something was sent
|
||
|
bool AvHEntityHierarchy::SendToNetworkStream(AvHEntityHierarchy& inClientHierarchy, entvars_t* inPlayer)
|
||
|
{
|
||
|
// Get iterators for both hierarchies
|
||
|
|
||
|
MapEntityMap::const_iterator clientIter = inClientHierarchy.mEntityList.begin();
|
||
|
MapEntityMap::const_iterator clientEnd = inClientHierarchy.mEntityList.end();
|
||
|
MapEntityMap::const_iterator serverIter = mEntityList.begin();
|
||
|
MapEntityMap::const_iterator serverEnd = mEntityList.end();
|
||
|
|
||
|
// Create maps for changes
|
||
|
MapEntityMap NewItems; //to be added or changed
|
||
|
EntityListType OldItems; //to be deleted
|
||
|
//TODO : replace OldItems with vector<int>
|
||
|
|
||
|
while (clientIter != clientEnd && serverIter != serverEnd)
|
||
|
{
|
||
|
if (serverIter->first < clientIter->first)
|
||
|
{
|
||
|
NewItems.insert( *serverIter );
|
||
|
++serverIter;
|
||
|
continue;
|
||
|
}
|
||
|
if (serverIter->first > clientIter->first)
|
||
|
{
|
||
|
OldItems.push_back( clientIter->first );
|
||
|
++clientIter;
|
||
|
continue;
|
||
|
}
|
||
|
if (clientIter->second != serverIter->second)
|
||
|
{
|
||
|
NewItems.insert( *serverIter );
|
||
|
}
|
||
|
|
||
|
++serverIter;
|
||
|
++clientIter;
|
||
|
}
|
||
|
|
||
|
while(serverIter != serverEnd)
|
||
|
{
|
||
|
NewItems.insert( *serverIter );
|
||
|
++serverIter;
|
||
|
}
|
||
|
|
||
|
while(clientIter != clientEnd)
|
||
|
{
|
||
|
OldItems.push_back( clientIter->first );
|
||
|
++clientIter;
|
||
|
}
|
||
|
|
||
|
NetMsg_UpdateEntityHierarchy( inPlayer, NewItems, OldItems );
|
||
|
return (!NewItems.empty() || !OldItems.empty());
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
////////////////
|
||
|
// end server //
|
||
|
////////////////
|
||
|
|
||
|
bool AvHEntityHierarchy::InsertEntity( const int inIndex, const MapEntity &inEntity )
|
||
|
{
|
||
|
this->mEntityList[inIndex] = inEntity;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool AvHEntityHierarchy::DeleteEntity( const int inIndex )
|
||
|
{
|
||
|
MapEntityMap::iterator loc = this->mEntityList.find(inIndex);
|
||
|
if( loc == this->mEntityList.end() )
|
||
|
{ return false; }
|
||
|
this->mEntityList.erase(loc);
|
||
|
return true;
|
||
|
}
|