Blog
Apps About

No Mans Blocks - 6/4/18

Development
#

Creating Time (literally!)

I have a knack for forgetting what I’ve managed to accomplish on the game during the week. To try to overcome this so I have updates I can post on it, I’ve started writing down each accomplishment on a sticky note.

Every Friday I hope to write a small blurb, and post some code showing off the current state of No Mans Blocks. While the networking implementation is still early, I’ve managed to get a sever-authoratative set up running that handles syncing up lobby of players together. Players can specify their own nicknames, which will be ensured to be unique. Chat with each other through text based messages, and some moderator functions such as kicking players are included.

Changelog:

Lastly while the switch to LiteNetLib was pretty hassle free I did have to implement my own network synchronized time system, which is actually quite a bit easier than it sounds!

Both the server, and clients maintain their own time which basically just indicates how long the game has been running for in seconds. To generate a synchronized time across the network the following steps need to be taken.

  1. When a client connects have them send a time sync request and track when it was sent

These code snippets are from my TimeSynchronizer class. They are the message handlers that process incoming messages from over the network.

private void OnConnectionMessage(object sender, NetMessageArgs e) {
    switch (e.Message?.Type) {
        //Step 1 (Client side):
        //When a new server is connected to. Send it a time request.
        case NetMessageType.ConnectionAccepted:
            SendSyncRequest();
            break;

        //Disconnected from server. Wipe offset.
        case NetMessageType.Disconnected:
            time.SetServerOffset(0);
            break;
    }
}

private void OnTimeMessage(object sender, NetMessageArgs e) {
    switch (e.Message?.Type) {
        //Step 3 (Client Side)
        //Time sync message was recieved.
        case NetMessageType.TimeSync:
            TimeSyncMessage incomingSync = e.Message as TimeSyncMessage;

            if (incomingSync != null) {
                time.SetServerOffset(incomingSync.ServerTime - timeSyncSentAt);
            }

            break;

        //Step 2 (Server Side)
        //Client is requesting a time sync message.
        case NetMessageType.TimeSyncRequest:
            LiteNetLib.NetPeer msgSender = e.Message.Sender;
            if (msgSender != null) {
                TimeSyncMessage outgoingSync = new TimeSyncMessage(Time.LocalTime);
                netManager.SendMessage(outgoingSync, msgSender, LiteNetLib.SendOptions.ReliableOrdered);
            }
            break;
    }
}

This process isn’t quite perfect and a variance of several milliseconds can occur but this can be overcome by repeating these steps occasionally. It could be taken one step further and several time syncs could be sent when a player first joins, then the average offset can be calculated from them which can reduce bad data due to a lag spike.