Panda3D Manual: DC File

The .dc file defines what distributed objects, and their functions, are communicated across the network.

This is the direct.dc file, which defines the necessary functionality for the distributed objects bundled with panda3d.

The syntax is based on C++ as, at the time, Panda was C++ only.

Here is the complete example with line by line explanation to follow.

// Comments are with two slashes
// Like C most lines must end with semicolons, except for the import statements
 
//keyword required;
keyword broadcast;
keyword ram;
//keyword db;
keyword p2p;
// keyword clsend;
 
// Currently unknown if these are implemented in the CMU distributed system.
 
// ownsend;
// airecv; // Special message to be received only by the AI, which will be described later. Not implimented
 
from direct.distributed import DistributedObject/AI
from direct.distributed import TimeManager/AI
from direct.distributed import DistributedNode/AI
from direct.distributed import DistributedSmoothNode/AI
 
struct BarrierData {
uint16 context;
string name;
uint32 avIds[];
};
 
// The most fundamental class mapped to a python object.
dclass DistributedObject {
// These are used to support DistributedObjectAI.beginBarrier() and
// the matching DistributedObject.doneBarrier(). If you do not call
// these functions, you don't care about these distributed methods.
// (Actually, you probably don'
t care anyway.)
setBarrierData(BarrierData data[]) broadcast ram;
setBarrierReady(uint16 context);
setLocation(uint32 parentId, uint32 zoneId) broadcast ram;
};
 
dclass TimeManager: DistributedObject {
requestServerTime(uint8 context) p2p;
serverTime(uint8 context, int32 timestamp);
};
 
 
// Inheritance of other dc definitions is allowed with the syntax: dclass NewObject: ParentObject {};
dclass DistributedNode: DistributedObject {
setX(int16 / 10) broadcast ram;
setY(int16 / 10) broadcast ram;
setZ(int16 / 10) broadcast ram;
setH(int16 % 360 / 10) broadcast ram;
setP(int16 % 360 / 10) broadcast ram;
setR(int16 % 360 / 10) broadcast ram;
 
setPos: setX, setY, setZ;
setHpr: setH, setP, setR;
setPosHpr: setX, setY, setZ, setH, setP, setR;
setXY: setX, setY;
setXZ: setX, setZ;
setXYH: setX, setY, setH;
setXYZH: setX, setY, setZ, setH;
};
 
dclass DistributedSmoothNode: DistributedNode {
// Component set pos and hpr functions.
 
setComponentL(uint64) broadcast ram;
setComponentX(int16 / 10) broadcast ram;
setComponentY(int16 / 10) broadcast ram;
setComponentZ(int16 / 10) broadcast ram;
setComponentH(int16 % 360 / 10) broadcast ram;
setComponentP(int16 % 360 / 10) broadcast ram;
setComponentR(int16 % 360 / 10) broadcast ram;
setComponentT(int16 timestamp) broadcast ram;
 
// Composite set pos and hpr functions. These map to combinations
// of one or more of the above components. They all include
// setComponentT(), which must be called last.
setSmStop: setComponentT;
setSmH: setComponentH, setComponentT;
setSmZ: setComponentZ, setComponentT;
setSmXY: setComponentX, setComponentY, setComponentT;
setSmXZ: setComponentX, setComponentZ, setComponentT;
setSmPos: setComponentX, setComponentY, setComponentZ, setComponentT;
setSmHpr: setComponentH, setComponentP, setComponentR, setComponentT;
setSmXYH: setComponentX, setComponentY, setComponentH, setComponentT;
setSmXYZH: setComponentX, setComponentY, setComponentZ, setComponentH, setComponentT;
setSmPosHpr: setComponentX, setComponentY, setComponentZ, setComponentH, setComponentP, setComponentR, setComponentT;
// special update if L (being location, such as zoneId) changes, send everything, intended to
// keep position and 'location' in sync
setSmPosHprL: setComponentL, setComponentX, setComponentY, setComponentZ, setComponentH, setComponentP, setComponentR, setComponentT;
 
clearSmoothing(int8 bogus) broadcast;
 
suggestResync(uint32 avId, int16 timestampA, int16 timestampB,
int32 serverTimeSec, uint16 serverTimeUSec,
uint16 / 100 uncertainty);
returnResync(uint32 avId, int16 timestampB,
int32 serverTimeSec, uint16 serverTimeUSec,
uint16 / 100 uncertainty);
};

