UDP woes? Or a logic error?

Okay, so player “B”'s X coord jumps between player “A”'s and it’s own By player “B” I mean the non-client controlled player, and “A” is the player your client controls. So on client #2 player #1 would jump between player#2’s X coord and it’s own. My test case is a little big, but it’s the bare minimum to reproduce the bug. also it requires Slick2d.

How can I fix this bug?

Client:


import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.nio.ByteBuffer;


import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.BasicGame;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;

public class TestClient extends BasicGame{
	ClientThread ct;
	int playerNum = 0;
	int[] playerX;
	int[] enemy;
	
	public  TestClient()
    {
        super("Test Client");
    }
	
	public static void main(String[] args) 
	throws SlickException
	{
		 AppGameContainer app = 
			new AppGameContainer(new TestClient());
		
		 app.setDisplayMode(640, 480, false);
		 app.setTargetFrameRate(60);
		 app.start();
	}

	@Override
	public void render(GameContainer gc, Graphics g) throws SlickException {
		g.fillRect(playerX[0], 0, 50, 50);
		g.fillRect(playerX[1], 0, 50, 50);
		g.drawString("px:" + playerX[playerNum], 10, 10);
		g.drawString("ex:" + playerX[enemy[playerNum]], 10, 25);
		g.drawString("p#:" + playerNum, 10, 40);
	}

	@Override
	public void init(GameContainer gc) throws SlickException {
		playerX = new int[2];
		playerX[0] = 50;
		playerX[1] = 200;
		enemy = new int[2];
		enemy[0] = 1;
		enemy[1] = 0;
		ct = new ClientThread(playerX);
	  	ct.start();
	  	ct.setPriority(Thread.MAX_PRIORITY);
	  	
	  	playerNum = ct.playerNum;
	}

	@Override
	public void update(GameContainer gc, int delta) throws SlickException {
		Input input = gc.getInput();
		 if(input.isKeyDown(Input.KEY_A))
	        {
	            playerX[playerNum]-=2;
	        }
	 
	        if(input.isKeyDown(Input.KEY_D))
	        {
	        	playerX[playerNum]+=2;
	        }
	}
}

class ClientThread extends Thread implements Runnable{
	DatagramSocket socket;
	DatagramPacket packet;
	int playerNum;
	int playerX[];
	int[] enemy;
    boolean loop = true;
    int port;
    byte [] addr;
    InetAddress address;
    
	public ClientThread(int playerX[]){
		super("ClientThread");
		
		this.playerX = playerX;
		enemy = new int[2];
		enemy[0] = 1;
		enemy[1] = 0;
		
		try{
			port = 4444;
		    addr = new byte[] {(byte) 76,(byte) 121,(byte) 76,(byte) 188};
		    address = InetAddress.getByAddress(addr);
		    
		    byte[] buf = new byte[10];
		    socket = new DatagramSocket();
		    DatagramPacket packet = new DatagramPacket(buf, 10, address, 4444);
			System.out.println("send" + address.toString());
			socket.send(packet);
			
			byte[] buf2 = new byte[255];
			packet = new DatagramPacket(buf2, buf2.length);
			socket.receive(packet);
			ByteBuffer receiveBuf = ByteBuffer.wrap(packet.getData());
			this.playerNum  = receiveBuf.getInt();
			System.out.println("#:"+this.playerNum);
			
		    
		}
		
		catch(Exception e){
			e.printStackTrace();
		}
	}
	
	public void run(){
		try{
			while(loop){
				
				try{
					ByteBuffer sendBuf = ByteBuffer.allocate(255);
					sendBuf.putInt(playerX[playerNum]);
					
					DatagramPacket packet = new DatagramPacket(sendBuf.array(), sendBuf.array().length, address, port);
					System.out.println("send" + address.toString());
					socket.send(packet);
					System.out.println("sent");
					
					byte[] buf = new byte[255];
					packet = new DatagramPacket(buf, buf.length);
					socket.receive(packet);
					ByteBuffer receiveBuf = ByteBuffer.wrap(packet.getData());
					playerX[enemy[playerNum]] = receiveBuf.getInt();
					System.out.println("playerX[enemy[playerNum]] "+playerX[enemy[playerNum]] );
					this.sleep(1);
		        }
				catch(Exception e){
			    		e.printStackTrace();
			    		//socket.close();
			    }  
			}
			
			
			
		}
		
		catch(Exception e){
			e.printStackTrace();
		}
	}
}

Server:


import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;


