Java でマルチプレイヤー ゲームを作成していますが、実際にいくつかの問題があります。何らかの理由で、コンソールによると、以前は完全に正常に受信していたにもかかわらず、データグラムソケットがクライアントから設定されたパケットの受信を停止します。私はネットワーキングやソケットを使ったプログラミングについてあまり知らないので、これには困惑しています。
これが私のコードです:
サーバ:
package server;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
import java.util.concurrent.atomic.AtomicInteger;
import shared.BaseEntity;
import shared.MethodNotOverridenException;
import shared.Packet;
import shared.Player;
public class S_GameLoop implements Runnable{
//Constants
private static final int TICKS_PER_SECOND = 25;
private static final int TICKS_TO_SKIP = 1000 / TICKS_PER_SECOND;
private static final int MAX_FRAMESKIP = 5;
private static final int SPAWN_COORD_X = 50;
private static final int SPAWN_COORD_Y = 50;
private Vector<S_Client> ClientList;
private Map<Integer, BaseEntity> EntityMap;
private AtomicInteger IDGenerator;
private boolean gameIsRunning = true;
private DatagramSocket socket;
byte[] recieveData = new byte[1024];
byte[] prevRecieveData = new byte[1024];
private int port;
private int loops;
public S_GameLoop(int port) {
ClientList = new Vector<S_Client>();
this.port = port;
IDGenerator = new AtomicInteger();
EntityMap = new HashMap<Integer, BaseEntity>();
}
private void Init() throws SocketException {
System.out.println("INIT");
socket = new DatagramSocket(port);
System.out.println("[Server] Create listen server on " + socket.getLocalAddress().getHostAddress() + " on port " + socket.getLocalPort());
socket.setSoTimeout(0);
}
private void Running() {
System.out.println("S_GameLoop staring");
long nextGameTick = System.currentTimeMillis();
DatagramPacket recievePacket = new DatagramPacket(recieveData, recieveData.length);
//GameLoop goes here
while(gameIsRunning) {
loops = 0;
//Receive the data
try {
socket.receive(recievePacket);
} catch (IOException e1) {
e1.printStackTrace();
}
while(System.currentTimeMillis() > nextGameTick && loops < MAX_FRAMESKIP) {
try {
Update(recievePacket);
} catch (MethodNotOverridenException | IOException e) {
System.err.println(e);
}
nextGameTick += TICKS_TO_SKIP;
loops++;
}
nextGameTick += TICKS_TO_SKIP;
loops++;
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void Update(DatagramPacket recievePacket) throws IOException, MethodNotOverridenException {
if(prevRecieveData != recieveData) {
parseData(formatData(recievePacket.getData()), recievePacket);
prevRecieveData = recieveData;
} else {
return;
}
}
public static Packet formatData(byte[] data) {
try {
if(data[1] == 0);
String tag = new String(Arrays.copyOfRange(data, 1, 8));
System.out.println("[Server] Recieved packet " + data[0] + " " + new String(tag));
return new Packet(data[0],tag.getBytes(), Arrays.copyOfRange(data, 8, data.length));
} catch (ArrayIndexOutOfBoundsException e) {
return new Packet((byte)0, new byte[0], new byte[0]);
}
}
private void parseData(Packet p, DatagramPacket recievePacket) throws IOException, MethodNotOverridenException {
if(p.getTag() == new byte[0]) {
System.out.println("[Server] Recieved NULL packet");
return;
}
switch (p.getTagAsString()) {
case "LGN_RQS": System.out.println("[Server] Login Request Recieved");
//Login was accepted
//Create a Client ref, and add it to the vector
S_Client newClient = new S_Client(recievePacket.getAddress(), recievePacket.getPort());
ClientList.add(newClient);
//Create a player and add it to Entity list
Player newPlayer = new Player(IDGenerator.getAndIncrement(), ClientList.indexOf(newClient));
EntityMap.put(newPlayer.getEntID(), newPlayer);
System.out.println("[Server] Created new Player with EID " + newPlayer.getEntID() + " and CID " + newPlayer.getCID());
//Send reply to Client that is logging in
sendData(new Packet((byte)2, "LGN_ACP".getBytes(), ("CID;" + ClientList.indexOf(newClient) + ";EID;" + newPlayer.getEntID()).getBytes()).getBytes(), newClient.getIp(), newClient.getPort());
//New Entity was created
//sendData(newPlayer.onCreate(this));
break;
case "HND_SHK": System.out.println("[Server] Handshake Recieved");
String fdata = new String(p.getData());
String[] data = fdata.split(";");
//Get client by client ID
S_Client c = ClientList.get(Integer.parseInt(data[1]));
c.setUsername(data[3]);
System.out.println("[Server] Set Client " + data[1] + "'s username to " + data[3]);
//Now spawn the player
sendData(new Packet((byte)9, "PLR_SPW".getBytes(), ("CID;" + data[1] + ";X;" + SPAWN_COORD_X + ";Y;" + SPAWN_COORD_Y).getBytes()).getBytes());
break;
}
}
public String[] byteArrayToStringArray(byte[] b) {
String fdata = new String(b);
return fdata.split(";");
}
public void createEntity(BaseEntity be) throws MethodNotOverridenException, IOException {
int ID = IDGenerator.incrementAndGet();
be.setEntID(ID);
EntityMap.put(ID, be);
sendData(be.onCreate(this));
}
public void sendData(byte[] sendData, InetAddress IP, int port) throws IOException {
System.out.println("[Server] Send packet " + sendData[0] + " " + new String(Arrays.copyOfRange(sendData, 1, 8)));
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IP, port);
socket.send(sendPacket);
}
public void sendData(byte[] sendData) throws IOException {
for (S_Client entry : ClientList) {
sendData(sendData, entry.getIp(), entry.getPort());
}
}
@Override
public void run() {
try {
Init();
Running();
} catch (SocketException e) {
System.err.println(e);
} catch (IOException e) {
System.err.println(e);
}
}
}
クライアント:
package client;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.Arrays;
import java.util.Vector;
import shared.BaseEntity;
import shared.Packet;
import shared.Player;
public class C_GameLoop {
//How fast should the game update?
private static final int TICKS_PER_SECOND = 25;
//How many ticks should be skipped in order to run it at that speed?
//If it runs faster, then the Render() will be called more often
private static final int TICKS_TO_SKIP = 1000 / TICKS_PER_SECOND;
//How many times should you skip rendering, if you have to?
private static final int MAX_FRAMESKIP = 5;
RenderCanvas rc;
InetAddress ServerIP;
private DatagramSocket socket;
private int port;
private boolean connectedToServer = false;
private boolean waitForData = false;
private String username = "Dummy";
byte[] sendPacket;
Vector<BaseEntity> RenderList;
Player player;
int fps = 0;
public C_GameLoop(RenderCanvas rc){
this.rc = rc;
RenderList = new Vector<BaseEntity>();
}
public boolean Connect(InetAddress ServerIP, int port) throws IOException {
this.port = port;
this.ServerIP = ServerIP;
socket = new DatagramSocket();
socket.setSoTimeout(4000);
DatagramPacket recieveData = new DatagramPacket(new byte[1024], new byte[1024].length);
System.out.println("[Client] Connecting to: " + ServerIP.getHostAddress() + ":" + port);
//Send a login request
sendData(new Packet((byte)1, "LGN_RQS".getBytes()).getBytes());
int retries = 0;
//Start the connect loop
while(!connectedToServer) {
try {
socket.receive(recieveData);
waitForData = false;
parseData(formatData(recieveData.getData()));
//recieveData.setData(new Packet((byte)0, new byte[0], new byte[0]).getBytes());
} catch (SocketTimeoutException e) {
if(waitForData = true && retries <= 4) {
System.out.println("[Client] Failed to recieve response from server, retrying");
parseData(formatData(recieveData.getData()));
retries++;
} else {
System.out.println("[Client] Failed to Connect to the server!");
return false;
}
} catch (IOException e) {
e.printStackTrace();
}
}
return true;
}
public void sendData(byte[] data) throws IOException {
System.out.println("[Client] Sent packet " + data[0] + " " + new String(Arrays.copyOfRange(data, 1, 8)));
DatagramPacket sendPacket = new DatagramPacket(data, data.length, ServerIP, port);
socket.send(sendPacket);
waitForData = true;
}
private void parseData(Packet p) throws IOException {
switch (p.getTagAsString()) {
case "LGN_ACP": System.out.println("[Client] Login Accepted");
//Get the data needed to create a new player from the packet
String fdata = new String(p.getData());
String[] data = fdata.split(";");
Player player = new Player(Integer.parseInt(data[1]), Integer.parseInt(data[3].trim()));
//Add it to the render list
this.player = player;
rc.getCamera().addDrawableEntity(player);
System.out.println("[Client] Player created with CID " + data[1] + " and EID " + data[3]);
//Send the handshake
System.out.println("[Client] Finshing Handshake...");
sendData(new Packet((byte)4, "HND_SHK".getBytes(), ("CID;" + player.getCID() + ";Username;" + username).getBytes()).getBytes());
break;
case "PLR_SPW": System.out.println("[Client] Spawn Recieved");
//Get the coords
String[] spawn_data = byteArrayToStringArray(p.getData());
this.player.setX(Integer.parseInt(spawn_data[3]));
this.player.setY(Integer.parseInt(spawn_data[5].trim()));
sendData(new Packet((byte)0, "KEP_ALV".getBytes()).getBytes());
break;
}
}
public String[] byteArrayToStringArray(byte[] b) {
String fdata = new String(b);
return fdata.split(";");
}
/*
* Formats data into a packet
*/
public static Packet formatData(byte[] data) {
try {
if(data[1] == 0);
String tag = new String(Arrays.copyOfRange(data, 1, 8));
System.out.println("[Client] Recieved packet " + data[0] + " " + new String(tag));
return new Packet(data[0],tag.getBytes(), Arrays.copyOfRange(data, 8, data.length));
} catch (ArrayIndexOutOfBoundsException e) {
return new Packet((byte)0, new byte[0], new byte[0]);
}
}
}
コード実行時のコンソール出力:
INIT
[Server] Create listen server on 0.0.0.0 on port 4334
S_GameLoop staring
[Client] Connecting to: 127.0.0.1:4334
[Client] Sent packet 1 LGN_RQS
[Server] Recieved packet 1 LGN_RQS
[Server] Login Request Recieved
[Server] Created new Player with EID 0 and CID 0
[Server] Send packet 2 LGN_ACP
[Client] Recieved packet 2 LGN_ACP
[Client] Login Accepted
[Client] Player created with CID 0 and EID 0
[Client] Finshing Handshake...
[Client] Sent packet 4 HND_SHK
[Client] Failed to recieve response from server, retrying
(Same lines as previous 6 just repeat 4 times)
[Client] Failed to Connect to the server!
何か案は?