Keywords

//keyword required;
keyword broadcast;
keyword ram;
//keyword db;
keyword p2p;
//keyword clsend;
 
// Currently unknown if these are implemented in the CMU distributed system.
// ownsend;
// aireceive;

Keywords define the circumstances for propagating the data. They must be defined at the start of the file.

  1. required: The parameters must be defined when generate() is called.
  2. broadcast: By default only the owner of the object will receive update messages. With the broadcast tag all copies of the object will receive the message. This will be the most frequently sued tag in most cases, leave off when you only want the owner of the object to receive a message such as a private chat, receiving gold, etd.
  3. ram: Normally the values sent over the wire will only be received by the interested clients, but a new client will not receive previously sent values. This is useful for things like chat. The values passed with a ram keyword will persist in memory and new clients will receive messages previously sent. This will be useful for things like position or names.
  4. db: Values stored into a database. This is currently not implemented in the CMU open source distributed system.
  5. p2p: Normally the owner of the object is the only one able to call the remote functions on other clients. The p2p tag allows any client to call remote functions.
  6. clsend: Without this field other clients are unable to set this field. If this field is set then any client may.
  7. aireceive: Special message to be received only by the AI, which will be described later

Python Imports

from direct.distributed import DistributedObject/AI
from direct.distributed import TimeManager/AI
from direct.distributed import DistributedNode/AI
from direct.distributed import DistributedSmoothNode/AI

Any python objects to be mapped for distributed networking should be imported here. A modified python syntax is used. In the first line DistributedObject.py and DistributedObjectAI.py will be mapped. The purpose for *AI.py files will be described in a later section.

Structs

struct BarrierData {
uint16 context;
string name;
uint32 avIds[];
};

You can define C-style structs in addition to the dclass (defined below). This is really the same thing as a dclass, except it can be embedded in a message rather than created as an object in its own right. The struct may or may not correspond with a Python class of the same name. If the struct does have a Python representation, an instance of that class is created and passed in to functions that receive this kind of parameter; otherwise, a tuple with all of the fields is passed instead.

Variable Types

Due to the nature of the underlaying datagram network system there are several fields, or containers, that can be used to transmit data. The "smaller" the package you can use, the less bandwidth used. Like C and unlike python the variables need to be typed.

Possible types are:

  1. int8, int16, int32, and int64: Integer values and bit size and uint* for unsigned integers.
  2. float64: A C double, for floating point numbers
  3. string: An arbitrary string up to 64k in length. Obviously bandwidth intensive so avoid for frequent communication
  4. char: Same as int8 but will be realized as a character
  5. blob: String but arbitrary byte sequence usually not intended for print or something encoded that is too complicated for the normal dc system
  6. Structures can also be identified as well.

dclass

dclass DistributedNode: DistributedObject {

Here the methods to be mapped in DistributedNode AND DistributedNodeAI are defined. Note that this inherits the definition of DistributedObject. Multiple inheritance is also allowed.

setX(int16 / 10) broadcast ram;
setY(int16 / 10) broadcast ram;
setZ(int16 / 10) broadcast ram;

Here are three function definitions. When a DistributedNode receives a message with the name "setX", DistributedNode.setX() will be called and the values passed to the function.

Syntax: functionName(container variable1 <, container variable 2,...>) <parameters>;

To conserve bandwidth when passing small float values it is possible to convert them into ints by multiplying them by the given value and dividing them again. int16 / 10 gives single point precision for values between -3276.7 to 3276.7. int16 / 100 will give two point precision for values between -327.67 and 327.67.

setH(int16 % 360 / 10) broadcast ram;
setP(int16 % 360 / 10) broadcast ram;
setR(int16 % 360 / 10) broadcast ram;
 
setPos: setX, setY, setZ;
setHpr: setH, setP, setR;
setPosHpr: setX, setY, setZ, setH, setP, setR;
setXY: setX, setY;
setXZ: setX, setZ;
setXYH: setX, setY, setH;
setXYZH: setX, setY, setZ, setH;
};

These messages are composed of previously defined messages. The message "setPos" will contain the message "setX", "setY", "setZ" and their appropriate values.