0

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!

何か案は?

4

1 に答える 1

1

あなたのServerクラスはRunnable、一部のワーカー スレッドとして使用するように設計されているようです。

問題はrun()、キャッチされていない例外のためにメソッドが停止していることと、ワーカー スレッドが単に終了していることだと思われます。

(少なくとも) 致命的な例外のスタック トレースをログに記録するように、既定のキャッチされない例外ハンドラーを構成することをお勧めします。詳細については、Threadjavadoc を参照してください。

于 2013-06-21T05:24:11.297 に答える