![]() TGE Version 1.5.2 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
NetObject Class Reference#include <netObject.h>
Inheritance diagram for NetObject: ![]() Detailed DescriptionSuperclass for ghostable networked objects.
Introduction To NetObject And GhostingOne of the most powerful aspects of Torque's networking code is its support for ghosting and prioritized, most-recent-state network updates. The way this works is a bit complex, but it is immensely efficient. Let's run through the steps that the server goes through for each client in this part of Torque's networking:
There several significant advantages to using this networking system:
NetConnection contains the Ghost Manager implementation, which deals with transferring data to the appropriate clients and keeping state in synch. An Example ImplementationThe basis of the ghost implementation in Torque is NetObject. It tracks the dirty flags for the various states that the object trackers, and does some other book-keeping to allow more efficient operation of the networking layer.Using a NetObject is very simple; let's go through a simple example implementation:
class SimpleNetObject : public NetObject { public: typedef NetObject Parent; DECLARE_CONOBJECT(SimpleNetObject); Above is the standard boilerplate code for a Torque class. You can find out more about this in SimObject.
char message1[256]; char message2[256]; enum States { Message1Mask = BIT(0), Message2Mask = BIT(1), }; For our example, we're having two "states" that we keep track of, message1 and message2. In a real object, we might map our states to health and position, or some other set of fields. You have 32 bits to work with, so it's possible to be very specific when defining states. In general, you should try to use as few states as possible (you never know when you'll need to expand your object's functionality!), and in fact, most of your fields will end up changing all at once, so it's not worth it to be too fine-grained. (As an example, position and velocity on Player are controlled by the same bit, as one rarely changes without the other changing, too.)
SimpleNetObject() { // in order for an object to be considered by the network system, // the Ghostable net flag must be set. // the ScopeAlways flag indicates that the object is always scoped // on all active connections. mNetFlags.set(ScopeAlways | Ghostable); dStrcpy(message1, "Hello World 1!"); dStrcpy(message2, "Hello World 2!"); } Here is the constructor. Here, you see that we initialize our net flags to show that we should always be scoped, and that we're to be taken into consideration for ghosting. We also provide some initial values for the message fields.
U32 packUpdate(NetConnection *, U32 mask, BitStream *stream) { // check which states need to be updated, and update them if(stream->writeFlag(mask & Message1Mask)) stream->writeString(message1); if(stream->writeFlag(mask & Message2Mask)) stream->writeString(message2); // the return value from packUpdate can set which states still // need to be updated for this object. return 0; } Here's half of the meat of the networking code, the packUpdate() function. (The other half, unpackUpdate(), we'll get to in a second.) The comments in the code pretty much explain everything, however, notice that the code follows a pattern of if(writeFlag(mask & StateMask)) { ... write data ... }. The packUpdate()/unpackUpdate() functions are responsible for reading and writing the dirty bits to the bitstream by themselves.
void unpackUpdate(NetConnection *, BitStream *stream) { // the unpackUpdate function must be symmetrical to packUpdate if(stream->readFlag()) { stream->readString(message1); Con::printf("Got message1: %s", message1); } if(stream->readFlag()) { stream->readString(message2); Con::printf("Got message2: %s", message2); } } The other half of the networking code in any NetObject, unpackUpdate(). In our simple example, all that the code does is print the new messages to the console; however, in a more advanced object, you might trigger animations, update complex object properties, or even spawn new objects, based on what packet data you unpack.
void setMessage1(const char *msg) { setMaskBits(Message1Mask); dStrcpy(message1, msg); } void setMessage2(const char *msg) { setMaskBits(Message2Mask); dStrcpy(message2, msg); } Here are the accessors for the two properties. It is good to encapsulate your state variables, so that you don't have to remember to make a call to setMaskBits every time you change anything; the accessors can do it for you. In a more complex object, you might need to set multiple mask bits when you change something; this can be done using the | operator, for instance, setMaskBits( Message1Mask | Message2Mask ); if you changed both messages.
IMPLEMENT_CO_NETOBJECT_V1(SimpleNetObject); ConsoleMethod(SimpleNetObject, setMessage1, void, 3, 3, "(string msg) Set message 1.") { object->setMessage1(argv[2]); } ConsoleMethod(SimpleNetObject, setMessage2, void, 3, 3, "(string msg) Set message 2.") { object->setMessage2(argv[2]); } Finally, we use the NetObject implementation macro, IMPLEMENT_CO_NETOBJECT_V1(), to implement our NetObject. It is important that we use this, as it makes Torque perform certain initialization tasks that allow us to send the object over the network. IMPLEMENT_CONOBJECT() doesn't perform these tasks, see the documentation on AbstractClassRep for more details.
Member Typedef Documentation
Reimplemented from SimObject. Reimplemented in AIPlayer, AIWheeledVehicle, AudioEmitter, Camera, Debris, FireballAtmosphere, Explosion, fxFoliageReplicator, fxLight, fxRenderObject, fxShapeReplicatedStatic, fxShapeReplicator, fxSunLight, Lightning, ParticleEmitterNode, ParticleEmitter, Precipitation, Splash, WeatherLightning, GameBase, Item, MissionArea, MissionMarker, SpawnSphere, PathCamera, PhysicalZone, Player, Projectile, RigidShape, ShapeBase, ShowTSShape, StaticShape, Trigger, TSStatic, FlyingVehicle, HoverVehicle, Vehicle, VehicleBlocker, WheeledVehicle, InteriorInstance, InteriorMap, InteriorSubObject, MirrorSubObject, PathedInterior, sgLightObject, sgMissionLightingFilter, volumeLight, SceneRoot, DecalManager, SceneObject, Marker, Sky, Sun, TerrainBlock, and WaterBlock.
Member Enumeration Documentation
Constructor & Destructor Documentation
Member Function Documentation
Register dynamic fields in a subclass of ConsoleObject.
Reimplemented from SimObject. Reimplemented in AudioEmitter, Camera, Debris, FireballAtmosphere, Explosion, fxFoliageReplicator, fxLight, fxRenderObject, fxShapeReplicator, fxSunLight, Lightning, ParticleEmitterNode, Precipitation, WeatherLightning, GameBase, Item, MissionArea, MissionMarker, SpawnSphere, PathCamera, PhysicalZone, Projectile, RigidShape, StaticShape, Trigger, TSStatic, FlyingVehicle, Vehicle, VehicleBlocker, WheeledVehicle, InteriorInstance, InteriorMap, MirrorSubObject, PathedInterior, sgLightObject, sgMissionLightingFilter, volumeLight, SceneObject, Marker, Sky, Sun, TerrainBlock, and WaterBlock.
Called when the object is added to the sim.
Reimplemented from SimObject. Reimplemented in AudioEmitter, Camera, Debris, FireballAtmosphere, Explosion, fxFoliageReplicator, fxLight, fxRenderObject, fxShapeReplicator, fxSunLight, Lightning, ParticleEmitterNode, ParticleEmitter, Precipitation, Splash, WeatherLightning, GameBase, Item, MissionArea, MissionMarker, SpawnSphere, PathCamera, PhysicalZone, Player, Projectile, RigidShape, ShapeBase, ShowTSShape, StaticShape, Trigger, TSStatic, FlyingVehicle, HoverVehicle, Vehicle, VehicleBlocker, WheeledVehicle, InteriorInstance, InteriorMap, PathedInterior, sgLightObject, sgMissionLightingFilter, volumeLight, SceneObject, Marker, Sky, Sun, TerrainBlock, and WaterBlock.
Called when the object is removed from the sim.
Reimplemented from SimObject. Reimplemented in AudioEmitter, Camera, Debris, FireballAtmosphere, Explosion, fxFoliageReplicator, fxLight, fxRenderObject, fxShapeReplicator, fxSunLight, Lightning, ParticleEmitterNode, ParticleEmitter, Precipitation, Splash, WeatherLightning, GameBase, Item, MissionMarker, PathCamera, PhysicalZone, Player, Projectile, RigidShape, ShapeBase, ShowTSShape, StaticShape, Trigger, TSStatic, FlyingVehicle, HoverVehicle, Vehicle, VehicleBlocker, WheeledVehicle, InteriorInstance, InteriorMap, PathedInterior, sgMissionLightingFilter, volumeLight, SceneObject, Marker, Sky, TerrainBlock, and WaterBlock.
Used to mark a bit as dirty; ie, that its corresponding set of fields need to be transmitted next update.
Clear the specified bits from the dirty mask.
Scope the object to all connections. The object is marked as ScopeAlways and is immediately ghosted to all active connections. This function has no effect if the object is not marked as Ghostable.
Stop scoping the object to all connections. The object's ScopeAlways flag is cleared and the object is removed from all current active connections.
This returns a value which is used to prioritize which objects need to be updated. In NetObject, our returned priority is 0.1 * updateSkips, so that less recently updated objects are more likely to be updated. In subclasses, this can be adjusted. For instance, ShapeBase provides priority based on proximity to the camera.
Reimplemented in GameBase, Projectile, and ShapeBase.
Instructs this object to pack its state for transfer over the network.
Reimplemented in AudioEmitter, Camera, FireballAtmosphere, fxFoliageReplicator, fxLight, fxRenderObject, fxShapeReplicator, fxSunLight, Lightning, ParticleEmitterNode, Precipitation, Splash, WeatherLightning, GameBase, Item, MissionArea, MissionMarker, SpawnSphere, PathCamera, PhysicalZone, Player, Projectile, RigidShape, ShapeBase, StaticShape, Trigger, TSStatic, FlyingVehicle, HoverVehicle, Vehicle, VehicleBlocker, WheeledVehicle, InteriorInstance, InteriorMap, PathedInterior, sgLightObject, sgMissionLightingFilter, volumeLight, Marker, Sky, Sun, TerrainBlock, and WaterBlock.
Instructs this object to read state data previously packed with packUpdate.
Reimplemented in AudioEmitter, Camera, FireballAtmosphere, fxFoliageReplicator, fxLight, fxRenderObject, fxShapeReplicator, fxSunLight, Lightning, ParticleEmitterNode, Precipitation, Splash, WeatherLightning, GameBase, Item, MissionArea, MissionMarker, SpawnSphere, PathCamera, PhysicalZone, Player, Projectile, RigidShape, ShapeBase, StaticShape, Trigger, TSStatic, FlyingVehicle, HoverVehicle, Vehicle, VehicleBlocker, WheeledVehicle, InteriorInstance, InteriorMap, PathedInterior, sgLightObject, sgMissionLightingFilter, volumeLight, Marker, Sky, Sun, TerrainBlock, and WaterBlock.
Queries the object about information used to determine scope. Something that is 'in scope' is somehow interesting to the client. If we are a NetConnection's scope object, it calls this method to determine how things should be scoped; basically, we tell it our field of view with camInfo, and have the opportunity to manually mark items as "in scope" as we see fit. By default, we just mark all ghostable objects as in scope.
Get the ghost index of this object.
Is this a server object?
Is this a client object?
Is this is a ghost?
Should this object only be visible to the client which created it?
Is this object subject to scoping?
Is this object ghostable?
Should this object always be ghosted?
Friends And Related Function Documentation
Reimplemented in GameBase.
Field Documentation
Mask indicating which states are dirty and need to be retransmitted on this object.
Static pointer to the head of the dirty NetObject list.
Next item in the dirty list...
Previous item in the dirty list...
Pointer to the server object; used only when we are doing "short-circuited" networking. When we are running with client and server on the same system (which can happen be either when we are doing a single player game, or if we're hosting a multiplayer game and having someone playing on the same instance), we can do some short circuited code to enhance performance. This variable is used to make it simpler; if we are running in short-circuited mode, it's set to the object on the server that this NetObject is ghosting.
Flag values from NetFlags.
The index of this ghost in the GhostManager on the server.
Head of a linked list storing GhostInfos referencing this NetObject.
|