Introduction

The Network System in AfterFour is basically a threaded Client-Server-Architecture. However, the way packages are generated is kind of special. Instead of collecting data that has to be sent and sending packages in a regular interval, packages are sent as soon as possible. This means there are more smaller packages instead of a few larger ones. The good thing about this is that the latency is kept low and the protocol stays simple and well readable. On the downside, every package has a header which generates a lot of overhead (at the moment only TCP is used for simplicity). The system is based on prediction instead of waiting for data to interpolate to. This makes the game react very fast. On the other hand this makes the implementation of every variable that changes over time (mainly positions) quite complicated.

Protocol

Since a tcp connection is basically just a char-stream, the packets have to somehow be separated. To achieve this, every package is preceded by a 10-char representation of the length of the packet. Reading a packet basically looks like this:

private static char[] readPacket() {
 
        int msglen = 0;
        try {
            msglen = Integer.parseInt(String.copyValueOf(read(10)).trim());     //read the package-length
        } catch (NumberFormatException numberFormatException) {
            System.out.println("PACKET FORMAT ERROR!");     //This is a fatal error that can not easily be recovered.
            connectionLost();                               //So drop the connection
        }
 
        char[] result = read(msglen);       //now read the package with the known length
        String outp = String.copyValueOf(result);   //convert it into a string
 
        return result;
    }

Analog to that, sending a package:

    outS.write(String.format("%10d%s", s.length(), s)); //prepend the length
    outS.flush(); //flush the buffer (actually send the data)

Notation

The first level separator for packets is a colon ”:”. The colon separates for example the package name from its arguments. Other separators are commas ”,” and semicolons ”;”, but it depends on the case.

Client

This is a list of packets the client can send to the server.

Control packets

Prefix: “s”

package nameparameters/formatdescriptionexample
sClientInfo[variable]=[value]:[…]Information about the client (login etc.)sClientInfo:nick=“testplayer”

Request packets

Prefix: “r”

package nameparameters/formatdescriptionexample
rTexture[TexID]Request the path to the texture-file behing the given IDrTexture:42
rTileUpdate[x1]:[x2]:[y1]:[y2]Request the map tiles for the specified arearTileUpdate:0:20:0:25

Action packets

Actions are defined by ID's that are defined as static final.

    public static final int A_TEST          = 1;
    public static final int A_MOVE_X        = 100;
    public static final int A_MOVE_Y        = 101;
    public static final int A_AIM           = 110;
    public static final int A_SHOOT         = 111;

Prefix: “a”

package nameparameters/formatdescriptionexample
a1used for testing/debugginga1:
a100[-1/0/1]Movement in X-direction (A/D pressed/released)a100:1
a101[-1/0/1]Movement in Y-direction (W/S pressed/released)a101:-1
a110[x],[y]The coordinates the mouse aims ata110:123,321
a111[0/1/2]Shooting, No/Right/Left mouse button clickeda11:1

Server

This list shows the packets the server sends to the client.

Control packets

Prefix: “g”

package nameparameters/formatdescriptionexample
gClientInfoRequests information about the client (e.g. login)gClientInfo

Answer packets

Answers to requests from clients.

Prefix: “a”

package nameparameters/formatdescriptionexample
aTileUpdate[posX],[posY],[textureID],[width],[height]:[…]list of map tilesaTileUpdate:0,0,5,8,8:0,8,5,8,8
aTexture[TextureID]:[Texture path]Tells the client the texture path behind an IDaTexture:5:test.jpg

Entity packets

Prefix: “e”

package nameparameters/formatdescriptionexample
eEnts[EntityString]:[…]Serialized list of entities (See Entity System)eEnts:42,testEntity,100,100
eUpd[EntityID],[attribute]=[value],[…]Change an attribute of an entityeUpd:42,x=100,y=500
eRem[EntityID]Remove the entityeRem:42
eYou[EntityID]Tells the player the ID of it's own entityeYou:23

Difficulties

What seems so easy in small projects can make lots of problems in bigger ones. One of those things is something as simple as correctly closing the connection.

The simple version: The client tells the server that it is going to close the connection and then just closes the connection. The server receives this message and stops reading and writing on this connection and takes the neccessary actions in the game logic.

For some reason, although it is just implemented that way, it does not work without exceptions being thrown. The exceptions are handled correctly, but I don't like that solution. Some more time has to be put into this.

 
 documentation/network.txt · Last modified: 2011/05/09 00:15 by armageddon
 
Except where otherwise noted, content on this wiki is licensed under the following license:CC Attribution-Noncommercial-Share Alike 3.0 Unported
Recent changes RSS feed Driven by DokuWiki