That is, the server will, upon start up, instantiate a commlayer server object (which runs a thread
in the background) and register a call back function with it. That
call back function, void receive(char *message)
, will be
called every time a new packet comes in for the server off the
network.
receive()
is the most important function in the server.
It is responsible for updating the world based upon input it receives
from the clients. In order to avoid problems with the world being
updated while it is being sent out to the clients (mutual exclusion),
receive()
is also in charge of broadcasting the world.
After spawning the commlayer (which runs receive()
) the
"main" thread of the server has little to do but make sure that the
world gets broadcast some minimum number of times per second (probably
thirty). To do this, the thread will simply sleep for a quantum and
then use the commlayer to send()
a message to itself
telling receive()
that update time has come. We're
assuming that Microsoft has done the DirectPlay networking code right
and a message sent to localhost is very quick.
// Pseudocode for the server process // The main function doesn't do much. All the real work is being done // in receive() which is being called by a thread started in main. void winmain() { double frame_rate=30; // Create a new comm object to receive messages using DirectPlay OXL_Comm_Server commobj; // Use it to create a new thread and register the receive() function // as a callback when messages come in off the network. commobj.Create(winhandle, receive); // Now just make sure that an update message goes out to receive at // least frame_rate times per second. while(1) { millisleep(1000/frame_rate); commobj.SendSelf("update"); // Could also place non-player updates here. (I.e., AI luxos // that the server controls. However, it might be better just to // leave all that in receive(). } } // This is a callback function. Whenever a message comes in off the // network for the server, we get called with a null-terminated string // as the sole argument. We are in charge of updating the state of the // world based upon what the clients tell us and occasionally // broadcasting any delta information necessary to the clients. // // The possible messages receive can handle from a client are: // "clientid: status" // "clientid: action SOMEACTION" // "clientid: keydown CHAR" (where CHAR is a literal character) // "clientid: keyup CHAR" (where CHAR is a literal character) // "clientid: joystick AXIS NUM" // (where AXIS is which axis (x or y) that is being sent and NUM is // that's axis's coordinate normalized to be an int between 0 and 1000) // Additionally receive must handle a message from the server telling // it it is time to broadcast update information to all the clients: // "serverid: update" void receive(char *message) { const char id[80], verb[80], adjective[80]; sscanf(message, "%s: %s %s %s", id, verb, adjective); switch(verb) { case "new": // Adds a new player to the game. // (Client's are distinguished by clientid) break; case "delete": // Removes a player from the game break; case "status": // Sends out complete world information instead of just the delta. // This is used for a new client. break; case "action": // "clientid: action left" // "clientid: action right" // "clientid: action down" // "clientid: action up" // "clientid: action up-left" // "clientid: action down-left" // "clientid: action up-right" // "clientid: action down-right" break; case "keydown": // "clientid: keydown CHAR" (where CHAR is a literal character) // "clientid: keydown button-1" // "clientid: keydown button-2" break; case "keyup": // "clientid: keyup CHAR" (where CHAR is a literal character) // "clientid: keyup button-1" // "clientid: keyup button-2" break; case "joystick": /* Optional */ // "clientid: joystick x NUM" // "clientid: joystick y NUM" break; case "update": // "serverid: update" broadcast_delta(); break; default: // Unknown verb } }
Destroys any previously created objects, allocates and initializes memory.
This transmits the mesh for the entire playing-field (hills, valleys, rivers, and other immovable features). This command is likely to change drastically in the future. For the initial stages, we will have a hard-wired playing-field on all the clients.
This will only be sent once for each client.
Set certain properties of the object referred to by _#_. This is how things move or change color.
D3DRMQuaternionFromRotation()
to create
a quaternion).
delete
the
objects.