Authoring a Logical Entity

From Valve Developer Community
Revision as of 19:04, 4 August 2005 by CycloNurb (talk | contribs) (→‎Declaring a data description for the entity: (changed CBaseEntity to CLogicalEntity))
Jump to navigation Jump to search


To begin, we’ll create a logical entity to perform a simple bit of work for us. This entity will store a value and increment that value every time it receives an input from another entity. Once the counter has reached a value we’ll define, the entity will fire an output to allow it to alert other entities of the condition.

Create a .CPP file for the new entity

Add the source file to the server.dll project by right-clicking.

  • Create a file named sdk_logicalentity.cpp. The file should go under the dlls folder under your source code folder. For example, if you installed the source code into C:\MyMod\src, then you would create a file called C:\MyMod\src\dlls\sdk_logicalentity.cpp.
  • Next, copy this code and paste it into this new file.
  • Last, add this file to your server.dll project. If you opened the game_sdk.sln solution, then you can right-click on the hl project in the Solution Explorer window and choose Add, then Add Existing Item.

Walking Through The code

Class Definition

class CMyLogicalEntity : public CLogicalEntity
{
public:
       DECLARE_CLASS( CMyLogicalEntity, CLogicalEntity );
};

We descend our new entity from the CLogicalEntity class. This class is a server-side only entity and will not transmit data to the client. We also use the helper macro DECLARE_CLASS to assist in some behind the scenes bookkeeping. By declaring the relationship between CMyLogicalEntity and CLogicalEntity we are able to use the BaseClass type within this class. This will be useful later for calling up to the CLogicalEntity class we’re descended from.

Linking the class to an entity name

Next we’ll link the CMyLogicalEntity class to an actual entity classname that the game engine can reference.

LINK_ENTITY_TO_CLASS( logic_my_logical_entity, CMyLogicalEntity );

Here our class CMyLogicalEntity declares its classname as "my_logical_entity". This is the name that Hammer will use to refer to the entity type in the editor and is also how other entities will search and find our entity type. The classname varies from the targetname of the entity, which is a string that labels an individual or group of entities. The classname refers to all entities of a type, while the targetname can span multiple different types of entities (i.e. You may have an entity with a classname of env_splash belonging to a group of entities, all with the targetname of splash_group).

Adding member variables

int     m_nThreshold;  // Count at which to fire our output
int     m_nCounter;    // Internal counter

Here we declare two integer values, to be used later.

Declaring a data description for the entity

 . . .

public:
       DECLARE_CLASS( CMyLogicalEntity, CLogicalEntity);
       DECLARE_DATADESC();

 . . .

LINK_ENTITY_TO_CLASS( my_logical_entity, CMyLogicalEntity );
BEGIN_DATADESC( CMyLogicalEntity )

DEFINE_FIELD( m_nCounter, FIELD_INTEGER ),
DEFINE_KEYFIELD( m_nThreshold, FIELD_INTEGER, "threshold" ),

END_DATADESC()

The DECLARE_DATADESC macro must be included to let the compiler know that we’ll be adding a data description table later in the class implementation. The data description holds various definitions for the data members and special functions for this class. In this case, m_nCounter is defined for save/load functionality, and m_nThreshold is defined to tell the game to use the value named "threshold" to link this member variable to the entity keyvalue from Hammer. See the Data Description Table Document for more information.

Creating the output event

COutputEvent   m_OnThreshold;
DEFINE_OUTPUT( m_OnThreshold, "OnThreshold" ),

This outputevent will be triggered when we meet the defined threshold. For more information on outputs, see Entity Input and Outputs.
Creating the input function

void InputTick( inputdata_t &inputData );

void CMyLogicalEntity::InputTick( inputdata_t &inputData )
{
       // Increment our counter
       m_nCounter++;

       // See if we've met or crossed our threshold value
       if ( m_nCounter >= m_nThreshold )
       {
              // Fire an output event
              m_OnThreshold.FireOutput( inputData.pActivator, this );
             
              // Reset our counter
              m_nCounter = 0;
       }
}

This function simply increments a counter and fires an output when that counter reaches or exceeds a certain threshold value, as specified in the entity inside of Hammer. The function takes no parameters from Hammer.

Create The FGD Entry

To use the entity within Hammer, we’ll need to create an entry in our FGD file. Hammer will use this data to interpret the various keyvalues and functions the entity is exposing. See the FGD Format document for more information about FGD files.

If you haven't created a custom .FGD file for your mod, you may want to do it at this point. To do this, create an empty file with a .FGD extension anywhere on your hard drive (putting it under your mod's folder is a good idea). Then paste the code below into it. Go into Hammer and choose Tools->Options and add the .FGD file in the Game Data files section. The Game Configurations dialog is described in this document.

In this case we declare the "threshold" value we have linked to the m_nThreshold data member, the input function Tick and the OnThreshold output function.

@PointClass base(Targetname) = logic_my_logical_entity : "Tutorial logical entity."
[
       threshold(integer) : "Threshold" : 1 : "Threshold value."
       input Tick(void) : "Adds one tick to the entity's count."
       output OnThreshold(void) : "Threshold was hit."
]