Generalities On Entities: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
(reworked to resolve POV issues.)
Line 1: Line 1:
{{tutpov}}
[[Category:Programming]]
[[Category:Programming]]


== Introduction ==
{{note|This article assumes that the reader has at least basic experience in C++}}
{{note|This article assumes that the reader has at least basic experience in C++}}


== Introduction ==
This article is mainly about entities in the Source engine and will try to explain everything about entities.
This article is mainly about entities in the Source engine and will try to explain everything about entities.


Line 10: Line 9:


== Naming Conventions ==
== Naming Conventions ==
In the Source engine, all class names begin with a capital <code>C</code>. Furthermore, on the client, the names begin with <code>C_</code> to differentiate them from their server counterparts.
 
Within the Source SDK, server classes begin with a capital C (<code>C</code>), while client classes begin with a capital C followed by an underscore (<code>C_</code>) - this helps differentiate between the two code bases.


For example:
For example:
Line 17: Line 17:
  Client: C_MyEntity
  Client: C_MyEntity


More information about these naming convention can be found at [[Wikipedia:Hungarian Notation|Hungarian Notation]]. Following this will save time later because classes and its variables will be easier to read.
The style of naming convention followed through the SDK code base is known as [[Wikipedia:Hungarian Notation|Hungarian Notation]]. Beginners are recommended to maintain the same style as used throughout the code base to save confusion.


== Which base class? ==
== Base Classes ==
Every entity is based on <code>CBaseEntity</code>, however there are many derived classes. Here's a short list with the most famous ones:
Every entity is based on <code>CBaseEntity</code>, however there are many derived classes. The following is a list of the more common derived classes.


=== CBaseAnimating ===
=== CBaseAnimating ===
Every model that has a model uses CBaseAnimating. Classes derived from CBaseAnimating can set a model and animate.
Every model that has a model uses CBaseAnimating. Classes derived from CBaseAnimating can set a model and animate.
{{note|Entities without models are not networked. A workaround is <code>AddEFlags( EFL_FORCE_CHECK_TRANSMIT );</code>}}
{{note|Entities without models are not networked by default. A workaround is <code>AddEFlags( EFL_FORCE_CHECK_TRANSMIT );</code>}}


=== CBaseTrigger ===
=== CBaseTrigger ===
This entity is only used by mappers. Mappers need [[trigger|triggers]] for their maps.
[[trigger|Triggers]] are brush based entities that are generally placed during the map creation process.


=== CBasePlayer ===
=== CBasePlayer ===
Line 42: Line 42:


=== Server side ===
=== Server side ===
On the server, coders have the option to define multiple think-functions. However, only 1 think function can be called each time.
On the server, coders have the option to define multiple think-functions. However, only one think function can be called each time.


====SetThink() and SetNextThink()====
====SetThink() and SetNextThink()====
With the function <code>SetThink</code> it's possible to set the think-function. With the function <code>SetNextThink</code> the time is set when the function should be called.
With the function <code>SetThink</code> it is possible to set the think-function. With the function <code>SetNextThink</code> the time is set when the function should be called.


For example:
For example:
Line 60: Line 60:


===Client Side===
===Client Side===
As I said before, the client does not have the same System for entities to think. These Client Thinks are handled in <code>client_thinklist.cpp</code>. You cannot define multiple think functions here, as SetThink will not work properly on this side. Instead, you must use the following:
The client does not provide the same methods for entities to think. These Client Thinks are handled in <code>client_thinklist.cpp</code>. Multiple think functions cannot be defined here, as SetThink will not work properly on this side. Instead, <code>ClientThink</code> and <code>SetNextClientThink()</code> should be used.


====ClientThink() and SetNextClientThink()====
====ClientThink() and SetNextClientThink()====
These are the equivalent of the server system, except you only have one function at your disposal here (which sucks a bit for organization, but oh well). This will get called based on the SetNextClientThink() time you set in Spawn, and in subsequent calls to ClientThink(). You can use two special time settings here: [[CLIENT_THINK_ALWAYS]] and [[CLIENT_THINK_NEVER]].
These are the equivalent of the server system, except only one function can be used. This will get called based on the SetNextClientThink() time set in the Spawn function, and in subsequent calls to ClientThink(). Two special time settings here: [[CLIENT_THINK_ALWAYS]] and [[CLIENT_THINK_NEVER]].


