Ares Developer Scrapbook: Difference between revisions
Creating |
Massively rewrote this to make it easier to read and understand; D, please check if everything is still correct. |
||
Line 1: | Line 1: | ||
==Identifying Objects== | |||
; | |||
:: | ===How do I best figure out stuff like "Is this object a BuildingType?"=== | ||
Using the <code>WhatAmI()</code> member. <code>WhatAmI()</code> returns a numeric value that can be compared to a multitude of predefined constants which tell you exactly what kind of object you're dealing with (more technically, it returns an eAbstractType, which is a typedef of an int).<br> | |||
:: | <code>WhatAmI()</code> is a pure virtual function of AbstractClass, the highest level of YR's class hierarchy; as such, it should exist on all objects you could possibly encounter. | ||
====Example==== | |||
ptr->WhatAmI() == abs_BuildingType | |||
====Possible Values==== | |||
The possible values to compare against are defined in YR++'s GeneralDefinitions.h, and, as of the time of this writing, are the following: | |||
{|cellpadding="4" cellspacing="0" border="1" | |||
| abs_None | |||
| abs_Overlay | |||
| abs_UnitType | |||
| abs_FoggedObject | |||
|- | |||
| abs_Unit | |||
| abs_OverlayType | |||
| abs_VoxelAnim | |||
| abs_AlphaShape | |||
|- | |||
| abs_Aircraft | |||
| abs_Particle | |||
| abs_VoxelAnimType | |||
| abs_VeinholeMonster | |||
|- | |||
| abs_AircraftType | |||
| abs_ParticleType | |||
| abs_Wave | |||
| abs_NavyType | |||
|- | |||
| abs_Anim | |||
| abs_ParticleSystem | |||
| abs_Tag | |||
| abs_SpawnManager | |||
|- | |||
| abs_AnimType | |||
| abs_ParticleSystemType | |||
| abs_TagType | |||
| abs_CaptureManager | |||
|- | |||
| abs_Building | |||
| abs_Script | |||
| abs_Tiberium | |||
| abs_Parasite | |||
|- | |||
| abs_BuildingType | |||
| abs_ScriptType | |||
| abs_Action | |||
| abs_Bomb | |||
|- | |||
| abs_Bullet | |||
| abs_Side | |||
| abs_Event | |||
| abs_RadSite | |||
|- | |||
| abs_BulletType | |||
| abs_Smudge | |||
| abs_WeaponType | |||
| abs_Temporal | |||
|- | |||
| abs_Campaign | |||
| abs_SmudgeType | |||
| abs_WarheadType | |||
| abs_Airstrike | |||
|- | |||
| abs_Cell | |||
| abs_Special | |||
| abs_Waypoint | |||
| abs_SlaveManager | |||
|- | |||
| abs_Factory | |||
| abs_SuperWeaponType | |||
| abs_Abstract | |||
| abs_DiskLaser | |||
|- | |||
| abs_House | |||
| abs_TaskForce | |||
| abs_Tube | |||
| | |||
|- | |||
| abs_HouseType | |||
| abs_Team | |||
| abs_EMPulse | |||
| | |||
|- | |||
| abs_Infantry | |||
| abs_TeamType | |||
| abs_TacticalMap | |||
| | |||
|- | |||
| abs_InfantryType | |||
| abs_Terrain | |||
| abs_Super | |||
| | |||
|- | |||
| abs_Isotile | |||
| abs_TerrainType | |||
| abs_AITrigger | |||
| | |||
|- | |||
| abs_IsotileType | |||
| abs_Trigger | |||
| abs_AITriggerType | |||
| | |||
|- | |||
| abs_LightSource | |||
| abs_TriggerType | |||
| abs_Neuron | |||
| | |||
|} | |||
===How do I best figure out stuff like "Is this object of this particular BuildingType?" (e.g. "Is this a GADEPT?")=== | |||
Each individual object blueprint, i.e. any Building-, Vehicle-, etc. Type defined in the INI, is stored as an instance of *TypeClass.<br> | |||
Each individual object of that type (*Class objects) will point back to that *TypeClass as its type.<br> | |||
Therefore, what you do is obtain a pointer to that particular *TypeClass, and compare it against the pointer an object returns for its type. | |||
If both pointers point to the same *TypeClass, the object is of the type you are comparing against. | |||
The easiest approach is to grab the pointer to the comparison *TypeClass right when reading the INI and storing it; assume we have a section like this: | |||
[SomeVehicle] | |||
CanDoStuffWith=GADEPT | |||
Now when we parse the INI, we read "GADEPT" and then obtain the pointer to the general GADEPT type object: | |||
void FooExt::ExtData::LoadFromINIFile(FooClass *pThis, CCINIClass *pINI) { | |||
{{co|// note that the following read is performed from the owning object's INI section - the same way works in Rules, where an object called MTNK has a section [MTNK]|DarkGrey}} | |||
{{co|// only store if the flag is actually set to something|DarkGrey}} | |||
if(pINI->ReadString(pThis->ID, "CanDoStuffWith", "", Ares::readBuffer, Ares::readLength)) { | |||
{{co|// ::Find iterates the currently declared BuildingTypes array and returns pointer to the one with the ID given as argument|DarkGrey}} | |||
this->BuildingTypeICanDoStuffWith = BuildingTypeClass::Find(Ares::readBuffer); | |||
} | |||
} | |||
So far so good. Now we have a pointer to the BuildingType GADEPT stored in the property <code>BuildingTypeICanDoStuffWith</code>. And now all we have to do is compare any given object's type against that: | |||
{{co|// assuming pSomeVehicleExt is the pointer to SomeExt::ExtData, where your extension variables should be saved|DarkGrey}} | |||
{{co|// and pSomeBuilding is the building whose type you want to check|DarkGrey}} | |||
if(pSomeBuilding->Type == pSomeVehicleExt->BuildingTypeICanDoStuffWith) { | |||
// The building's type is the same as the type you got from the INI | |||
} | |||
==Hierarchy Traversal== | |||
===I have a pointer to a given game object/class - how do I get its type class?=== | |||
*{{tt|ptr->GetType()}} returns an {{tt|ObjectTypeClass *}} to the type data | |||
*On TechnoClass and its derivates, {{tt|ptr->GetTechnoType()}} returns a {{tt|TechnoTypeClass *}} to the same type data | |||
..both of them are actually pointers to the final derived type of the object, just downcasted (this is a C++ covariant return type limitation). So if you know the exact type you need and [[#{{anchorencode:I have a Techno-/ObjectClass-derived pointer, how do I get the exact (Building{{!}}Infantry{{!}}Vehicle{{!}}Aircraft)Class pointer?}}|are sure that the object's type is appropriate]], you can just do | |||
reinterpret_cast<TargetTypeClass *>(ptr->GetTechnoType()) | |||
and that's it. | |||
===I have a Techno-/ObjectClass-derived pointer, how do I get the exact (Building|Infantry|Vehicle|Aircraft)Class pointer?=== | |||
Sometime in the future, there will be an automagic way to do this. In the meantime, you have to do it the following way: | |||
Use <code>WhatAmI()</code> as you [[#{{anchorencode:How do I best figure out stuff like "Is this object a BuildingType?"}}|learned above]] to safeguard a cast to the correct type. | |||
if(ptr->WhatAmI() == abs_Building) { | if(ptr->WhatAmI() == abs_Building) { | ||
BuildingClass * pBuilding = reinterpret_cast<BuildingClass *>(ptr); | |||
} | } | ||
/* the intelligent casts like dynamic won't work, | /* the intelligent casts like dynamic won't work, | ||
Line 12: | Line 161: | ||
*/ | */ | ||
===I have a Techno-/ObjectTypeClass-derived pointer, how do I get the exact (Building|Infantry|Vehicle|Aircraft)TypeClass pointer?=== | |||
[[#{{anchorencode:I have a Techno-/ObjectClass-derived pointer, how do I get the exact (Building{{!}}Infantry{{!}}Vehicle{{!}}Aircraft)Class pointer?}}|See above.]] | |||
===I have a pointer to a given game object/class - how do I get that class's Ares extension?=== | |||
Unlike the game's classes which are in a hierarchy, Ares's extension classes are all siblings. That means that a {{tt|BuildingExt}} doesn't contain {{tt|TechnoExt}} even though it seems like it should.<br> | |||
Therefore, you need the ''ExtMap''. ExtMap should be a static member of all extension classes, and has a .Find member function that allows you to find the correct ExtData block in the correct type for a given object. | |||
*If you need data from {{tt|TechnoTypeExt}}, you call {{Tt|TechnoTypeExt::ExtMap.Find(ptr)}} and receive a {{tt|TechnoTypeExt *}} associated with this object. | |||
*If you need data from {{tt|BuildingTypeExt}}, you call {{Tt|BuildingTypeExt::ExtMap.Find(ptr)}} and receive a {{tt|BuildingTypeExt *}} associated with this object. | |||
*If you need data from {{tt|BuildingExt}}, you call {{Tt|BuildingExt::ExtMap.Find(ptr)}} and receive a {{tt|BuildingExt *}} associated with this object. | |||
Remember to always ensure you're trying to get the correct ExtData, e.g. don't try to get *TypeExt on a non-type or vice versa. | |||
{{tt|Find}} might return NULL if there is no data associated with this object, but that shouldn't happen normally, all objects which can have extension data are attached to the ExtMap when they are created/destroyed. So you don't need to check for NULL when you fetch it. | {{tt|Find}} might return NULL if there is no data associated with this object, but that shouldn't happen normally, all objects which can have extension data are attached to the ExtMap when they are created/destroyed. So you don't need to check for NULL when you fetch it. | ||
====Example==== | |||
:: | :''from BulletExt::ExtData::DamageOccupants()'' | ||
The function has a bullet (TheBullet), and needs the Ares extension of the bullet's type: | |||
BulletTypeExt::ExtData* TheBulletTypeExt = BulletTypeExt::ExtMap.Find(TheBullet->Type); | |||
...and that's it. | |||
===I have a given ExtData block - how do I get the game object it belongs to?=== | |||
Every Ares extension has an <code>AttachedToObject</code> pointer that links back to the game object this extension belongs to. | |||
====Example==== | |||
:: | :''from BulletExt::ExtData::DamageOccupants()'' | ||
: | BulletClass* TheBullet = this->AttachedToObject; | ||
:: | |||
Revision as of 22:34, 14 December 2009
Identifying Objects
How do I best figure out stuff like "Is this object a BuildingType?"
Using the WhatAmI()
member. WhatAmI()
returns a numeric value that can be compared to a multitude of predefined constants which tell you exactly what kind of object you're dealing with (more technically, it returns an eAbstractType, which is a typedef of an int).
WhatAmI()
is a pure virtual function of AbstractClass, the highest level of YR's class hierarchy; as such, it should exist on all objects you could possibly encounter.
Example
ptr->WhatAmI() == abs_BuildingType
Possible Values
The possible values to compare against are defined in YR++'s GeneralDefinitions.h, and, as of the time of this writing, are the following:
abs_None | abs_Overlay | abs_UnitType | abs_FoggedObject |
abs_Unit | abs_OverlayType | abs_VoxelAnim | abs_AlphaShape |
abs_Aircraft | abs_Particle | abs_VoxelAnimType | abs_VeinholeMonster |
abs_AircraftType | abs_ParticleType | abs_Wave | abs_NavyType |
abs_Anim | abs_ParticleSystem | abs_Tag | abs_SpawnManager |
abs_AnimType | abs_ParticleSystemType | abs_TagType | abs_CaptureManager |
abs_Building | abs_Script | abs_Tiberium | abs_Parasite |
abs_BuildingType | abs_ScriptType | abs_Action | abs_Bomb |
abs_Bullet | abs_Side | abs_Event | abs_RadSite |
abs_BulletType | abs_Smudge | abs_WeaponType | abs_Temporal |
abs_Campaign | abs_SmudgeType | abs_WarheadType | abs_Airstrike |
abs_Cell | abs_Special | abs_Waypoint | abs_SlaveManager |
abs_Factory | abs_SuperWeaponType | abs_Abstract | abs_DiskLaser |
abs_House | abs_TaskForce | abs_Tube | |
abs_HouseType | abs_Team | abs_EMPulse | |
abs_Infantry | abs_TeamType | abs_TacticalMap | |
abs_InfantryType | abs_Terrain | abs_Super | |
abs_Isotile | abs_TerrainType | abs_AITrigger | |
abs_IsotileType | abs_Trigger | abs_AITriggerType | |
abs_LightSource | abs_TriggerType | abs_Neuron |
How do I best figure out stuff like "Is this object of this particular BuildingType?" (e.g. "Is this a GADEPT?")
Each individual object blueprint, i.e. any Building-, Vehicle-, etc. Type defined in the INI, is stored as an instance of *TypeClass.
Each individual object of that type (*Class objects) will point back to that *TypeClass as its type.
Therefore, what you do is obtain a pointer to that particular *TypeClass, and compare it against the pointer an object returns for its type.
If both pointers point to the same *TypeClass, the object is of the type you are comparing against.
The easiest approach is to grab the pointer to the comparison *TypeClass right when reading the INI and storing it; assume we have a section like this:
[SomeVehicle] CanDoStuffWith=GADEPT
Now when we parse the INI, we read "GADEPT" and then obtain the pointer to the general GADEPT type object:
void FooExt::ExtData::LoadFromINIFile(FooClass *pThis, CCINIClass *pINI) { // note that the following read is performed from the owning object's INI section - the same way works in Rules, where an object called MTNK has a section [MTNK] // only store if the flag is actually set to something if(pINI->ReadString(pThis->ID, "CanDoStuffWith", "", Ares::readBuffer, Ares::readLength)) { // ::Find iterates the currently declared BuildingTypes array and returns pointer to the one with the ID given as argument this->BuildingTypeICanDoStuffWith = BuildingTypeClass::Find(Ares::readBuffer); } }
So far so good. Now we have a pointer to the BuildingType GADEPT stored in the property BuildingTypeICanDoStuffWith
. And now all we have to do is compare any given object's type against that:
// assuming pSomeVehicleExt is the pointer to SomeExt::ExtData, where your extension variables should be saved // and pSomeBuilding is the building whose type you want to check if(pSomeBuilding->Type == pSomeVehicleExt->BuildingTypeICanDoStuffWith) { // The building's type is the same as the type you got from the INI }
Hierarchy Traversal
I have a pointer to a given game object/class - how do I get its type class?
- ptr->GetType() returns an ObjectTypeClass * to the type data
- On TechnoClass and its derivates, ptr->GetTechnoType() returns a TechnoTypeClass * to the same type data
..both of them are actually pointers to the final derived type of the object, just downcasted (this is a C++ covariant return type limitation). So if you know the exact type you need and are sure that the object's type is appropriate, you can just do
reinterpret_cast<TargetTypeClass *>(ptr->GetTechnoType())
and that's it.
I have a Techno-/ObjectClass-derived pointer, how do I get the exact (Building|Infantry|Vehicle|Aircraft)Class pointer?
Sometime in the future, there will be an automagic way to do this. In the meantime, you have to do it the following way:
Use WhatAmI()
as you learned above to safeguard a cast to the correct type.
if(ptr->WhatAmI() == abs_Building) { BuildingClass * pBuilding = reinterpret_cast<BuildingClass *>(ptr); } /* the intelligent casts like dynamic won't work, as they rely on the RTTI which is likely to be different between the game's and Ares's objects. Additionally, do not just (BuildingClass *)ptr instead. Seriously. */
I have a Techno-/ObjectTypeClass-derived pointer, how do I get the exact (Building|Infantry|Vehicle|Aircraft)TypeClass pointer?
I have a pointer to a given game object/class - how do I get that class's Ares extension?
Unlike the game's classes which are in a hierarchy, Ares's extension classes are all siblings. That means that a BuildingExt doesn't contain TechnoExt even though it seems like it should.
Therefore, you need the ExtMap. ExtMap should be a static member of all extension classes, and has a .Find member function that allows you to find the correct ExtData block in the correct type for a given object.
- If you need data from TechnoTypeExt, you call TechnoTypeExt::ExtMap.Find(ptr) and receive a TechnoTypeExt * associated with this object.
- If you need data from BuildingTypeExt, you call BuildingTypeExt::ExtMap.Find(ptr) and receive a BuildingTypeExt * associated with this object.
- If you need data from BuildingExt, you call BuildingExt::ExtMap.Find(ptr) and receive a BuildingExt * associated with this object.
Remember to always ensure you're trying to get the correct ExtData, e.g. don't try to get *TypeExt on a non-type or vice versa.
Find might return NULL if there is no data associated with this object, but that shouldn't happen normally, all objects which can have extension data are attached to the ExtMap when they are created/destroyed. So you don't need to check for NULL when you fetch it.
Example
- from BulletExt::ExtData::DamageOccupants()
The function has a bullet (TheBullet), and needs the Ares extension of the bullet's type:
BulletTypeExt::ExtData* TheBulletTypeExt = BulletTypeExt::ExtMap.Find(TheBullet->Type);
...and that's it.
I have a given ExtData block - how do I get the game object it belongs to?
Every Ares extension has an AttachedToObject
pointer that links back to the game object this extension belongs to.
Example
- from BulletExt::ExtData::DamageOccupants()
BulletClass* TheBullet = this->AttachedToObject;