Files
firestorm/Gameleap/code/mw4/Libraries/Adept/EntityManager.cpp
T
Cyd 2b8ca921cb Initial full mirror of c:\VWE (source + assets + toolchain + outputs) via Git LFS
Complete disaster-recovery snapshot: engine/game source, game data assets,
VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive.
Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false,
no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
2026-06-24 21:28:16 -05:00

675 lines
16 KiB
C++

//===========================================================================//
// File: EntityManager.cpp //
//---------------------------------------------------------------------------//
// Date Who Modification //
// -------- --- ---------------------------------------------------------- //
// 11/29/94 JMA Initial coding. //
// 08/25/97 JMA Infrastructure changes //
// 08/25/97 ECH Infrastructure changes //
//---------------------------------------------------------------------------//
// Copyright (C) 1994, Virtual World Entertainment, Inc. //
// All Rights reserved worldwide //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
//===========================================================================//
#include "AdeptHeaders.hpp"
#include "EntityManager.hpp"
#include "Application.hpp"
#include "Map.hpp"
#include "DropZone.hpp"
#include "Mission.hpp"
#include "Mover.hpp"
#include "CollisionGrid.hpp"
#include "Tile.hpp"
#include "DamageObject.hpp"
#include "Player.hpp"
//#############################################################################
//########################## EntityStockpile ############################
//#############################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
EntityStockpile::EntityStockpile():
Plug(DefaultData),
availableEntities(NULL)
{
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
EntityStockpile::~EntityStockpile()
{
availableEntities.DeletePlugs();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
EntityStockpile::TestInstance()
{
}
//#############################################################################
//########################### EntityManager #############################
//#############################################################################
EntityManager::ClassData*
EntityManager::DefaultData = NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
EntityManager::InitializeClass()
{
Verify(!DefaultData);
DefaultData =
new ClassData(
EntityManagerClassID,
"Adept::EntityManager",
Plug::DefaultData
);
Register_Object(DefaultData);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
EntityManager::TerminateClass()
{
Unregister_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
EntityManager::EntityManager(ClassData *data):
Plug(data),
armory(53, NULL, true),
deathRow(NULL),
nameSocket(NULL, true),
resourceIDSocket(2003, NULL, true),
postCollisionExecutors(NULL),
updateEntities(NULL),
tileBoundDamage(3000>>3)
{
Check_Pointer(this);
isExecutionSuspended = false;
playerReady = false;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
EntityManager::~EntityManager()
{
//
//------------------
// Delete stockpiles
//------------------
//
armory.DeletePlugs();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void EntityManager::SetPlayerReady(Entity *entity)
{
playerReady = true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
EntityManager::StoreInArmory(Entity *entity)
{
Check_Object(this);
Check_Object(entity);
const ResourceID &data_id = entity->GetDataListResourceID();
Verify(data_id != ResourceID::Null);
//
//-----------------------------------
// Verify that the entity is reusable
//-----------------------------------
//
Verify(entity->IsReusable());
Map::GetInstance()->RemoveChild(entity);
entity->BecomeUninteresting();
entity->owningConnection->RemoveReplicator(entity);
//
//--------------------------------------
// Get the stockpile for its resource ID
//--------------------------------------
//
EntityStockpile *stockpile;
if ((stockpile = armory.Find(data_id)) == NULL)
{
gos_PushCurrentHeap(g_Heap);
stockpile = new EntityStockpile;
gos_PopCurrentHeap();
Register_Object(stockpile);
armory.AddValue(stockpile, data_id);
}
Check_Object(stockpile);
//
//--------------------------------------------
// If it has already been entered, then return
//--------------------------------------------
//
Verify(!stockpile->availableEntities.IsPlugMember(entity));
stockpile->availableEntities.Add(entity);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Entity*
EntityManager::RequestFromArmory(const ResourceID &instance_resource_ID)
{
Check_Object(this);
//
//------------------------------------------------
// Get the stockpile for this entity, if it exists
//------------------------------------------------
//
EntityStockpile *stockpile;
if ((stockpile = armory.Find(instance_resource_ID)) == NULL)
return NULL;
Check_Object(stockpile);
if (stockpile->availableEntities.IsEmpty())
return NULL;
//
//-----------------------------------------
// Verify that an entity can be created now
//-----------------------------------------
//
Check_Object(Application::GetInstance());
Verify(!Application::GetInstance()->InPreCollisionPhase());
//
//-------------------------------------------
// Grab an entity from the available entities
//-------------------------------------------
//
Entity *entity;
ChainIteratorOf<Entity*> iterator(&stockpile->availableEntities);
entity = iterator.GetCurrent();
Check_Object(entity);
iterator.Remove();
//
//----------------------------------------------------------------
// Otherwise, grab the oldest in use, and update position in chain
//----------------------------------------------------------------
//
Verify(entity->GetDataListResourceID() == instance_resource_ID);
Verify(entity->IsReusable());
return entity;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
EntityManager::EntityCreated(Entity *entity)
{
Check_Object(this);
Check_Object(entity);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
EntityManager::FryDeathRow()
{
Check_Object(this);
if (!deathRow.IsEmpty())
{
ChainIteratorOf<Entity*> iterator(&deathRow);
Entity *entity;
while ((entity = iterator.GetCurrent()) != NULL)
{
Check_Object(entity);
//
// If the entity is reusable,
// it needs to be entered into the armory
//
//This is armory stuff that is going to be rewritten
if (entity->IsReusable())
{
{
// LOGIC("Background Tasks::Fry Death Row::REMOVE");
iterator.Remove();
}
{
// LOGIC("Background Tasks::Fry Death Row::STORE");
StoreInArmory(entity);
}
}
else
{
{
// LOGIC("Background Tasks::Fry Death Row::REMOVE");
iterator.Remove();
}
{
// LOGIC("Background Tasks::Fry Death Row::DELETE");
Unregister_Object(entity);
delete entity;
}
}
iterator.First();
}
return true;
}
return false;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
EntityManager::PrefixParentToName(
const Stuff::MString& parent_name,
Entity *entity
)
{
Check_Object(this);
Check_Object(entity);
MString new_name;
new_name = parent_name;
new_name += "::";
new_name += entity->instanceName;
#if defined(_ARMOR)
nameSocket.Remove(entity);
#endif
entity->instanceName = new_name;
#if defined(_ARMOR)
nameSocket.AddValue(entity, entity->instanceName);
#endif
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
DropZone*
EntityManager::GetDropZone(ObjectID zone_id)
{
Check_Object(this);
Entity *entity = NameTable::GetInstance()->FindData(zone_id);
if((entity) && (entity != (Entity *)-1))
{
Check_Object(entity);
Verify(entity->IsDerivedFrom(DropZone::DefaultData));
DropZone *zone;
zone = Cast_Object(DropZone *, entity);
return zone;
}
return NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
EntityManager::AddPlayerVehicle(Mover *mover)
{
Check_Object(this);
Check_Object(mover);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
EntityManager::SetNetworkDamageBit(bool bit_value, int bit_number)
{
int byte = bit_number >> 3;
BYTE bit = (BYTE)(bit_number & 0x7);
// no allocations are allowed now. They are only allowed at start up inside
// of BuildTileBoundDamageList
Verify(byte+1 < tileBoundDamage.GetSize());
BYTE *memory = (BYTE*)tileBoundDamage.GetPointer();
if (bit_value)
{
memory[byte] |= 0x1<<bit;
}
else
{
// if bit is 3 than the third bit should be zeroed
// 11111011
memory[byte] &= ~(0x1<<bit);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
EntityManager::GetNetworkDamageBit(int bit_number)
{
int byte = bit_number >> 3;
BYTE bit = (BYTE)(bit_number & 0x7);
Verify(byte+1 < tileBoundDamage.GetSize());
BYTE *memory = (BYTE*)tileBoundDamage.GetPointer();
return (memory[byte] & (0x1<<bit))?true:false;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
EntityManager::BuildTileBoundDamageList()
{
Check_Object(CollisionGrid::Instance);
BYTE row_size;
BYTE column_size;
CollisionGrid::Instance->GetSize(&row_size, &column_size);
int current_byte = 0;
for (WORD index = 0; index < (row_size * column_size); ++index)
{
Tile *tile = CollisionGrid::Instance->GetTile(index);
Check_Object(tile);
// go thru the children...
int current_bit = current_byte<<3;
int tile_entity_count = 0;
tile->SetDamageBitStart(current_bit);
Entity *entity;
for (int i = 0; i < tile->GetDamagableEntityCount(); ++i)
{
entity = tile->GetDamagableEntity(i);
Check_Object(entity);
Verify(entity->IsDestroyable());
entity->damageBit = current_bit;
tileBoundDamage.WriteBit(entity->IsDestroyed());
++current_bit;
++tile_entity_count;
if (tileBoundDamage.GetBytesRemaining() < 2)
{
tileBoundDamage.AllocateBytes(1000>>3);
}
}
tileBoundDamage.WriteByteAlign();
current_byte = tileBoundDamage.GetBytesUsed();
}
tileBoundDamage.Rewind();
}
void
EntityManager::ResetTileBoundDamageList()
{
Check_Object(CollisionGrid::Instance);
BYTE row_size;
BYTE column_size;
CollisionGrid::Instance->GetSize(&row_size, &column_size);
int current_byte = 0;
tileBoundDamage.Rewind();
for (WORD index = 0; index < (row_size * column_size); ++index)
{
Tile *tile = CollisionGrid::Instance->GetTile(index);
Check_Object(tile);
// go thru the children...
int current_bit = current_byte<<3;
int tile_entity_count = 0;
tile->SetDamageBitStart(current_bit);
Entity *entity;
for (int i = 0; i < tile->GetDamagableEntityCount(); ++i)
{
entity = tile->GetDamagableEntity(i);
Check_Object(entity);
Verify(entity->IsDestroyable());
tileBoundDamage.WriteBit(entity->IsDestroyed());
++current_bit;
++tile_entity_count;
}
tileBoundDamage.WriteByteAlign();
current_byte = tileBoundDamage.GetBytesUsed();
}
tileBoundDamage.Rewind();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
EntityManager::PreCollisionExecute(Time till)
{
Check_Object(this);
PRECOLLISION_LOGIC("Entity Manager");
//
//--------------------------------------------
// Execute the mission if we are not suspended
//--------------------------------------------
//
Check_Object(Mission::GetInstance());
if (!isExecutionSuspended)
{
Mission::GetInstance()->PreCollisionExecute(till);
PreCollisionNetworkEvents();
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
EntityManager::PostCollisionExecute(Time till)
{
Check_Object(this);
POSTCOLLISION_LOGIC("Entity Manager");
//
//-------------------------------------------------
// Execute all callback entities in insertion order
//-------------------------------------------------
//
while (!postCollisionExecutors.IsEmpty())
{
ChainIteratorOf<Entity*> entities(&postCollisionExecutors);
Entity *entity = entities.GetCurrent();
Check_Object(entity);
Verify(!entity->GetElement()->IsMatrixDirty());
entity->PostCollisionExecute(till);
Verify(!entity->newCollisions);
Verify(!entity->GetElement()->IsMatrixDirty());
postCollisionExecutors.RemovePlug(entity);
}
Verify(postCollisionExecutors.IsEmpty());
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
EntityManager::UpdateEntities()
{
Check_Object(this);
return;
// WE NO LONGER DO THIS FOR NETWORK UPDATES
// EVERYTHING IS CLIENT SERVER BASED NOW
#if 0
//
//-------------------------------------------------
// Execute all callback entities in insertion order
//-------------------------------------------------
//
ChainIteratorOf<Entity*> entities(&updateEntities);
Entity *entity;
while ((entity = entities.GetCurrent()) != NULL)
{
Check_Object(entity);
Verify(entity->GetReplicatorMode() == Replicator::MasterMode);
//
//---------------------------------------------------------------------
// For each one, we need to make a stream for the message to write into
// and then broadcast the message to the entities replicants
//---------------------------------------------------------------------
//
DynamicMemoryStream stream;
Entity::UpdateMessage *message = entity->ConstructUpdate(&stream);
Check_Object(message);
entity->DispatchToReplicants(message);
//
//---------------------------------------------------
// Clean out each entry in the chain as it's executed
//---------------------------------------------------
//
entity->updateFlags = 0;
entities.Remove();
}
#endif
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
EntityManager::RequestPostCollisionExecution(Entity *entity)
{
Check_Object(this);
Check_Object(entity);
Verify(!postCollisionExecutors.IsPlugMember(entity));
postCollisionExecutors.Add(entity);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
EntityManager::RemovePostCollisionExecution(Entity *entity)
{
Check_Object(this);
Check_Object(entity);
Verify(!entity->newCollisions);
if (entity->IsUsingPostCollision())
{
postCollisionExecutors.Remove(entity);
entity->IgnorePostCollision();
}
Verify(!postCollisionExecutors.IsPlugMember(entity));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
EntityManager::RequestUpdate(Entity *entity)
{
Check_Object(this);
Check_Object(entity);
updateEntities.Add(entity);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
EntityManager::IsInPostCollisionExecution(Entity *entity)
{
Check_Object(this);
Check_Object(entity);
return postCollisionExecutors.IsPlugMember(entity);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void EntityManager::ServeLocalEntities(Time till)
{
STOP(("That's a bad little monkey!!!: EntityManager::ServeLocalEntities - VIRTUAL NOT IMPLEMENTED"));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void EntityManager::UpdateClientEntites(int connection, int message_type, Stuff::MemoryStream *message)
{
STOP(("That's a bad little monkey!!!: EntityManager::UpdateLocalEntites - VIRTUAL NOT IMPLEMENTED"));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
EntityManager::TestInstance()
{
Verify(IsDerivedFrom(DefaultData));
}