Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get real time for a game

Tags:

java

time

ntp

i am working with Java and i am making a game. In this game the real time is very essensial part. For this reason i am trying to get the real time using Ntp.

What i found in the web is this code.

import java.net.InetAddress;
import java.util.Date;
import org.apache.commons.net.ntp.NTPUDPClient; 
import org.apache.commons.net.ntp.TimeInfo;

public class test{
    public static void main(String args[]) throws Exception{
        String TIME_SERVER = "time-a.nist.gov";   
        NTPUDPClient timeClient = new NTPUDPClient();
        InetAddress inetAddress = InetAddress.getByName(TIME_SERVER);
        TimeInfo timeInfo = timeClient.getTime(inetAddress);

        long returnTime = timeInfo.getReturnTime();
        Date time = new Date(returnTime);

        System.out.println("Time from " + TIME_SERVER + ": " + time);
    }
}

My problem is that using this, the system is still getting the System.currentMillis(); because it actually prints you the time that your local machine got the time message. For this reason if the player changes his Desktop time to the future, the game time will also change.

If someone could help in order to have the real time i would be very thankful. P.S. i dont have a server, my game will be playing on Kongregate and the data will be on the players computer.

Thanks in advance.

like image 820
Athorivos Avatar asked Dec 22 '14 14:12

Athorivos


People also ask

How do real time games work?

Real-Time is perhaps the simpler concept, in that a game that runs in real time has events that update…in real time. If there is a clock in the game, it runs at 60 seconds per minute. Characters move, actions are taken, and choices are made with the clock running consistently and incessantly.

How do real time multiplayer games work?

In a real-time match, the players are connected to each other simultaneously in a single game session where they exchange data messages. This form of match is suitable for implementing any type of game that requires live participation.

What is colyseus arena?

Welcome to Colyseus Arena It provides developers with enterprise grade hosting leaving server management, infrastructure, DevOps and scaling to us. With Arena, you can setup, manage and update your Colyseus servers with a few clicks from an intuitive administration dashboard.


3 Answers

Just get the time once via NTP at the start of your program and then use System.nanoTime() to get the relative time after that. It is completely monotomic and will not be changed via the setting of the system time.

like image 185
Vality Avatar answered Oct 06 '22 22:10

Vality


As per the NTPUDPClient javadoc:

To use the class, merely open a local datagram socket with open and call getTime() to retrieve the time. Then call close to close the connection properly. Successive calls to getTime are permitted without re-establishing a connection.

You are missing a call to open() in your code (technically close() as well, but that's not the reason for your issue).

Also, in your requirements, you state you needed the real time (and not whatever time the local client can set). This quantity should not be obtained directly but as an offset required to match local time to server (remote) time, obtained by the method getOffset().

If getting the real time is a common procedure, you may want to only use NTP once at the start and use the offset obtained to correct system time in the future, reducing the latency when retrieving real time.

Such a process can be described in a class as such:

public class TimeKeeper{
    // Constant: Time Server
    private final String TIME_SERVER = "time-a.nist.gov";

    // Last time the time offset was retrieved via NTP
    private long last_offset_time = -1;

    // The real time, calculated from offsets, of when the last resync happened
    private long retrieve_time;

    private synchronized void resync(){
        NTPUDPClient timeClient = new NTPUDPClient();
        InetAddress inetAddress = InetAddress.getByName(TIME_SERVER);
        TimeInfo timeInfo = null;

        try{
            timeClient.open();
            timeInfo = timeClient.getTime(inetAddress);
        }catch(IOException ex){
            return;
        }finally{
            timeClient.close();
        }

        // Real time calculated from the offset time and the current system time.
        retrieve_time = System.currentTimeMillis() + timeInfo.getOffset();
        last_offset_time = System.nanoTime();
    }

    public long getRealTimeInMillis(){
        // Possible to set some resync criteria here
        if(last_offset_time == -1){
            resync();

            // Handle exception whilst retrieving time here
        }

        // Returns the system time, corrected with the offset
        return retrieve_time + Math.round((System.nanoTime() - last_offset_time) / 1000.0)
    }
}
like image 40
initramfs Avatar answered Oct 06 '22 22:10

initramfs


Try this:

String TIME_SERVER = "time-a.nist.gov";   
TimeTCPClient client = new TimeTCPClient();

try {
    client.connect(TIME_SERVER);
    System.out.println(client.getDate());
} finally {
    client.disconnect();
}
like image 20
Jordi Castilla Avatar answered Oct 06 '22 21:10

Jordi Castilla