====Simulate()====
====Simulate()====
Here's the commentary in c_baseentity.cpp: ''"Once-per-frame stuff should go in Simulate()."'' That really sums it up. I personally use Simulate() mainly for Particle effects, or graphical effects of any sorts. Beware of what you run in Simulate(), as said before, this gets run EVERY FRAME, meaning you should avoid creating 50 new particles every Frame ;)
Here's the commentary in c_baseentity.cpp: ''"Once-per-frame stuff should go in Simulate()."'' That really sums it up. Generally Simulate() should be used for Particle effects and other such graphical effects. Beware of what is run in Simulate(), because it is run every frame checks should be made to ensure that nothing too intensive is being called continuously.
 
That's about it I believe. Think functions are an essential part of any entity and you should learn to use them well.


== Macros ==
== Macros ==
I want to dedicate an entire chapter to these Macros, because they are what causes problems with entities at least 60% of the time. Badly set up macros will give you errors messages, crash your game, give you erratic behavior, and so forth. I'm going to try to sum up most of them and a few more tips as best as I can:
Badly set up macros will give cause errors messages, crash the game and cause erratic behavior. The following is a list of the more common macro definitions and some of the issues that surround them.


===[[LINK_ENTITY_TO_CLASS]]()===
===[[LINK_ENTITY_TO_CLASS]]()===
This is your main macro. You do not have an entity until you call this macro. This macro will NAME your entity for the game. Anytime you call GetClassname() on an entity, this is the name that will be returned on the server side. There is a subtlety however, which is that, on the client side, the entity name will not be the one you give to [[LINK_ENTITY_TO_CLASS]] unless you  make a DATADESC. Instead, it returns (client-side) something like "class C_MyEntity".  
This is one of the main macros. An entity cannot be created without this macro being used to define the entity's classname (as returned from <code>GetClassname()</code> on the server). However, on the client, an entity will not return it's classname unless there is a matching data description (<code>DATADESC</code>).


===[[PRECACHE_REGISTER]]()===
===[[PRECACHE_REGISTER]]()===
This is used to tell the engine that it needs to precache your entity when it loads. You pass it the name of your entity (the same you passed to [[LINK_ENTITY_TO_CLASS]]() ).
This is used to tell the engine that it needs to precache the entity when it loads. This is provided with the name of the entity (the same name as passed to [[LINK_ENTITY_TO_CLASS]]() ).


===[[DECLARE_CLASS]]()===
===[[DECLARE_CLASS]]()===
You need to put this in your Class definition, in a public section. This gives you access to the BaseClass Macro, which is very handy. I believe it also helps to set up some networking stuff.
This should be placed in the public section of an entities Class definition. This provides access to the BaseClass Macro.