public class TestServer {
	static DatagramSocket socket;
	static int[] playerX;
	public void doStuff(){
		int MAX_PLAYERS = 2;
    	int playerNum = 0;
    	playerX = new int[2];
    	byte [] addr = new byte[] {(byte) 0,(byte) 0,(byte) 0,(byte) 0};
	  	
    	InetAddress player1IP = null;
    	try {
			player1IP = InetAddress.getByAddress(addr);
		} catch (UnknownHostException e2) {
			// TODO Auto-generated catch block
			e2.printStackTrace();
		}
	  	int player1Port = -1;
    	boolean listening = true;
        
        try {
			socket = new DatagramSocket(4444);
		} catch (SocketException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
        
        while(playerNum < 2){
        	
	        	byte[] buf = new byte[255];
	            DatagramPacket packet = new DatagramPacket(buf, buf.length);
	            System.out.println("Waiting for packet from player: " + playerNum + "\n");
	        	
	           
	            
	            try {
					socket.receive(packet);
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
	        	
				if(packet.getAddress().toString().compareTo(player1IP.toString()) != 0 || packet.getPort() != player1Port){
	            	if(playerNum == 0){ 
	            		player1IP = packet.getAddress();
	            		player1Port = packet.getPort();
	            	}
	        	
				
	        	System.out.println("Waiting to connect with player: " + playerNum + "\n");
	        	new ClientThread(this, socket, packet,playerNum, playerX).start();
	        	//stops here.
	        	System.out.println("Connected with player: " + playerNum + " Now incrementing" + "\n");
	        	playerNum++;
	        	System.out.println("Incremented to: " + playerNum+ "\n");
        	}
        }
        
        while(true){}
        
	}
	
	public static void main(String[] args){
		TestServer t = new TestServer();
		t.doStuff();
        //serverSocket.close();
       // System.exit(0);
	}
}


Client thread (Server)


import java.io.IOException;
import java.net.*;
import java.nio.ByteBuffer;

public class ClientThread extends Thread implements Runnable{
	int playerNum;
	int enemy[];
	DatagramSocket socket;
	InetAddress address;
	TestServer ts;
	int port;
	public ClientThread(TestServer ts, DatagramSocket socket, DatagramPacket packet, int playerNum, int playerX[]){
		super("ClientThread");
		
		address = packet.getAddress();
		port = packet.getPort();
		this.socket = socket;
		this.playerNum = playerNum;
		this.ts = ts;
		enemy = new int[2];
		enemy[0] = 1;
		enemy[1] = 0;
		
		ByteBuffer sendBuf = ByteBuffer.allocate(255);
		System.out.println("#:"+playerNum);
		sendBuf.putInt(playerNum);
		DatagramPacket packet2 = new DatagramPacket(sendBuf.array(), sendBuf.array().length, address, port);
		try {
			socket.send(packet2);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void run(){
		try{
			System.out.println("Thread" + playerNum + ": " + "Accepted. Now creating I/O.\n");
	        
	        while(true){
	        	byte[] buf = new byte[255];
	        	DatagramPacket packet = new DatagramPacket(buf, buf.length);
	            socket.receive(packet);
	        	
	        	ByteBuffer recieveBuf = ByteBuffer.wrap(packet.getData());
	        	//System.out.println("Threadxx#"+playerNum+": x:" + recieveBuf.getInt());
				
	        	ts.playerX[playerNum] = recieveBuf.getInt();
				//System.out.println("Thread#"+playerNum+": x:" + recieveBuf.getInt());
				
				ByteBuffer sendBuf = ByteBuffer.allocate(255);
				
				sendBuf.putInt(ts.playerX[enemy[playerNum]]);
				System.out.println("Thread#"+playerNum+": ex:" + ts.playerX[enemy[playerNum]]);
				DatagramPacket packet2 = new DatagramPacket(sendBuf.array(), sendBuf.array().length, address, port);
				socket.send(packet2);
				
		       this.sleep(1);
	        }

		}
		
		catch(Exception e){
			e.printStackTrace();
			System.exit(1);
		}
        
       
	}
	
}

Could you be more clear? I’m having trouble understanding.

Sounds kind of like it’s just a latency issue though. Generally I store one position old on the client and I interpolate between positions so it looks smooth. Also for unreliable networking protocols, store the date the most recent packet was sent and don’t respond to any packets that were sent older than that.

Well, I don’t think it’s a latency issue. Anyway I’ll try to explain it more clearly. If you’re running on the second client to connect to the server you’ll control player #2. In this case player #1 will jump between the position it’s suppose to be in (It’s own x) and where player #2 is.

Likewise if you’re on the first client to connect to the server you will be in control of player #1 and you’ll see player #2 messing up.

Maybe you are incorrectly setting some variables somewhere? Accidentally setting player #1’s position as player #2?

Nope. I triple checked both the client and server, and that doesn’t ever happen.

Okay I fixed the bug where the X’s got mixed up thanks to Kev, but now I’m getting awful lag. Can someone take a look and tell me why it’s so laggy, or give me some tips on how to speed it up?

Server


import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;


public class TestServer {
	static DatagramSocket socket;
	static int[] playerX;
	public void doStuff(){
		int MAX_PLAYERS = 2;
    	int playerNum = 0;
    	playerX = new int[2];
    	byte [] addr = new byte[] {(byte) 0,(byte) 0,(byte) 0,(byte) 0};
	  	
    	InetAddress player1IP = null;
    	try {
			player1IP = InetAddress.getByAddress(addr);
		} catch (UnknownHostException e2) {
			// TODO Auto-generated catch block
			e2.printStackTrace();
		}
	  	int player1Port = -1;
    	boolean listening = true;
        
        try {
			socket = new DatagramSocket(4444);
		} catch (SocketException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
        
        while(playerNum < 2){
        	
	        	byte[] buf = new byte[255];
	            DatagramPacket packet = new DatagramPacket(buf, buf.length);
	            System.out.println("Waiting for packet from player: " + playerNum + "\n");
	        	
	           
	            
	            try {
					socket.receive(packet);
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
	        	
				if(packet.getAddress().toString().compareTo(player1IP.toString()) != 0 || packet.getPort() != player1Port){
	            	if(playerNum == 0){ 
	            		player1IP = packet.getAddress();
	            		player1Port = packet.getPort();
	            	}
	        	
				
	        	System.out.println("Waiting to connect with player: " + playerNum + "\n");
	        	new ClientThread(this, socket, packet,playerNum, playerX).start();
	        	//stops here.
	        	System.out.println("Connected with player: " + playerNum + " Now incrementing" + "\n");
	        	playerNum++;
	        	System.out.println("Incremented to: " + playerNum+ "\n");
        	}
        }
        
        while(true){}
        
	}
	
	public static void main(String[] args){
		TestServer t = new TestServer();
		t.doStuff();
        //serverSocket.close();
       // System.exit(0);
	}
}


Client Thread (Server)


import java.io.IOException;
import java.net.*;
import java.nio.ByteBuffer;

public class ClientThread extends Thread implements Runnable{
	int playerNum;
	int enemy[];
	DatagramSocket socket;
	InetAddress address;
	TestServer ts;
	int port;
	public ClientThread(TestServer ts, DatagramSocket socket, DatagramPacket packet, int playerNum, int playerX[]){
		super("ClientThread");
		
		address = packet.getAddress();
		port = packet.getPort();
		this.socket = socket;
		this.playerNum = playerNum;
		this.ts = ts;
		enemy = new int[2];
		enemy[0] = 1;
		enemy[1] = 0;
		
		ByteBuffer sendBuf = ByteBuffer.allocate(255);
		System.out.println("#:"+playerNum);
		sendBuf.putInt(playerNum);
		DatagramPacket packet2 = new DatagramPacket(sendBuf.array(), sendBuf.array().length, address, port);
		try {
			socket.send(packet2);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void run(){
		try{
			System.out.println("Thread" + playerNum + ": " + "Accepted. Now creating I/O.\n");
	        
	        while(true){
	        	byte[] buf = new byte[255];
	        	DatagramPacket packet = new DatagramPacket(buf, buf.length);
	            socket.receive(packet);
	        	
	        	ByteBuffer recieveBuf = ByteBuffer.wrap(packet.getData());
	        	//System.out.println("Threadxx#"+playerNum+": x:" + recieveBuf.getInt());
	        	int tempPlayerNum = recieveBuf.getInt();
	        	
	        	if(tempPlayerNum == playerNum)
	        		ts.playerX[playerNum] = recieveBuf.getInt();
				//System.out.println("Thread#"+playerNum+": x:" + recieveBuf.getInt());
				
				ByteBuffer sendBuf = ByteBuffer.allocate(255);
				
				sendBuf.putInt(enemy[playerNum]);
				sendBuf.putInt(ts.playerX[enemy[playerNum]]);
				System.out.println("Thread#"+playerNum+": ex:" + ts.playerX[enemy[playerNum]]);
				DatagramPacket packet2 = new DatagramPacket(sendBuf.array(), sendBuf.array().length, address, port);
				socket.send(packet2);
				
		       this.sleep(1);
	        }

		}
		
		catch(Exception e){
			e.printStackTrace();
			System.exit(1);
		}
        
       
	}
	
}

client:


import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.nio.ByteBuffer;


import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.BasicGame;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;

public class TestClient extends BasicGame{
	ClientThread ct;
	int playerNum = 0;
	int[] playerX;
	int[] enemy;
	
	public  TestClient()
    {
        super("Test Client");
    }
	
	public static void main(String[] args) 
	throws SlickException
	{
		 AppGameContainer app = 
			new AppGameContainer(new TestClient());
		
		 app.setDisplayMode(640, 480, false);
		 app.setTargetFrameRate(60);
		 app.setAlwaysRender(true);
		 app.start();
	}

	@Override
	public void render(GameContainer gc, Graphics g) throws SlickException {
		g.fillRect(playerX[0], 0, 50, 50);
		g.fillRect(playerX[1], 0, 50, 50);
		g.drawString("px:" + playerX[playerNum], 10, 10);
		g.drawString("ex:" + playerX[enemy[playerNum]], 10, 25);
		g.drawString("p#:" + playerNum, 10, 40);
	}

	@Override
	public void init(GameContainer gc) throws SlickException {
		playerX = new int[2];
		playerX[0] = 50;
		playerX[1] = 200;
		enemy = new int[2];
		enemy[0] = 1;
		enemy[1] = 0;
		ct = new ClientThread(playerX);
	  	ct.start();
	  	ct.setPriority(Thread.MAX_PRIORITY);
	  	
	  	playerNum = ct.playerNum;
	}

	@Override
	public void update(GameContainer gc, int delta) throws SlickException {
		Input input = gc.getInput();
		 if(input.isKeyDown(Input.KEY_A))
	        {
	            playerX[playerNum]-=2;
	        }
	 
	        if(input.isKeyDown(Input.KEY_D))
	        {
	        	playerX[playerNum]+=2;
	        }
	}
}

class ClientThread extends Thread implements Runnable{
	DatagramSocket socket;
	DatagramPacket packet;
	int playerNum;
	int playerX[];
	int[] enemy;
    boolean loop = true;
    int port;
    byte [] addr;
    InetAddress address;
    
	public ClientThread(int playerX[]){
		super("ClientThread");
		
		this.playerX = playerX;
		enemy = new int[2];
		enemy[0] = 1;
		enemy[1] = 0;
		
		try{
			port = 4444;
		    addr = new byte[] {(byte) 76,(byte) 121,(byte) 76,(byte) 188};
		    address = InetAddress.getByAddress(addr);
		    
		    byte[] buf = new byte[10];
		    socket = new DatagramSocket();
		    System.out.println("port" + socket.getLocalPort());
		    DatagramPacket packet = new DatagramPacket(buf, 10, address, 4444);
			System.out.println("send" + address.toString());
			socket.send(packet);
			
			byte[] buf2 = new byte[255];
			packet = new DatagramPacket(buf2, buf2.length);
			socket.receive(packet);
			ByteBuffer receiveBuf = ByteBuffer.wrap(packet.getData());
			this.playerNum  = receiveBuf.getInt();
			System.out.println("#:"+this.playerNum);
			
		    
		}
		
		catch(Exception e){
			e.printStackTrace();
		}
	}
	
	public void run(){
		try{
			while(loop){
				
				try{
					ByteBuffer sendBuf = ByteBuffer.allocate(255);
					sendBuf.putInt(playerNum);
					sendBuf.putInt(playerX[playerNum]);
					
					DatagramPacket packet = new DatagramPacket(sendBuf.array(), sendBuf.array().length, address, port);
					System.out.println("send" + address.toString());
					socket.send(packet);
					System.out.println("sent");
					
					byte[] buf = new byte[255];
					packet = new DatagramPacket(buf, buf.length);
					socket.receive(packet);
					ByteBuffer receiveBuf = ByteBuffer.wrap(packet.getData());
					int tempEnemyNum = receiveBuf.getInt();
					
					if(enemy[playerNum] == tempEnemyNum ){
						playerX[enemy[playerNum]] = receiveBuf.getInt();
						System.out.println("playerX[enemy[playerNum]] "+playerX[enemy[playerNum]] + " p" + socket.getLocalPort()+"ten"+ tempEnemyNum);
					}
						this.sleep(1);
		        }
				catch(Exception e){
			    		e.printStackTrace();
			    		//socket.close();
			    }  
			}
			
			
			
		}
		
		catch(Exception e){
			e.printStackTrace();
		}
	}
}

It looks perfectly fine to me. However, why do you extends Thread and implement Runnable? You only need Thread, no need for Runnable.

Yes, it’s no big deal, but it is redundant.

[quote=javadoc]java.lang
Class Thread

java.lang.Object
java.lang.Thread
All Implemented Interfaces:
Runnable
[/quote]
Your lag could be caused by the while(true){} in TestServer, it’s going to take a lot of resources from the server that can’t go out to your client threads. You should put a sleep in there, at the very least.

Also, I think your overall design is not the best way of doing this. A lot of sleeping loops is pretty unreliable. Instead I’d put a fixed timestep loop on the client and server (with the same timestep). This is generally much better for networked games.

He does sleep, albeit for 1 millisecond. Maybe 5-10 milliseconds could help.

No he does.

while(true){}

There is no sleep in between the braces. He sleeps in other places.

fixed timestep loop? You mean using the Timer class?

Whoa, yeah what’s that “while(true) {}” line for?!?
And I discourage the use of Swing Timer, use the Util Timer :slight_smile:

No, I’d definitely avoid using that as well. A fixed timestep loop is one that updates logic a fixed number of times per minute, rather than going as fast as it possibly can. Usually I will have fixed game updates of only about 20 or 25 / second, and then let the FPS (rendering only) go as fast as it can and interpolate it.

Hm actually I’ve had a fixed timestep demo for a while that I haven’t put anywhere. I’ll put it in tutorials and link it…

Here go you:

http://www.java-gaming.org/index.php/topic,24220.0.html

<3

Okay, I tried doing what Eli said, but now even though the clients connect they don’t seem to update their position, or something. Maybe I’m doing the loop wrong?

Server:


import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;


public class TestServer {
	static DatagramSocket socket;
	static int[] playerX;
	private long lastFpsTime;
	private int fps;
	public void doStuff(){
		long lastLoopTime = System.nanoTime();
        final long OPTIMAL_TIME = 1000000000 / 60; //60fps is optimal
		
		int MAX_PLAYERS = 2;
    	int playerNum = 0;
    	playerX = new int[2];
    	byte [] addr = new byte[] {(byte) 0,(byte) 0,(byte) 0,(byte) 0};
	  	
    	InetAddress player1IP = null;
    	try {
			player1IP = InetAddress.getByAddress(addr);
		} catch (UnknownHostException e2) {
			// TODO Auto-generated catch block
			e2.printStackTrace();
		}
	  	int player1Port = -1;
    	boolean listening = true;
        
        try {
			socket = new DatagramSocket(4444);
		} catch (SocketException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
        
        while(playerNum < 2){
        	
	        	byte[] buf = new byte[255];
	            DatagramPacket packet = new DatagramPacket(buf, buf.length);
	            System.out.println("Waiting for packet from player: " + playerNum + "\n");
	        	
	           
	            
	            try {
					socket.receive(packet);
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
	        	
				if(packet.getAddress().toString().compareTo(player1IP.toString()) != 0 || packet.getPort() != player1Port){
	            	if(playerNum == 0){ 
	            		player1IP = packet.getAddress();
	            		player1Port = packet.getPort();
	            	}
	        	
				
	        	System.out.println("Waiting to connect with player: " + playerNum + "\n");
	        	new ClientThread(this, socket, packet,playerNum, playerX).start();
	        	//stops here.
	        	System.out.println("Connected with player: " + playerNum + " Now incrementing" + "\n");
	        	playerNum++;
	        	System.out.println("Incremented to: " + playerNum+ "\n");
        	}
        }
        
        while(true){
        	long now = System.nanoTime();
            long updateLength = now - lastLoopTime;
            lastLoopTime = now;
            //double delta = updateLength / ((double)OPTIMAL_TIME);
     
            // update the frame counter
            lastFpsTime += updateLength;
            fps++;
             
            // update our FPS counter if a second has passed since
            // we last recorded
            if (lastFpsTime >= 1000000000)
            {
                System.out.println("(FPS: "+fps+")");
                lastFpsTime = 0;
                fps = 0;
            }
            
            try {
            	if((lastLoopTime-System.nanoTime())/1000000 + 10000 >= 0)
            		Thread.sleep( (lastLoopTime-System.nanoTime())/1000000 + 10000 );
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
        }
        
	}
	
	public static void main(String[] args){
		TestServer t = new TestServer();
		t.doStuff();
        //serverSocket.close();
       // System.exit(0);
	}
}


Client Thread (Server )


import java.io.IOException;
import java.net.*;
import java.nio.ByteBuffer;

public class ClientThread extends Thread implements Runnable{
	int playerNum;
	int enemy[];
	DatagramSocket socket;
	InetAddress address;
	TestServer ts;
	int port;
	private long lastLoopTime;
	private long lastFpsTime;
	private int fps;
	public ClientThread(TestServer ts, DatagramSocket socket, DatagramPacket packet, int playerNum, int playerX[]){
		super("ClientThread");
		
		address = packet.getAddress();
		port = packet.getPort();
		this.socket = socket;
		this.playerNum = playerNum;
		this.ts = ts;
		enemy = new int[2];
		enemy[0] = 1;
		enemy[1] = 0;
		
		ByteBuffer sendBuf = ByteBuffer.allocate(255);
		System.out.println("#:"+playerNum);
		sendBuf.putInt(playerNum);
		DatagramPacket packet2 = new DatagramPacket(sendBuf.array(), sendBuf.array().length, address, port);
		try {
			socket.send(packet2);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void run(){
		try{
			long lastLoopTime = System.nanoTime();
	        final long OPTIMAL_TIME = 1000000000 / 60; //60fps is optimal
			
			System.out.println("Thread" + playerNum + ": " + "Accepted. Now creating I/O.\n");
	        
	        while(true){
	        	
	        	long now = System.nanoTime();
	            long updateLength = now - lastLoopTime;
	            lastLoopTime = now;
	            //double delta = updateLength / ((double)OPTIMAL_TIME);
	     
	            // update the frame counter
	            lastFpsTime += updateLength;
	            fps++;
	             
	            // update our FPS counter if a second has passed since
	            // we last recorded
	            if (lastFpsTime >= 1000000000)
	            {
	                System.out.println("(FPS: "+fps+")");
	                lastFpsTime = 0;
	                fps = 0;
	            }
	        	
	        	byte[] buf = new byte[255];
	        	DatagramPacket packet = new DatagramPacket(buf, buf.length);
	            socket.receive(packet);
	        	
	        	ByteBuffer recieveBuf = ByteBuffer.wrap(packet.getData());
	        	//System.out.println("Threadxx#"+playerNum+": x:" + recieveBuf.getInt());
	        	int tempPlayerNum = recieveBuf.getInt();
	        	
	        	if(tempPlayerNum == playerNum)
	        		ts.playerX[playerNum] = recieveBuf.getInt();
				//System.out.println("Thread#"+playerNum+": x:" + recieveBuf.getInt());
				
				ByteBuffer sendBuf = ByteBuffer.allocate(255);
				
				sendBuf.putInt(enemy[playerNum]);
				sendBuf.putInt(ts.playerX[enemy[playerNum]]);
				System.out.println("Thread#"+playerNum+": ex:" + ts.playerX[enemy[playerNum]]);
				DatagramPacket packet2 = new DatagramPacket(sendBuf.array(), sendBuf.array().length, address, port);
				socket.send(packet2);
				
				if((lastLoopTime-System.nanoTime())/1000000 + 10000 >= 0)
	            		Thread.sleep( (lastLoopTime-System.nanoTime())/1000000 + 10000 );
	        }

		}
		
		catch(Exception e){
			e.printStackTrace();
			System.exit(1);
		}
        
       
	}
	
}

Client:


import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.nio.ByteBuffer;


import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.BasicGame;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;

public class TestClient extends BasicGame{
	ClientThread ct;
	int playerNum = 0;
	int[] playerX;
	int[] enemy;
	
	public  TestClient()
    {
        super("Test Client");
    }
	
	public static void main(String[] args) 
	throws SlickException
	{
		 AppGameContainer app = 
			new AppGameContainer(new TestClient());
		
		 app.setDisplayMode(640, 480, false);
		 app.setTargetFrameRate(60);
		 app.setAlwaysRender(true);
		 app.start();
	}

	@Override
	public void render(GameContainer gc, Graphics g) throws SlickException {
		g.fillRect(playerX[0], 0, 50, 50);
		g.fillRect(playerX[1], 0, 50, 50);
		g.drawString("px:" + playerX[playerNum], 10, 10);
		g.drawString("ex:" + playerX[enemy[playerNum]], 10, 25);
		g.drawString("p#:" + playerNum, 10, 40);
	}

	@Override
	public void init(GameContainer gc) throws SlickException {
		playerX = new int[2];
		playerX[0] = 50;
		playerX[1] = 200;
		enemy = new int[2];
		enemy[0] = 1;
		enemy[1] = 0;
		ct = new ClientThread(playerX);
	  	ct.start();
	  	ct.setPriority(Thread.MAX_PRIORITY);
	  	
	  	playerNum = ct.playerNum;
	}

	@Override
	public void update(GameContainer gc, int delta) throws SlickException {
		Input input = gc.getInput();
		 if(input.isKeyDown(Input.KEY_A))
	        {
	            playerX[playerNum]-=2;
	        }
	 
	        if(input.isKeyDown(Input.KEY_D))
	        {
	        	playerX[playerNum]+=2;
	        }
	}
}

class ClientThread extends Thread implements Runnable{
	DatagramSocket socket;
	DatagramPacket packet;
	int playerNum;
	int playerX[];
	int[] enemy;
    boolean loop = true;
    int port;
    byte [] addr;
    InetAddress address;
	private long lastFpsTime;
	private int fps;
    
	public ClientThread(int playerX[]){
		super("ClientThread");
		
		this.playerX = playerX;
		enemy = new int[2];
		enemy[0] = 1;
		enemy[1] = 0;
		
		try{
			port = 4444;
		    addr = new byte[] {(byte) 76,(byte) 121,(byte) 76,(byte) 188};
		    address = InetAddress.getByAddress(addr);
		    
		    byte[] buf = new byte[10];
		    socket = new DatagramSocket();
		    System.out.println("port" + socket.getLocalPort());
		    DatagramPacket packet = new DatagramPacket(buf, 10, address, 4444);
			System.out.println("send" + address.toString());
			socket.send(packet);
			
			byte[] buf2 = new byte[255];
			packet = new DatagramPacket(buf2, buf2.length);
			socket.receive(packet);
			ByteBuffer receiveBuf = ByteBuffer.wrap(packet.getData());
			this.playerNum  = receiveBuf.getInt();
			System.out.println("#:"+this.playerNum);
			
		    
		}
		
		catch(Exception e){
			e.printStackTrace();
		}
	}
	
	public void run(){
		try{
			long lastLoopTime = System.nanoTime();
	        final long OPTIMAL_TIME = 1000000000 / 60; //60fps is optimal
			
			while(loop){
				
				long now = System.nanoTime();
	            long updateLength = now - lastLoopTime;
	            lastLoopTime = now;
	            //double delta = updateLength / ((double)OPTIMAL_TIME);
	     
	            // update the frame counter
	            lastFpsTime += updateLength;
	            fps++;
	             
	            // update our FPS counter if a second has passed since
	            // we last recorded
	            if (lastFpsTime >= 1000000000)
	            {
	                System.out.println("(FPS: "+fps+")");
	                lastFpsTime = 0;
	                fps = 0;
	            }
				
				try{
					ByteBuffer sendBuf = ByteBuffer.allocate(255);
					sendBuf.putInt(playerNum);
					sendBuf.putInt(playerX[playerNum]);
					
					DatagramPacket packet = new DatagramPacket(sendBuf.array(), sendBuf.array().length, address, port);
					System.out.println("send" + address.toString());
					socket.send(packet);
					System.out.println("sent");
					
					byte[] buf = new byte[255];
					packet = new DatagramPacket(buf, buf.length);
					socket.receive(packet);
					ByteBuffer receiveBuf = ByteBuffer.wrap(packet.getData());
					int tempEnemyNum = receiveBuf.getInt();
					
					if(enemy[playerNum] == tempEnemyNum ){
						playerX[enemy[playerNum]] = receiveBuf.getInt();
						System.out.println("playerX[enemy[playerNum]] "+playerX[enemy[playerNum]] + " p" + socket.getLocalPort()+"ten"+ tempEnemyNum);
					}
					
					if((lastLoopTime-System.nanoTime())/1000000 + 10000 >= 0)
	            		Thread.sleep( (lastLoopTime-System.nanoTime())/1000000 + 10000 );
			
		        }
				catch(Exception e){
			    		e.printStackTrace();
			    		//socket.close();
			    }  
			}
			
			
			
		}
		
		catch(Exception e){
			e.printStackTrace();
		}
	}
}

Okay I was told in #lwjgl to make my client and server single threaded, so I did and now i have a problem where the first client to connect to the server always freezes. Can anyone help me figure this out and fix it?

Server:


import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;


public class TestServer {
	static DatagramSocket socket;
	static int[] playerX;
	int enemy[];
	
	public void doStuff(){
		System.nanoTime();
        int playerNum = 0;
    	playerX = new int[2];
    	
    	enemy = new int[2];
		enemy[0] = 1;
		enemy[1] = 0;
    	
    	byte [] addr = new byte[] {(byte) 0,(byte) 0,(byte) 0,(byte) 0};
	  	
    	InetAddress player1IP = null;
    	try {
			player1IP = InetAddress.getByAddress(addr);
		} catch (UnknownHostException e2) {
			// TODO Auto-generated catch block
			e2.printStackTrace();
		}
	  	int player1Port = -1;
    	try {
			socket = new DatagramSocket(4444);
		} catch (SocketException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
        
        while(playerNum < 2){
        	byte[] buf = new byte[255];
            DatagramPacket packet = new DatagramPacket(buf, buf.length);
            System.out.println("Waiting for packet from player: " + playerNum + "\n");
        	
           
            
            try {
				socket.receive(packet);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
        	
			if(packet.getAddress().toString().compareTo(player1IP.toString()) != 0 || packet.getPort() != player1Port){
            	if(playerNum == 0){ 
            		player1IP = packet.getAddress();
            		player1Port = packet.getPort();
            	}
        	
			
            	ByteBuffer sendBuf = ByteBuffer.allocate(255);
        		System.out.println("#:"+playerNum);
        		sendBuf.putInt(playerNum);
        		DatagramPacket packet2 = new DatagramPacket(sendBuf.array(), sendBuf.array().length, packet.getAddress(), packet.getPort());
        		
        		try {
        			socket.send(packet2);
        		} catch (IOException e) {
        			e.printStackTrace();
        		}
        		
	        	System.out.println("Connected with player: " + playerNum + " Now incrementing" + "\n");
	        	playerNum++;
	        	System.out.println("Incremented to: " + playerNum+ "\n");
			}
			
			else{
				System.out.println("player1 connected before player 2");
				serverLoop();
			}
        }
        
        while(true){
        	serverLoop();
        }
	}
	
	public void serverLoop(){
		byte[] buf = new byte[255];
    	DatagramPacket packet = new DatagramPacket(buf, buf.length);
        try {
			socket.receive(packet);
		} catch (IOException e1) {
			e1.printStackTrace();
		}
    	
    	ByteBuffer recieveBuf = ByteBuffer.wrap(packet.getData());
    	//System.out.println("Threadxx#"+playerNum+": x:" + recieveBuf.getInt());
    	int tempPlayerNum = recieveBuf.getInt();
    	
    	playerX[tempPlayerNum] = recieveBuf.getInt();
		//System.out.println("Thread#"+playerNum+": x:" + recieveBuf.getInt());
		
		ByteBuffer sendBuf = ByteBuffer.allocate(255);
		
		sendBuf.putInt(enemy[tempPlayerNum]);
		sendBuf.putInt(playerX[enemy[tempPlayerNum]]);
		System.out.println("tempPlayerNum#"+tempPlayerNum+": ex:" + playerX[enemy[tempPlayerNum]]);
		DatagramPacket packet2 = new DatagramPacket(sendBuf.array(), sendBuf.array().length, packet.getAddress(), packet.getPort());
		try {
			socket.send(packet2);
		} catch (IOException e) {
			e.printStackTrace();
		}
    }
	
	public static void main(String[] args){
		TestServer t = new TestServer();
		t.doStuff();
        //serverSocket.close();
       // System.exit(0);
	}
}


Client:


import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.nio.ByteBuffer;


import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.BasicGame;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;

public class TestClient extends BasicGame{
	int playerNum = 0;
	int[] playerX;
	int[] enemy;
	
	DatagramSocket socket;
	DatagramPacket packet;
	private InetAddress address;
	private byte[] addr;
	private int port;
	
	public  TestClient()
    {
        super("Test Client");
    }
	
	public static void main(String[] args) 
	throws SlickException
	{
		 AppGameContainer app = 
			new AppGameContainer(new TestClient());
		
		 app.setDisplayMode(640, 480, false);
		 app.setTargetFrameRate(60);
		 app.setAlwaysRender(true);
		 app.start();
	}

	@Override
	public void render(GameContainer gc, Graphics g) throws SlickException {
		g.fillRect(playerX[0], 0, 50, 50);
		g.fillRect(playerX[1], 0, 50, 50);
		g.drawString("px:" + playerX[playerNum], 10, 10);
		g.drawString("ex:" + playerX[enemy[playerNum]], 10, 25);
		g.drawString("p#:" + playerNum, 10, 40);
	}

	@Override
	public void init(GameContainer gc) throws SlickException {
		playerX = new int[2];
		playerX[0] = 50;
		playerX[1] = 200;
		enemy = new int[2];
		enemy[0] = 1;
		enemy[1] = 0;
		enemy = new int[2];
		enemy[0] = 1;
		enemy[1] = 0;
		
		try{
			port = 4444;
		    addr = new byte[] {(byte) 76,(byte) 121,(byte) 76,(byte) 188};
		    address = InetAddress.getByAddress(addr);
		    
		    byte[] buf = new byte[10];
		    socket = new DatagramSocket();
		    System.out.println("port" + socket.getLocalPort());
		    DatagramPacket packet = new DatagramPacket(buf, 10, address, 4444);
			System.out.println("send" + address.toString());
			socket.send(packet);
			
			byte[] buf2 = new byte[255];
			packet = new DatagramPacket(buf2, buf2.length);
			socket.receive(packet);
			ByteBuffer receiveBuf = ByteBuffer.wrap(packet.getData());
			this.playerNum  = receiveBuf.getInt();
			System.out.println("#:"+this.playerNum);
			
		    
		}
		
		catch(Exception e){
			e.printStackTrace();
		}
	}

	@Override
	public void update(GameContainer gc, int delta) throws SlickException {
		Input input = gc.getInput();
		 if(input.isKeyDown(Input.KEY_A))
	        {
	            playerX[playerNum]-=2;
	        }
	 
	        if(input.isKeyDown(Input.KEY_D))
	        {
	        	playerX[playerNum]+=2;
	        }
	        
	        ByteBuffer sendBuf = ByteBuffer.allocate(255);
			sendBuf.putInt(playerNum);
			sendBuf.putInt(playerX[playerNum]);
			
			DatagramPacket packet = new DatagramPacket(sendBuf.array(), sendBuf.array().length, address, port);
			System.out.println("send" + address.toString());
			try {
				socket.send(packet);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println("sent");
			
			byte[] buf = new byte[255];
			packet = new DatagramPacket(buf, buf.length);
			try {
				socket.receive(packet);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			ByteBuffer receiveBuf = ByteBuffer.wrap(packet.getData());
			int tempEnemyNum = receiveBuf.getInt();
			
			if(enemy[playerNum] == tempEnemyNum ){
				playerX[enemy[playerNum]] = receiveBuf.getInt();
				System.out.println("playerX[enemy[playerNum]] "+playerX[enemy[playerNum]] + " p" + socket.getLocalPort()+"ten"+ tempEnemyNum);
			}
	}
}

Okay, so I’m now using the non-blocking DatagramChannel, and the code for this problem isn’t that big. See, the clients seem to be connecting to the server in that the server incrementing the playerNum, but both clients both say their playerNum is 0, so it seems like the clients aren’t getting the data. Any idea why?

Server:


import java.io.IOException;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;


public class TestServer {
	DatagramChannel channel;
	SocketAddress player1IP;
	static int[] playerX;
	int enemy[];
	
	public void doStuff(){
		int playerNum = 0;
    	playerX = new int[2];
    	playerX[0] = 50;
    	playerX[1] = 200;
    	enemy = new int[2];
		enemy[0] = 1;
		enemy[1] = 0;
    	
		channel = null;
		try {
			channel = DatagramChannel.open();
		} catch (IOException e3) {
			e3.printStackTrace();
		}
	    SocketAddress address = new InetSocketAddress(4444);
	    DatagramSocket socket = channel.socket();
	    try {
			socket.bind(address);
		} catch (SocketException e3) {
			e3.printStackTrace();
		}
		ByteBuffer buffer = ByteBuffer.allocate(255);
		
        while(playerNum < 2){
        	SocketAddress client = null;
			try {
				client = channel.receive(buffer);
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
        	
			if(!client.equals(player1IP)){
            	if(playerNum == 0){ 
            		player1IP = client;
            	}
        	
			
            	ByteBuffer sendBuf = ByteBuffer.allocate(255);
        		System.out.println("#:"+playerNum);
        		sendBuf.putInt(playerNum);
        		try {
					channel.send(sendBuf, client);
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
        		
	        	System.out.println("Connected with player: " + playerNum + " Now incrementing" + "\n");
	        	playerNum++;
	        	System.out.println("Incremented to: " + playerNum+ "\n");
			}
        }
        
        while(true){
        	serverLoop();
        }
	}
	
	public void serverLoop(){}
	
	public static void main(String[] args){
		TestServer t = new TestServer();
		t.doStuff();
	}
}


Client:


import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;


import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.BasicGame;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;

public class TestClient extends BasicGame{
	int playerNum = 0;
	int[] playerX;
	int[] enemy;
	
	DatagramChannel channel;
	
	public  TestClient()
    {
        super("Test Client");
    }
	
	public static void main(String[] args) 
	throws SlickException
	{
		 AppGameContainer app = 
			new AppGameContainer(new TestClient());
		
		 app.setDisplayMode(640, 480, false);
		 app.setTargetFrameRate(60);
		 app.setAlwaysRender(true);
		 app.start();
	}

	@Override
	public void render(GameContainer gc, Graphics g) throws SlickException {
		g.fillRect(playerX[0], 0, 50, 50);
		g.fillRect(playerX[1], 0, 50, 50);
		g.drawString("px:" + playerX[playerNum], 10, 10);
		g.drawString("ex:" + playerX[enemy[playerNum]], 10, 25);
		g.drawString("p#:" + playerNum, 10, 40);
	}

	@Override
	public void init(GameContainer gc) throws SlickException {
		playerX = new int[2];
		playerX[0] = 0;
		playerX[1] = 0;
		enemy = new int[2];
		enemy[0] = 1;
		enemy[1] = 0;
		enemy = new int[2];
		enemy[0] = 1;
		enemy[1] = 0;
		
		try{
			channel = DatagramChannel.open();
		    SocketAddress address = new InetSocketAddress(0);
		    DatagramSocket socket = channel.socket();
		    socket.bind(address);
		    
		    SocketAddress server = new InetSocketAddress("76.121.76.188", 4444);
		    channel.connect(server);
		    
		    ByteBuffer sendBuf = ByteBuffer.allocate(255);
		    sendBuf.put((byte) 0);
		    channel.send(sendBuf, server);
			
		    ByteBuffer receiveBuf  = ByteBuffer.allocate(255);
		    channel.receive(receiveBuf);
			this.playerNum  = receiveBuf.getInt();
			System.out.println("#:"+this.playerNum);
			
		    
		}
		
		catch(Exception e){
			e.printStackTrace();
		}
	}

	@Override
	public void update(GameContainer gc, int delta) throws SlickException {
		Input input = gc.getInput();
		 if(input.isKeyDown(Input.KEY_A))
	        {
	            playerX[playerNum]-=2;
	        }
	 
	        if(input.isKeyDown(Input.KEY_D))
	        {
	        	playerX[playerNum]+=2;
	        }
	}
}

What is your exact output on the console from your TestServer and TestClient instances?

Client: (both)


Sun May 15 17:20:43 PDT 2011 INFO:Slick Build #229
Sun May 15 17:20:43 PDT 2011 INFO:LWJGL Version: 2.6
Sun May 15 17:20:43 PDT 2011 INFO:OriginalDisplayMode: 1024 x 600 x 32 @60Hz
Sun May 15 17:20:43 PDT 2011 INFO:TargetDisplayMode: 640 x 480 x 0 @0Hz
Sun May 15 17:20:44 PDT 2011 INFO:Starting display 640x480
Sun May 15 17:20:44 PDT 2011 INFO:Use Java PNG Loader = true
WARNING: Found unknown Windows version: Windows 7
Attempting to use default windows plug-in.
Loading: net.java.games.input.DirectAndRawInputEnvironmentPlugin
Sun May 15 17:20:44 PDT 2011 INFO:Found 0 controllers
#:0

Server:


#:0
Connected with player: 0 Now incrementing

Incremented to: 1

#:1
Connected with player: 1 Now incrementing

Incremented to: 2