/* Copyright (c) 2002-2012 Croteam Ltd. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define FILTER_ALL "All files (*.*)\0*.*\0" #define FILTER_END "\0" #define PROPERTY(offset, type) ENTITYPROPERTY(this, offset, type) ///////////////////////////////////////////////////////////////////// // Property management functions /* * Set all properties to default values. */ void CEntity::SetDefaultProperties(void) { // no properties to set in base class } /* * Helpers for writing/reading entity pointers. */ void CEntity::ReadEntityPointer_t(CTStream *istrm, CEntityPointer &pen) { CEntity *penPointed; // read index INDEX iPointedEntity; *istrm>>iPointedEntity; // if there is no entity pointed to if (iPointedEntity == -1) { // set NULL pointer penPointed = NULL; // if there is some entity } else { // get the entity in this world with that index extern BOOL _bReadEntitiesByID; if (_bReadEntitiesByID) { penPointed = en_pwoWorld->EntityFromID(iPointedEntity); } else { penPointed = en_pwoWorld->wo_cenAllEntities.Pointer(iPointedEntity); } } // return the entity pointer pen = penPointed; } void CEntity::WriteEntityPointer_t(CTStream *ostrm, CEntityPointer pen) { // if there is no entity pointed to if (pen==NULL) { // write -1 index *ostrm<<(INDEX)-1; // if there is some entity } else { // the entity must be in the same world as this one ASSERT(pen->en_pwoWorld == en_pwoWorld); // write index of the entity in this world *ostrm<<(pen->en_ulID); } } /* * Read all properties from a stream. */ void CEntity::ReadProperties_t(CTStream &istrm) // throw char * { istrm.ExpectID_t("PRPS"); // 'properties' //CDLLEntityClass *pdecDLLClass = en_pecClass->ec_pdecDLLClass; INDEX ctProperties; // read number of properties (note that this doesn't have to be same as number // of properties in the class (class might have changed)) istrm>>ctProperties; // for all saved properties for(INDEX iProperty=0; iPropertydec_ctProperties; // read packed identifier ULONG ulIDAndType; istrm>>ulIDAndType; // unpack property ID and property type from the identifier ULONG ulID; CEntityProperty::PropertyType eptType; ulID = ulIDAndType>>8; eptType = (CEntityProperty::PropertyType )(ulIDAndType&0x000000FFUL); // get the property with that ID and type CEntityProperty *pepProperty = PropertyForTypeAndID(eptType, ulID); // if not found, but it is a string if (pepProperty == NULL && eptType==CEntityProperty::EPT_STRING) { // maybe that became translatable string try that pepProperty = PropertyForTypeAndID(CEntityProperty::EPT_STRINGTRANS, ulID); // NOTE: it is still loaded as string, without translation chunk, // we just find it in properties table as a translatable string. } // if it was not found if (pepProperty == NULL) { // depending on the property type switch (eptType) { // if it is BOOL case CEntityProperty::EPT_BOOL: { // skip BOOL BOOL bDummy; istrm>>(INDEX &)bDummy; break; } // if it is INDEX case CEntityProperty::EPT_INDEX: case CEntityProperty::EPT_ENUM: case CEntityProperty::EPT_FLAGS: case CEntityProperty::EPT_ANIMATION: case CEntityProperty::EPT_ILLUMINATIONTYPE: case CEntityProperty::EPT_COLOR: case CEntityProperty::EPT_ANGLE: { // skip INDEX INDEX iDummy; istrm>>iDummy; } break; // if it is FLOAT case CEntityProperty::EPT_FLOAT: case CEntityProperty::EPT_RANGE: { // skip FLOAT FLOAT fDummy; istrm>>fDummy; } break; // if it is STRING case CEntityProperty::EPT_STRING: { // skip STRING CTString strDummy; istrm>>strDummy; break; } // if it is STRINGTRANS case CEntityProperty::EPT_STRINGTRANS: { // skip STRINGTRANS istrm.ExpectID_t("DTRS"); CTString strDummy; istrm>>strDummy; break; } // if it is FILENAME case CEntityProperty::EPT_FILENAME: { // skip FILENAME CTFileName fnmDummy; istrm>>fnmDummy; break; } // if it is FILENAMENODEP case CEntityProperty::EPT_FILENAMENODEP: { // skip FILENAMENODEP CTFileNameNoDep fnmDummy; istrm>>fnmDummy; break; } // if it is ENTITYPTR case CEntityProperty::EPT_ENTITYPTR: { // skip index INDEX iDummy; istrm>>iDummy; } break; // if it is FLOATAABBOX3D case CEntityProperty::EPT_FLOATAABBOX3D: { // skip FLOATAABBOX3D FLOATaabbox3D boxDummy; istrm>>boxDummy; } break; // if it is FLOATMATRIX3D case CEntityProperty::EPT_FLOATMATRIX3D: { // skip FLOATMATRIX3D FLOATmatrix3D boxDummy; istrm>>boxDummy; } break; // if it is EPT_FLOATQUAT3D case CEntityProperty::EPT_FLOATQUAT3D: { // skip EPT_FLOATQUAT3D FLOATquat3D qDummy; istrm>>qDummy; } break; // if it is FLOAT3D case CEntityProperty::EPT_FLOAT3D: { // skip FLOAT3D FLOAT3D vDummy; istrm>>vDummy; } break; // if it is ANGLE3D case CEntityProperty::EPT_ANGLE3D: { // skip ANGLE3D ANGLE3D vDummy; istrm>>vDummy; } break; // if it is FLOATplane3D case CEntityProperty::EPT_FLOATplane3D: { // skip FLOATplane3D FLOATplane3D plDummy; istrm>>plDummy; } break; // if it is MODELOBJECT case CEntityProperty::EPT_MODELOBJECT: // skip CModelObject SkipModelObject_t(istrm); break; // if it is MODELINSTANCE case CEntityProperty::EPT_MODELINSTANCE: SkipModelInstance_t(istrm); break; // if it is ANIMOBJECT case CEntityProperty::EPT_ANIMOBJECT: // skip CAnimObject SkipAnimObject_t(istrm); break; // if it is SOUNDOBJECT case CEntityProperty::EPT_SOUNDOBJECT: // skip CSoundObject SkipSoundObject_t(istrm); break; default: ASSERTALWAYS("Unknown property type"); } // if it was found } else { // fixup for loading old strings as translatable strings CEntityProperty::PropertyType eptLoad = pepProperty->ep_eptType; if (eptType==CEntityProperty::EPT_STRING && eptLoad==CEntityProperty::EPT_STRINGTRANS) { eptLoad = CEntityProperty::EPT_STRING; } // depending on the property type switch (eptLoad) { // if it is BOOL case CEntityProperty::EPT_BOOL: // read BOOL istrm>>(INDEX &)PROPERTY(pepProperty->ep_slOffset, BOOL); break; // if it is INDEX case CEntityProperty::EPT_INDEX: case CEntityProperty::EPT_ENUM: case CEntityProperty::EPT_FLAGS: case CEntityProperty::EPT_ANIMATION: case CEntityProperty::EPT_ILLUMINATIONTYPE: case CEntityProperty::EPT_COLOR: case CEntityProperty::EPT_ANGLE: // read INDEX istrm>>PROPERTY(pepProperty->ep_slOffset, INDEX); break; // if it is FLOAT case CEntityProperty::EPT_FLOAT: case CEntityProperty::EPT_RANGE: // read FLOAT istrm>>PROPERTY(pepProperty->ep_slOffset, FLOAT); break; // if it is STRING case CEntityProperty::EPT_STRING: // read STRING istrm>>PROPERTY(pepProperty->ep_slOffset, CTString); break; // if it is STRINGTRANS case CEntityProperty::EPT_STRINGTRANS: // read STRINGTRANS istrm.ExpectID_t("DTRS"); istrm>>PROPERTY(pepProperty->ep_slOffset, CTString); break; // if it is FILENAME case CEntityProperty::EPT_FILENAME: // read FILENAME istrm>>PROPERTY(pepProperty->ep_slOffset, CTFileName); if (PROPERTY(pepProperty->ep_slOffset, CTFileName)=="") { break; } // try to replace file name if it doesn't exist for(;;) { if( !FileExists( PROPERTY(pepProperty->ep_slOffset, CTFileName))) { // if file was not found, ask for replacing file CTFileName fnReplacingFile; if( GetReplacingFile( PROPERTY(pepProperty->ep_slOffset, CTFileName), fnReplacingFile, FILTER_ALL FILTER_END)) { // replacing file was provided PROPERTY(pepProperty->ep_slOffset, CTFileName) = fnReplacingFile; } else { ThrowF_t(TRANS("File '%s' does not exist"), (const char*)PROPERTY(pepProperty->ep_slOffset, CTFileName)); } } else { break; } } break; // if it is FILENAMENODEP case CEntityProperty::EPT_FILENAMENODEP: // read FILENAMENODEP istrm>>PROPERTY(pepProperty->ep_slOffset, CTFileNameNoDep); break; // if it is ENTITYPTR case CEntityProperty::EPT_ENTITYPTR: // read the entity pointer ReadEntityPointer_t(&istrm, PROPERTY(pepProperty->ep_slOffset, CEntityPointer)); break; // if it is FLOATAABBOX3D case CEntityProperty::EPT_FLOATAABBOX3D: // read FLOATAABBOX3D istrm>>(PROPERTY(pepProperty->ep_slOffset, FLOATaabbox3D)); break; // if it is FLOATMATRIX3D case CEntityProperty::EPT_FLOATMATRIX3D: // read FLOATMATRIX3D istrm>>(PROPERTY(pepProperty->ep_slOffset, FLOATmatrix3D)); break; // if it is FLOATQUAT3D case CEntityProperty::EPT_FLOATQUAT3D: // read FLOATQUAT3D istrm>>(PROPERTY(pepProperty->ep_slOffset, FLOATquat3D)); break; // if it is FLOAT3D case CEntityProperty::EPT_FLOAT3D: // read FLOAT3D istrm>>(PROPERTY(pepProperty->ep_slOffset, FLOAT3D)); break; // if it is ANGLE3D case CEntityProperty::EPT_ANGLE3D: // read ANGLE3D istrm>>(PROPERTY(pepProperty->ep_slOffset, ANGLE3D)); break; // if it is FLOATplane3D case CEntityProperty::EPT_FLOATplane3D: // read FLOATplane3D istrm>>(PROPERTY(pepProperty->ep_slOffset, FLOATplane3D)); break; // if it is MODELOBJECT case CEntityProperty::EPT_MODELOBJECT: // read CModelObject ReadModelObject_t(istrm, PROPERTY(pepProperty->ep_slOffset, CModelObject)); break; // if it is MODELINSTANCE case CEntityProperty::EPT_MODELINSTANCE: // read CModelObject ReadModelInstance_t(istrm, PROPERTY(pepProperty->ep_slOffset, CModelInstance)); break; // if it is ANIMOBJECT case CEntityProperty::EPT_ANIMOBJECT: // read CAnimObject ReadAnimObject_t(istrm, PROPERTY(pepProperty->ep_slOffset, CAnimObject)); break; // if it is SOUNDOBJECT case CEntityProperty::EPT_SOUNDOBJECT: // read CSoundObject { CSoundObject &so = PROPERTY(pepProperty->ep_slOffset, CSoundObject); ReadSoundObject_t(istrm, so); so.so_penEntity = this; } break; // if it is CPlacement3D case CEntityProperty::EPT_PLACEMENT3D: // read CPlacement3D istrm>>(PROPERTY(pepProperty->ep_slOffset, CPlacement3D)); break; default: ASSERTALWAYS("Unknown property type"); } } } } /* * Write all properties to a stream. */ void CEntity::WriteProperties_t(CTStream &ostrm) // throw char * { INDEX ctProperties = 0; // for all classes in hierarchy of this entity {for(CDLLEntityClass *pdecDLLClass = en_pecClass->ec_pdecDLLClass; pdecDLLClass!=NULL; pdecDLLClass = pdecDLLClass->dec_pdecBase) { // count the properties ctProperties+=pdecDLLClass->dec_ctProperties; }} ostrm.WriteID_t("PRPS"); // 'properties' // write number of properties ostrm<ec_pdecDLLClass; pdecDLLClass!=NULL; pdecDLLClass = pdecDLLClass->dec_pdecBase) { // for all properties for(INDEX iProperty=0; iPropertydec_ctProperties; iProperty++) { CEntityProperty &epProperty = pdecDLLClass->dec_aepProperties[iProperty]; // pack property ID and property type together ULONG ulID = epProperty.ep_ulID; ULONG ulType = (ULONG)epProperty.ep_eptType; ULONG ulIDAndType = (ulID<<8)|ulType; // write the packed identifier ostrm<Obtain_t(ec_fnmComponent); ctUsed = ec_ptdTexture->GetUsedCount(); break; // if model case ECT_MODEL: // obtain model data ec_pmdModel = _pModelStock->Obtain_t(ec_fnmComponent); ctUsed = ec_pmdModel->GetUsedCount(); break; // if sound case ECT_SOUND: // obtain sound data ec_psdSound = _pSoundStock->Obtain_t(ec_fnmComponent); ctUsed = ec_psdSound->GetUsedCount(); break; // if class case ECT_CLASS: // obtain entity class ec_pecEntityClass = _pEntityClassStock->Obtain_t(ec_fnmComponent); ctUsed = ec_pecEntityClass->GetUsedCount(); break; // if something else default: // error ThrowF_t(TRANS("Component '%s'(%d) is of unknown type!"), (const char *) (CTString&)ec_fnmComponent, ec_slID); } // if not already loaded and should not be precaching now if( ctUsed<=1 && !_precache_bNowPrecaching) { // report warning CPrintF(TRANSV("Not precached: (0x%08X)'%s'\n"), this->ec_slID, (const char *) ec_fnmComponent); } //CPrintF(TRANSV("Precaching NOW: (0x%08X)'%s'\n"), this->ec_slID, (const char *) ec_fnmComponent); // add to CRC AddToCRCTable(); } void CEntityComponent::ObtainWithCheck(void) { try { Obtain_t(); } catch(char *strError) { FatalError("%s", strError); } } // add component to crc table void CEntityComponent::AddToCRCTable(void) { // if not obtained if (ec_pvPointer==NULL) { // do nothing return; } // add it switch(ec_ectType) { case ECT_TEXTURE: ec_ptdTexture->AddToCRCTable(); break; case ECT_MODEL: ec_pmdModel->AddToCRCTable(); break; case ECT_SOUND: ec_psdSound->AddToCRCTable(); break; case ECT_CLASS: ec_pecEntityClass->AddToCRCTable(); break; } } /* * Release the component. */ void CEntityComponent::Release(void) { // if the component is not obtained if (ec_pvPointer==NULL) { // don't release it return; } // check the component type switch(ec_ectType) { // if texture case ECT_TEXTURE: // release texture data _pTextureStock->Release(ec_ptdTexture); break; // if model case ECT_MODEL: // release model data _pModelStock->Release(ec_pmdModel); break; // if sound case ECT_SOUND: // release sound data _pSoundStock->Release(ec_psdSound); break; // if class case ECT_CLASS: // release entity class _pEntityClassStock->Release(ec_pecEntityClass); break; // if something else default: // error ThrowF_t(TRANS("Component '%s'(%d) is of unknown type!"), (const char *) (CTString&)ec_fnmComponent, ec_slID); } // released ec_pvPointer=NULL; } // these entity classes are bases, here stop all recursive searches ENTITY_CLASSDEFINITION_BASE(CEntity, 32000); ENTITY_CLASSDEFINITION_BASE(CLiveEntity, 32001); ENTITY_CLASSDEFINITION_BASE(CRationalEntity, 32002);