===DECLARE_[[DATADESC]](), BEGIN_[[DATADESC]](), END_[[DATADESC]](), and DEFINE_XXX()===
===DECLARE_[[DATADESC]](), BEGIN_[[DATADESC]](), END_[[DATADESC]](), and DEFINE_XXX()===
This set of macros is used for two main things:
First, you need it if you're going to have think functions.
Second, I believe it takes care of saving any variable that is defined in the set for Single Player Games, and restoring their values when you load a saved game.
I refer you to the Valve tutorial [http://developer.valvesoftware.com/wiki/Data_Descriptions Data Descriptions] for more info.


===Networking Entities=== I was going to explain a little bit about networking entities and networked variables and such, but there are already a lot of nice tutorials by Valve that explain it all in detail. See the [[:Category:Programming#Networking|network section]] section in this wiki's [[:Category:Programming|programming category]].
The Data Description macros provide for a number of different features;
* Specifying Think and Touch functions
* Providing Inputs and Outputs for mappers
* Providing external variable inputs (such as setting a model or the health of an item)


== Conclusion ==
Further information is available on the [http://developer.valvesoftware.com/wiki/Data_Descriptions Data Descriptions] page.
I have only brushed the surface here. I have been working with this SDK for over 8 months now, and I learn something new about it every time I open it. It is complex, it is vast, and you will not learn all about it by just reading tutorials. The best way to do it has always been for me to JUST DO IT. You take an idea, something you want to add to your MOD. You look around source with a few keywords to see what's already been done. You search on a few forums and see if it's already been discussed. You look at tutorial sites and see if anything relates to it. Once you have a good idea on how you're gonna do it, well you just dive in the deep end and start coding it!


I hope you've learned something from this tutorial. Once again, if I mislead you in anyway, it is not intentional. This is all of what I have learned through months of trial and error and I hope it speeds up your progress in learning more about this SDK.
===Networking Entities===


Good Luck.
See the [[:Category:Programming#Networking|Networking]] section for more information on networking entities, as that is outside the scope of this article.
Imperio59

Revision as of 18:31, 16 January 2007


Introduction

Note.pngNote:This article assumes that the reader has at least basic experience in C++

This article is mainly about entities in the Source engine and will try to explain everything about entities.

Every object, even the world, is an entity in the Source engine. All entities are derived from CBaseEntity.

Naming Conventions

Within the Source SDK, server classes begin with a capital C (C), while client classes begin with a capital C followed by an underscore (C_) - this helps differentiate between the two code bases.

For example:

Server: CMyEntity
Client: C_MyEntity

The style of naming convention followed through the SDK code base is known as Hungarian Notation. Beginners are recommended to maintain the same style as used throughout the code base to save confusion.

Base Classes

Every entity is based on CBaseEntity, however there are many derived classes. The following is a list of the more common derived classes.

CBaseAnimating

Every model that has a model uses CBaseAnimating. Classes derived from CBaseAnimating can set a model and animate.

Note.pngNote:Entities without models are not networked by default. A workaround is AddEFlags( EFL_FORCE_CHECK_TRANSMIT );

CBaseTrigger

Triggers are brush based entities that are generally placed during the map creation process.

CBasePlayer

This entity is the player itself. Every player-entity in the game is CBasePlayer or is derived from this entity.

CGameRules

This entity regulates the rules of the current game. It's mainly the gameplay.

CBaseCombatCharacter

Every NPC & player are derived from this class.

Think Functions

Think functions are very important in the Source engine. Each entity "thinks", which is essentially just calling a function of that entity.

Server side

On the server, coders have the option to define multiple think-functions. However, only one think function can be called each time.

SetThink() and SetNextThink()

With the function SetThink it is possible to set the think-function. With the function SetNextThink the time is set when the function should be called.

For example:

SetThink(&CBasePlayer::DeathThink);
SetNextThink( gpGlobals->curtime + 0.1f );

This piece of code will make sure that the function PlayerDeathThink is called over 0.1 seconds. It the think-function needs to be called so fast as possible, setting the time to gpGlobals->curtime + 0.01f would be better. When it's set to the current time, it may not work and the Source engine doesn't ever tick faster then 0.01 seconds. Please note that after this call, the think-function is not called anymore. To keep it being called, a SetNextThink call is needed in the function.

Every think-function needs to be defined in the datadesc of the entity. For example: BEGIN_DATADESC( CBasePlayer) DEFINE_THINKFUNC( DeathThink), END_DATADESC()

Client Side

The client does not provide the same methods for entities to think. These Client Thinks are handled in client_thinklist.cpp. Multiple think functions cannot be defined here, as SetThink will not work properly on this side. Instead, ClientThink and SetNextClientThink() should be used.

ClientThink() and SetNextClientThink()

These are the equivalent of the server system, except only one function can be used. This will get called based on the SetNextClientThink() time set in the Spawn function, and in subsequent calls to ClientThink(). Two special time settings here: CLIENT_THINK_ALWAYS and CLIENT_THINK_NEVER.

Simulate()

Here's the commentary in c_baseentity.cpp: "Once-per-frame stuff should go in Simulate()." That really sums it up. Generally Simulate() should be used for Particle effects and other such graphical effects. Beware of what is run in Simulate(), because it is run every frame checks should be made to ensure that nothing too intensive is being called continuously.

Macros

Badly set up macros will give cause errors messages, crash the game and cause erratic behavior. The following is a list of the more common macro definitions and some of the issues that surround them.

LINK_ENTITY_TO_CLASS()

This is one of the main macros. An entity cannot be created without this macro being used to define the entity's classname (as returned from GetClassname() on the server). However, on the client, an entity will not return it's classname unless there is a matching data description (DATADESC).

PRECACHE_REGISTER()

This is used to tell the engine that it needs to precache the entity when it loads. This is provided with the name of the entity (the same name as passed to LINK_ENTITY_TO_CLASS() ).

DECLARE_CLASS()

This should be placed in the public section of an entities Class definition. This provides access to the BaseClass Macro.

DECLARE_DATADESC(), BEGIN_DATADESC(), END_DATADESC(), and DEFINE_XXX()

The Data Description macros provide for a number of different features;

  • Specifying Think and Touch functions
  • Providing Inputs and Outputs for mappers
  • Providing external variable inputs (such as setting a model or the health of an item)

Further information is available on the Data Descriptions page.

Networking Entities

See the Networking section for more information on networking entities, as that is outside the scope of this article.