//===========================================================================// // 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 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 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<> 3; BYTE bit = (BYTE)(bit_number & 0x7); Verify(byte+1 < tileBoundDamage.GetSize()); BYTE *memory = (BYTE*)tileBoundDamage.GetPointer(); return (memory[byte] & (0x1<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 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 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)); }