#include "munga.h" #pragma hdrstop #include "entity.h" #include "interest.h" #include "exptbl.h" #include "hostmgr.h" #include "player.h" #include "audio.h" #include "fileutil.h" #include "registry.h" #include "event.h" #include "app.h" #include "nttmgr.h" #include "subsystm.h" #include "namelist.h" #include "notation.h" #if defined(TRACE_EXECUTE_ENTITY) static BitTrace Execute_Entity("Execute Entity"); #define SET_EXECUTE_ENTITY() Execute_Entity.Set() #define CLEAR_EXECUTE_ENTITY() Execute_Entity.Clear() #else #define SET_EXECUTE_ENTITY() #define CLEAR_EXECUTE_ENTITY() #endif #if defined(TRACE_PERFORM_ENTITY) static BitTrace Perform_Entity("Perform Entity"); #define SET_PERFORM_ENTITY() Perform_Entity.Set() #define CLEAR_PERFORM_ENTITY() Perform_Entity.Clear() #else #define SET_PERFORM_ENTITY() #define CLEAR_PERFORM_ENTITY() #endif #if defined(TRACE_PERFORM_SUBSYSTEMS) static BitTrace Perform_Subsystems("Perform Subsystems"); #define SET_PERFORM_SUBSYSTEMS() Perform_Subsystems.Set() #define CLEAR_PERFORM_SUBSYSTEMS() Perform_Subsystems.Clear() #else #define SET_PERFORM_SUBSYSTEMS() #define CLEAR_PERFORM_SUBSYSTEMS() #endif //############################################################################# //############################## Entity ################################# //############################################################################# //############################################################################# // Virtual Data support // Derivation* Entity::GetClassDerivations() { static Derivation classDerivations(Simulation::GetClassDerivations(), "Entity"); return &classDerivations; } Entity::SharedData Entity::DefaultData( Entity::GetClassDerivations(), Entity::GetMessageHandlers(), Entity::GetAttributeIndex(), Entity::StateCount, Entity::Make ); //############################################################################# // Message Support // const Receiver::HandlerEntry Entity::MessageHandlerEntries[]= { { Entity::MakeMessageID, "Make", (Entity::Handler)&Entity::DefaultMessageHandler }, { Entity::MakeReadyMessageID, "MakeReady", (Entity::Handler)&Entity::DefaultMessageHandler }, { Entity::RemakeEntityMessageID, "RemakeEntity", (Entity::Handler)&Entity::DefaultMessageHandler }, { Entity::RemakeReadyMessageID, "RemakeReady", (Entity::Handler)&Entity::DefaultMessageHandler }, { Entity::RemakeCompleteMessageID, "RemakeComplete", (Entity::Handler)&Entity::DefaultMessageHandler }, { Entity::RemakeIncompleteMessageID, "RemakeIncomplete", (Entity::Handler)&Entity::DefaultMessageHandler }, MESSAGE_ENTRY(Entity, DestroyEntity), { Entity::TransferEntityMessageID, "TransferEntity", (Entity::Handler)&Entity::DefaultMessageHandler }, { Entity::TransferCompleteMessageID, "TransferComplete", (Entity::Handler)&Entity::DefaultMessageHandler }, { Entity::TransferIncompleteMessageID, "TransferIncomplete", (Entity::Handler)&Entity::DefaultMessageHandler }, MESSAGE_ENTRY(Entity, BecomeInteresting), MESSAGE_ENTRY(Entity, BecomeUninteresting), MESSAGE_ENTRY(Entity, Update), { Entity::SubscribeReplicantMessageID, "SubscribeReplicant", (Entity::Handler)&Entity::DefaultMessageHandler }, { Entity::UnsubscribeReplicantMessageID, "UnsubscribeReplicant", (Entity::Handler)&Entity::DefaultMessageHandler }, MESSAGE_ENTRY(Entity, TakeDamage), MESSAGE_ENTRY(Entity, PlayerLink), MESSAGE_ENTRY(Entity, TakeDamageStream) }; Entity::MessageHandlerSet& Entity::GetMessageHandlers() { static Entity::MessageHandlerSet messageHandlers(ELEMENTS(Entity::MessageHandlerEntries), Entity::MessageHandlerEntries, Receiver::GetMessageHandlers()); return messageHandlers; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::Receive(Event* event) { Check(this); Check(event); // //------------------------------------------------------------------------- // If the entity is being transferred, post the message to the new owner of // the entity //------------------------------------------------------------------------- // // //-------------------------------------------------------------------------- // If the object is not valid, filter the message to determine which ones to // defer and which ones to immediately process //-------------------------------------------------------------------------- // if (!IsValid()) { //switch case commented out by Ryan Bunker on 1/6/07 //switch (event->messageToSend->messageID) { // //---------------------------------------------------------------------- // The messages which should be allowed through should just break out of // this switch //---------------------------------------------------------------------- // //default: // //------------------- // Defer the messages //------------------- // event->Defer(); return; } } // //------------------------------------------------ // Go ahead and dispatch the message to the entity //------------------------------------------------ // Receiver::Receive(event); #if defined(USE_FPU_ANALYSIS) if (!Fpu_Ok()) { Registry *registry = application->GetRegistry(); Receiver::SharedData *shared_data = registry->GetStaticData(GetClassID()); Derivation *derivation = shared_data->derivedClasses; Receiver::MessageHandlerSet *handlers = shared_data->activeMessageHandlers; DEBUG_STREAM << derivation->className << ',' << GetInstance() << endl << std::flush; DEBUG_STREAM << handlers->GetName(event->messageToSend->messageID) << endl; Fail("Event corrupted FPU!"); } #else Check_Fpu(); #endif } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::Dispatch(Receiver::Message* incoming) { Message *message = (Message*) incoming; Check(this); Check(message); // // Call Receiver if it is not entity aware!!!!! // if (message->messageID < Receiver::NextMessageID) { Receiver::Dispatch(message); } // //----------------------------------------- // Initialize the entity information fields //----------------------------------------- // message->entityID = entityID; message->interestZoneID = interestZoneID; // //------------------------------------------------------------------- // If this is a replicant instance, reroute the message to the master //------------------------------------------------------------------- // if (GetInstance() == ReplicantInstance) { application->SendMessage( ownerID, EntityManager::EntityManagerClientID, message ); } // //-------------------------------------------------------- // If this entity is invalid, post the message as an event //-------------------------------------------------------- // else if (!IsValid()) { // ECH 1/28/96 - application->Post(DefaultEventPriority, this, message); application->Post(EntityInvalidEventPriority, this, message); } // //-------------------------------------------- // Otherwise, go ahead and receive the message //-------------------------------------------- // else { Receiver::Receive(message); } Check_Fpu(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::DispatchToReplicants(Message *what) { Check(this); Check(what); what->entityID = entityID; what->interestZoneID = interestZoneID; Check(application); InterestManager *int_mgr = application->GetInterestManager(); Check(int_mgr); int_mgr->EntityBroadcastToReplicants(this, what); Check_Fpu(); } //############################################################################# // Attribute Support // const Entity::IndexEntry Entity::AttributePointers[]= { ATTRIBUTE_ENTRY(Entity, LocalToWorld, localToWorld), ATTRIBUTE_ENTRY(Entity, LocalOrigin, localOrigin), ATTRIBUTE_ENTRY(Entity, DamageZoneCount, damageZoneCount), ATTRIBUTE_ENTRY(Entity, DamageZones, damageZones) }; Entity::AttributeIndexSet& Entity::GetAttributeIndex() { static Entity::AttributeIndexSet attributeIndex(ELEMENTS(Entity::AttributePointers), Entity::AttributePointers, Simulation::GetAttributeIndex() ); return attributeIndex; } //############################################################################# // Model Support // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::WriteUpdateRecord( Simulation::UpdateRecord *record, int update_model ) { Check(this); Check_Pointer(record); switch (update_model) { case DefaultUpdateModelBit: { Simulation::WriteUpdateRecord(record, update_model); // //---------------------------- // Write out the record update //---------------------------- // UpdateRecord *update = (UpdateRecord*)record; update->localOrigin = localOrigin; updateOrigin = localOrigin; update->recordLength = sizeof(*update); } break; case DamageZoneUpdateModelBit: record->timeStamp = lastPerformance; record->recordID = (Word)update_model; WriteDamageUpdateRecord(record); break; default: Simulation::WriteUpdateRecord(record, update_model); break; } record->subsystemID = (Word)(EntitySubsystemID + 1); Check_Fpu(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::UpdateMessageHandler(UpdateMessage *message) { Check(this); Check(message); // //------------------------------------------------------ // Position to the beginning of the update record blocks //------------------------------------------------------ // MemoryStream stream(message, message->messageLength, sizeof(*message)); // //------------------------------------------------------------------------ // Step through each block until there are no more remaining, and send the // update out the the simulation indicated by the subsystemID //------------------------------------------------------------------------ // while (stream.GetBytesRemaining()) { Simulation::UpdateRecord *update = (Simulation::UpdateRecord*)stream.GetPointer(); Check_Pointer(update); Simulation *simulation = GetSimulation((int)update->subsystemID-1); Check(simulation); simulation->ReadUpdateRecord(update); stream.AdvancePointer(update->recordLength); } Check_Fpu(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::ReadUpdateRecord(Simulation::UpdateRecord *record) { Check(this); Check_Pointer(record); switch(record->recordID) { case DefaultUpdateModelBit: { // //----------------------- // Read the record update //----------------------- // UpdateRecord *update = (UpdateRecord*)record; updateOrigin = update->localOrigin; // //------------------------------------------------------------------ // If we aren't able to run yet, we must update local origin as well //------------------------------------------------------------------ // Check(application); int app_state = application->GetApplicationState(); if ( app_state < Application::RunningMission || app_state == Application::CreatingMission ) { localOrigin = updateOrigin; localToWorld = localOrigin; } Simulation::ReadUpdateRecord(record); } break; case DamageZoneUpdateModelBit: ReadDamageUpdateRecord(record); break; default: Simulation::ReadUpdateRecord(record); } Check_Fpu(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::ReadDamageUpdateRecord(Simulation::UpdateRecord *update_record) { // //------------------------------------------------------------------------ // Step through each block until there are no more remaining, and send the // update out the the damageZone indicated by the damageZoneIndex //------------------------------------------------------------------------ // MemoryStream stream( update_record, update_record->recordLength, sizeof(*update_record) ); while (stream.GetBytesRemaining()) { DamageZone::UpdateRecord *damage_zone_record = (DamageZone::UpdateRecord*)stream.GetPointer(); int damage_zone_index = damage_zone_record->damageZoneIndex; damageZones[damage_zone_index]->ReadUpdateRecord(damage_zone_record); stream.AdvancePointer(damage_zone_record->recordLength); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // #define MAX_UPDATE_LENGTH 1400 static long Update_Buffer[MAX_UPDATE_LENGTH >> 2]; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::WriteDamageUpdateRecord(Simulation::UpdateRecord *update_record) { Check(this); Check_Pointer(update_record); // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Make a memory stream this size of a network packet //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // MemoryStream stream( update_record, sizeof(Update_Buffer) - ((char*)update_record - (char*)Update_Buffer), sizeof(*update_record) ); DamageZone::UpdateRecord *record_start = (DamageZone::UpdateRecord*)stream.GetPointer(); // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Update Every DamageZone For NOW //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // for(int ii=0;iiWriteUpdateRecord(damage_zone_update); stream.AdvancePointer(damage_zone_update->recordLength); } // //----------------------------------------------- // Check to see if an update message is necessary //----------------------------------------------- // if (stream.GetPointer() != record_start) { Simulation::UpdateRecord *damage_update = (Simulation::UpdateRecord*)update_record; damage_update->recordLength = (char*)stream.GetPointer() - (char*)update_record; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Entity::UpdateMessage* Entity::Execute(const Time& till) { SET_EXECUTE_ENTITY(); Check(this); Check(&till); MemoryStream stream(Update_Buffer, sizeof(Update_Buffer), sizeof(UpdateMessage)); char *record_start = (char*)stream.GetPointer(); // //----------------------------------------------------------------------- // Check to see if the application will let us run. If We are starting a // mission, only the player class objects can execute //----------------------------------------------------------------------- // Check(application); // BT bring-up trace (env BT_NET_TRACE): which Execute branch high-ID entities take. if (getenv("BT_NET_TRACE") && (int)GetEntityID() >= 20) { static int s_execTrace = 0; if ((s_execTrace++ % 240) == 0) { DEBUG_STREAM << "[ent-exec] " << GetEntityID() << " state=" << (int)application->GetApplicationState() << " preRun=" << (int)IsPreRunnable() << " inst=" << (int)GetInstance() << "\n" << std::flush; } } if ( application->GetApplicationState() == Application::RunningMission || application->GetApplicationState() == Application::EndingMission || IsPreRunnable() ) { PerformAndWatch(till, &stream); } else { WriteSimulationUpdate(&stream); } #if defined(USE_FPU_ANALYSIS) if (!Fpu_Ok()) { Registry *registry = application->GetRegistry(); Receiver::SharedData *shared_data = registry->GetStaticData(GetClassID()); Derivation *derivation = shared_data->derivedClasses; DEBUG_STREAM << derivation->className << ',' << GetInstance() << endl << std::flush; Fail("Simulation corrupted FPU!"); } #endif // //----------------------------------------------- // Check to see if an update message is necessary //----------------------------------------------- // if (stream.GetPointer() != record_start) { UpdateMessage *update = (UpdateMessage*)Update_Buffer; update->messageID = UpdateMessageID; update->messageLength = (char*)stream.GetPointer() - (char*)Update_Buffer; update->messageFlags = 0; CLEAR_EXECUTE_ENTITY(); return update; } // //------------------------------------- // Otherwise, return NULL for no update //------------------------------------- // Check_Fpu(); CLEAR_EXECUTE_ENTITY(); return NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Simulation* Entity::GetSimulation(int index) { Check(this); if (index == EntitySubsystemID) { return this; } Check_Fpu(); if ((unsigned)index < subsystemCount) { return subsystemArray[index]; } else { return NULL; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Subsystem* Entity::FindSubsystem(const char* name) { Check(this); Check_Pointer(name); for (int i=0; iGetName(), name)) { return subsystemArray[i]; } } } Check_Fpu(); return NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // #define MAX_SUB_FILE_NAME (256) int Entity::FindSubsytemID ( #if DEBUG_LEVEL>0 const char *model_name, const char *subsystem_name #else const char *, const char *subsystem_name #endif ) { Check_Pointer(model_name); Check_Pointer(subsystem_name); int subsytem_id = EntitySubsystemID; int sub_count = 0; CString sub_file_string; CString sub_directory_string("models\\"); CString model_name_string("model_name"); CString sub_post_string(".sub"); sub_file_string = sub_directory_string + model_name_string + sub_post_string; NotationFile sub_file(sub_file_string); Check(&sub_file); NameList *page_list = sub_file.MakePageList(); Register_Object(page_list); NameList::Entry *entry=page_list->GetFirstEntry(); while (entry != NULL) { Check(entry); Check_Pointer(entry->GetName()); if (!stricmp(subsystem_name, entry->GetName())) { subsytem_id = sub_count; break; } ++sub_count; entry = entry->GetNextEntry(); } Unregister_Object(page_list); delete page_list; return subsytem_id; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::PerformAndWatch( const Time &till, MemoryStream *update_stream ) { Check(this); Check(&till); // //----------------------------------------- // Execute all the subsystems, then ourself //----------------------------------------- // SET_PERFORM_SUBSYSTEMS(); if (subsystemArray) { Check_Pointer(subsystemArray); // //--------------------------------------------------- // If this is not a replicant, execute all subsystems //--------------------------------------------------- // if (GetInstance() != ReplicantInstance) { for (int i=0; iIsNonReplicantExecutable()) { subsystem->PerformAndWatch(till, update_stream); #if defined(USE_FPU_ANALYSIS) if (!Fpu_Ok()) { Registry *registry = application->GetRegistry(); Receiver::SharedData *shared_data = registry->GetStaticData(GetClassID()); Derivation *derivation = shared_data->derivedClasses; DEBUG_STREAM << derivation->className << "\nExecuting subsystem[" << i << "], " << subsystem->GetName() << endl; Fail("Simulation corrupted FPU!"); } #endif } } } } // //-------------------------------------------------------------------- // If this is a replicant, execute only those subsystems which need to //-------------------------------------------------------------------- // else { for (int i=0; iIsReplicantExecutable()) { subsystem->PerformAndWatch(till, update_stream); #if defined(USE_FPU_ANALYSIS) if (!Fpu_Ok()) { Registry *registry = application->GetRegistry(); Receiver::SharedData *shared_data = registry->GetStaticData(GetClassID()); Derivation *derivation = shared_data->derivedClasses; DEBUG_STREAM << derivation->className << " replicant\nExecuting subsystem[" << i << "], " << subsystem->GetName() << endl; Fail("Simulation corrupted FPU!"); } #endif } } } } } CLEAR_PERFORM_SUBSYSTEMS(); SET_PERFORM_ENTITY(); Simulation::PerformAndWatch(till, update_stream); Check_Fpu(); CLEAR_PERFORM_ENTITY(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::PlayerLinkMessageHandler(PlayerLinkMessage *message) { Check(application); HostManager *host = application->GetHostManager(); Check(host); playerLink =(Player*) host->GetEntityPointer(message->playerID); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::TakeDamageStreamMessageHandler(TakeDamageStreamMessage *message) { Check(this); Check(message); // //------------------------------------------------- // Extract the common information out of the stream //------------------------------------------------- // Damage damage_data; EntityID shooting_entity = message->shootingEntity; int damage_zone_index = message->damageZoneIndex; damage_data.impactPoint = message->impactPoint; // //--------------------------------------------------- // Figure out how many damage messages there are here //--------------------------------------------------- // DynamicMessage damage_stream( message, message->messageLength, sizeof(*message) ); int entry_count; damage_stream >> entry_count; for (int i=0; i> damage_data.damageType >> damage_data.damageAmount; int subsystem; damage_stream >> subsystem; // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Apply the damage to the appropriate damageZone //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // TakeDamageMessage message( TakeDamageMessageID, sizeof(TakeDamageMessage), shooting_entity, damage_zone_index, damage_data, subsystem ); Dispatch(&message); } Check_Fpu(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::TakeDamageMessageHandler(TakeDamageMessage *message) { // //------------------------------------- // YOU MUST CHECK FOR -1 DamageZone!!!! //------------------------------------- // if (!damageZones || message->damageZone == -1) { return; } // //---------------------------------------------------------------------- // If we have no damage zones allocated, we ignore any damage sent to us //---------------------------------------------------------------------- // Verify(message->damageZone < damageZoneCount); Verify(message->damageZone >= 0 ); Check_Pointer(damageZones); Check(damageZones[message->damageZone]); damageZones[message->damageZone]->TakeDamage(message->damageData); Check_Fpu(); } //############################################################################# // Construction and Destruction // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Entity::Entity( Entity::MakeMessage *creation_message, Entity::SharedData &virtual_data ): Simulation(creation_message->classToCreate,virtual_data), staticVideoSocket(NULL), dynamicVideoSocket(NULL), audioSocket(NULL) { Check_Pointer(this); Check(creation_message); // // Get host manager pointer // HostManager *host_manager; Check(application); host_manager = application->GetHostManager(); Check(host_manager); // //----------------------------- // Initialize the entity fields //----------------------------- // playerLink = NULL; resourceID = creation_message->resourceID; owningPlayer = (Player*)host_manager->GetEntityPointer( creation_message->owningPlayerID ); simulationFlags = creation_message->instanceFlags; entityID = creation_message->entityID; ownerID = creation_message->ownerID; creationTime = Now(); interestZoneID = creation_message->interestZoneID; interestCount = 0; // initialize attributes localOrigin = creation_message->localOrigin; updateOrigin = localOrigin; localToWorld = localOrigin; // initialize camera stuff cameraOffset = Origin::Identity; SetInvalidFlag(); // initialize model stuff lastPerformance = creationTime; subsystemCount = 0; subsystemArray = NULL; damageZones = NULL; damageZoneCount = 0; // //-------------------------------- // Allocate the damageZones array //-------------------------------- // // // Read In DamageZones and Create DamageZoneID's // if (resourceID != ResourceDescription::NullResourceID) { ResourceDescription *dmg_res = application->GetResourceFile()->SearchList( resourceID, ResourceDescription::DamageZoneStreamResourceType ); // //-------------------------------------------- // Allocate damageZones for this entity only // if they were defined in the resource //-------------------------------------------- // if (dmg_res) { dmg_res->Lock(); DynamicMemoryStream damage_zone_stream( dmg_res->resourceAddress, dmg_res->resourceSize); damage_zone_stream >> damageZoneCount; damageZones = new (::DamageZone(*[damageZoneCount])); Register_Pointer(damageZones); dmg_res->Unlock(); } } // //--------------------------------------------------------- // Create a new entity ID and assign ownership to this host // If (this is a master entity) or // (this is a dynamic hermit) or // (this is the initial independent) //--------------------------------------------------------- // if ( (GetInstance() == MasterInstance) || (GetInstance() == HermitInstance && IsDynamic()) || ( (GetInstance() == IndependantInstance) && (creation_message->ownerID == NullHostID || creation_message->ownerID == MapHostID) ) ) { entityID = host_manager->MakeUniqueEntityID(); ownerID = host_manager->GetLocalHostID(); creation_message->entityID = entityID; creation_message->ownerID = ownerID; } // //-------------------------------------------- // Tell the host manager about this new entity //-------------------------------------------- // Check(host_manager); host_manager->NotifyOfEntityCreation(this, creation_message); Check_Fpu(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Entity* Entity::Make(Entity::MakeMessage *creation_message) { return new Entity(creation_message,DefaultData); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Logical Entity::CreateMakeMessage( MakeMessage *creation_message, #if DEBUG_LEVEL>0 NotationFile *model_file, #else NotationFile *, #endif const ResourceDirectories * ) { Check(creation_message); Check(model_file); char *p; creation_message->messageLength = sizeof(Entity::MakeMessage); creation_message->messageID = Entity::MakeMessageID; creation_message->owningPlayerID = EntityID::Null; creation_message->messageFlags = 0; creation_message->classToCreate = RegisteredClass::TrivialEntityClassID; creation_message->instanceFlags = 0; //DefaultFlags; if ((p = strtok(NULL, " ")) == NULL) { std::cerr << "X position coordinate missing!\n"; return False; } creation_message->localOrigin.linearPosition.x = atof(p); if ((p = strtok(NULL, " ")) == NULL) { std::cerr << "Y position coordinate missing!\n"; return False; } creation_message->localOrigin.linearPosition.y = atof(p); if ((p = strtok(NULL, " ")) == NULL) { std::cerr << "Z position coordinate missing!\n"; return False; } creation_message->localOrigin.linearPosition.z = atof(p); EulerAngles pyr; if ((p = strtok(NULL, " ")) == NULL) { std::cerr << "Pitch missing!\n"; return False; } pyr.pitch = atof(p); if ((p = strtok(NULL, " ")) == NULL) { std::cerr << "Yaw missing!\n"; return False; } pyr.yaw = atof(p); if ((p = strtok(NULL, " ")) == NULL) { std::cerr << "Roll missing!\n"; return False; } pyr.roll = atof(p); creation_message->localOrigin.angularPosition = pyr; return True; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Logical Entity::CreateMakeMapMessage( MakeMapMessage *creation_message, ResourceDescription::ResourceID resource_id, #if DEBUG_LEVEL>0 NotationFile *model_file, #else NotationFile *, #endif const ResourceDirectories * ) { Check(creation_message); Check(model_file); char *p; creation_message->messageLength = sizeof(Entity::MakeMapMessage); creation_message->messageID = Entity::MakeMessageID; creation_message->messageFlags = Entity::MakeMessage::MapStreamMarkerFlag; if ((p = strtok(NULL, " ")) == NULL) { std::cerr << "X position coordinate missing!\n"; return False; } creation_message->localOrigin.linearPosition.x = atof(p); if ((p = strtok(NULL, " ")) == NULL) { std::cerr << "Y position coordinate missing!\n"; return False; } creation_message->localOrigin.linearPosition.y = atof(p); if ((p = strtok(NULL, " ")) == NULL) { std::cerr << "Z position coordinate missing!\n"; return False; } creation_message->localOrigin.linearPosition.z = atof(p); EulerAngles pyr = EulerAngles::Identity; #if 0 if ((p = strtok(NULL, " ")) == NULL) { std::cerr << "Pitch missing!\n"; return False; } pyr.pitch = atof(p); if ((p = strtok(NULL, " ")) == NULL) { std::cerr << "Yaw missing!\n"; return False; } pyr.yaw = atof(p); if ((p = strtok(NULL, " ")) == NULL) { std::cerr << "Roll missing!\n"; return False; } pyr.roll = atof(p); #endif creation_message->localOrigin.angularPosition = pyr; creation_message->resourceID = resource_id; return True; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Entity::DestroyEntityMessageHandler(Message *) { CondemnToDeathRow(); Check_Fpu(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Entity::~Entity() { // // Notify the host manager that we are going away // Check(application); application->GetHostManager()->NotifyOfEntityDestruction(this); // // Delete the subsystem array // if (subsystemArray) { Check_Pointer(subsystemArray); for (int i=0; iGetEntityManager(); Check(entity_manager); // //------------------------------------------------- // Make sure we are not entered into deathrow twice //------------------------------------------------- // if (!IsCondemned()) { entity_manager->deathRow->Add(this); SetCondemnedFlag(); NeverExecute(); } Check_Fpu(); } //############################################################################# // Test Support // Logical Entity::TestInstance() const { return IsDerivedFrom(*GetClassDerivations()); } //########################################################################## // Renderer Support // void Entity::AddStaticVideoComponent(Component *component) { Check(component); Check(&staticVideoSocket); staticVideoSocket.Add(component); Check_Fpu(); } void Entity::AddDynamicVideoComponent(Component *component) { Check(component); Check(&dynamicVideoSocket); dynamicVideoSocket.Add(component); Check_Fpu(); } void Entity::AddAudioComponent(Component *component) { Check(component); Check(&audioSocket); audioSocket.Add(component); Check_Fpu(); } Enumeration Entity::GetAudioRepresentation(Entity *linked_entity) { Check(this); Check(linked_entity); return (linked_entity == this) ? InternalAudioRepresentation : ExternalAudioRepresentation; } //############################################################################# // Interest Support // void Entity::BecomeInteresting() { BecomeInterestingMessage message( Entity::BecomeInterestingMessageID, sizeof(BecomeInterestingMessage) ); Receiver::Dispatch(&message); Check_Fpu(); } void Entity::BecomeInterestingMessageHandler(const Receiver::Message*) { ++interestCount; Check_Fpu(); } void Entity::BecomeUninterestingMessageHandler() { --interestCount; Check_Fpu(); } Enumeration Entity::GetInterestPriority(Entity *linked_entity) { Check(this); Check(linked_entity); return (linked_entity == this) ? HighInterestPriority : LowInterestPriority; } int Entity::GetDamageZoneIndex(const CString &damage_zone_name) const { for(int ii=0;iidamageZoneName.Compare(damage_zone_name) == 0) { return ii; } } return -1; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // int Entity::CreateDamageZoneStream( ResourceFile *resource_file, const char *model_name, NotationFile *model_file, const ResourceDirectories *directories ) { Check(resource_file); Check_Pointer(model_name); Check(model_file); Check_Pointer(directories); // //------------------- // Find the .dmg file //------------------- // const char* dmg_file_cname; if ( !model_file->GetEntry( "gamedata", "DamageZones", &dmg_file_cname ) ) { std::cerr << model_name << " is missing .dmg file specification!\n"; return -1; } CString dmg_filename = MakePathedFilename(directories->modelDirectory, dmg_file_cname); NotationFile *dmg_file = new NotationFile(dmg_filename); Register_Object(dmg_file); int page_count = dmg_file->PageCount(); if (!page_count) { std::cerr << dmg_filename << " is empty or missing!\n"; Unregister_Object(dmg_file); delete dmg_file; return -1; } DynamicMemoryStream damage_stream; damage_stream << page_count; NameList *dmg_namelist = dmg_file->MakePageList(); Register_Object(dmg_namelist); NameList::Entry *dmg_entry = dmg_namelist->GetFirstEntry(); CString dmg_page_name; while(dmg_entry) { dmg_page_name = dmg_entry->GetName(); DamageZone::CreateStreamedDamageZone( model_file, model_name, NULL, dmg_page_name, &damage_stream, dmg_file, directories ); dmg_entry = dmg_entry->GetNextEntry(); } // //~~~~~~~~~~~~~~~~~~~~~~~ // Add Stream to Resource //~~~~~~~~~~~~~~~~~~~~~~~ // ResourceDescription *new_res = resource_file->AddResourceMemoryStream( model_name, ResourceDescription::DamageZoneStreamResourceType, 1, ResourceDescription::Preload, &damage_stream ); Check(new_res); Unregister_Object(dmg_file); delete dmg_file; Unregister_Object(dmg_namelist); delete dmg_namelist; return new_res->resourceID; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ResourceDescription::ResourceID Entity::CreateExplosionTableStream( ResourceFile *resource_file, const char *model_name, NotationFile *model_file, const ResourceDirectories *directories ) { Check(resource_file); Check_Pointer(model_name); Check(model_file); Check_Pointer(directories); // //~~~~~~~~~~~~~~~~~ // Find *.dmg file //~~~~~~~~~~~~~~~~~ // const char *entry_data; if (!model_file->GetEntry( "gamedata", "DamageZones", &entry_data ) ) { DEBUG_STREAM << model_name << " is missing .dmg file specification!\n" << std::flush; return -1; } CString filename = MakePathedFilename(directories->modelDirectory, entry_data); // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Make a notation file of the DMG Entries //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // NotationFile *dmg_file = new NotationFile(filename); Register_Object(dmg_file); if(dmg_file->IsEmpty()) { DEBUG_STREAM << model_name << " *.dmg file is empty or missing!\n" << std::flush; Unregister_Object(dmg_file); delete dmg_file; return -1; } DynamicMemoryStream explosion_stream; NameList *dmg_namelist = dmg_file->MakePageList(); Register_Object(dmg_namelist); NameList::Entry *dmg_entry = dmg_namelist->GetFirstEntry(); while(dmg_entry) { const char *entry_data; if (dmg_file->GetEntry( dmg_entry->GetName(), "ExplosionTable", &entry_data ) ) { CString filename = MakePathedFilename(directories->modelDirectory, entry_data); NotationFile *exp_file = new NotationFile(filename); Register_Object(exp_file); if(exp_file->IsEmpty()) { std::cerr<GetNextEntry(); } ResourceDescription *new_res = resource_file->AddResourceMemoryStream( model_name, ResourceDescription::ExplosionTableStreamResourceType, 1, ResourceDescription::Preload, &explosion_stream ); Check(new_res); Unregister_Object(dmg_file); delete dmg_file; Unregister_Object(dmg_namelist); delete dmg_namelist; return new_res->resourceID; } #if defined(TEST_CLASS) # include "entity.tcp" #endif