ArrayList в сериализуемом объекте, не переносящем writeUnshared / readUnshared (по сети) - PullRequest
0 голосов
/ 15 октября 2018

Я занимаюсь разработкой многопользовательской игры на Java, основанной на моей собственной клиент-серверной архитектуре.Короче говоря, клиент запрашивает копию объекта World сервера 30 раз в секунду и, получив его, устанавливает свою копию на стороне клиента в ответ.Все это делается с помощью стандартного сетевого API Java.

Проблема, с которой я сталкиваюсь, заключается в том, что я также храню ArrayList объектов Player в мире, и когда я добавляю Player в этот список, клиент неполучить обновление.Он все еще получает копию мира с сервера, но он не обновлен.

Я столкнулся с аналогичной проблемой в прошлом проекте, которая была вызвана write / readObject, и исправил ее с помощью write/ readUnshared, но даже это не работает.

Вот важные вещи со стороны сервера связи:

String message;
int sum = 0;
while(active)
{
    message = "";
    try {
        message = in.readUTF();
    } catch (IOException e) {
        active = false;
        System.out.println("Lost connection with client " + socket.getInetAddress());
    }

    if(message.equals("GETWORLD"))
    {
        try {
            sum++;
            if(sum == 100)
                main.world.addPlayer(999, 2, 2);
            System.out.println("Client requested world (#" + sum + ")");
            System.out.println(main.world.players.size());
            out.writeUnshared(main.world);
            out.flush();
            System.out.println("Sent client world (#" + sum + ")");
        } catch (IOException e) {
            active = false;
            System.out.println("Lost connection with client " + socket.getInetAddress());
        }
    }

    if(message.equals("DISCONNECT"))
    {
        active = false;
        System.out.println("Client " + socket.getInetAddress() + " requested disconnect");
    }
}

А затем клиентская сторона:

Object read = null;
int sum = 0;
while(active)
{
    try {
        Thread.sleep((long)(1000 / 30.0));

        if(connected)
        {
            sum++;
            System.out.println("Asking server for world (#" + sum + ")");
            out.writeUTF("GETWORLD");
            out.flush();

            read = in.readUnshared();
            if(read instanceof World)
            {
                World temp = (World)read;
                System.out.println(temp.players.size());
                frame.panel.updateWorld((World)read);
                System.out.println("Got world from server (#" + sum + ")");
            }
        }
    } catch (InterruptedException | ClassNotFoundException e1) {
        active = false;
        e1.printStackTrace();
    } catch (IOException e2) {
        active = false;
        System.out.println("Lost connection with server @ " + socket.getInetAddress());
        frame.dispose();
        System.exit(0);
    }
}

Очевидно, что переменная sum предназначена для отладки.Далее я проверил это с некоторым выводом, вот что меня пугает:

Client log:
...
Asking server for world (#99)
1
Got world from server (#99)
Asking server for world (#100)
1
Got world from server (#100)
Asking server for world (#101)
1
Got world from server (#101)
...

Server log:
...
Client requested world (#99)
1
Sent client world (#99)
Client requested world (#100)
2
Sent client world (#100)
Client requested world (#101)
2
Sent client world (#101)
...

Здесь вы можете видеть, что, хотя номера запросов совпадают, существует явное несоответствие между количеством объектов Player в объекте World.

Вот важные вещи из классов World и Player для любопытных:

public class World implements Serializable
{

    public ArrayList<Room> rooms;
    public ArrayList<Player> players;

    private QuickMaths qm;

...

public class Player implements Serializable
{

    private double xPos;
    private double yPos;
    private Color color;

    int id;
    ...

Я прошу прощения, если это долголегкая проблема.Я не уверен, что это проблема с ссылками или какая-то другая странность, но это действительно сводит меня с ума.Заранее спасибо.

1 Ответ

0 голосов
/ 15 октября 2018

Ваша проблема с writeUnshared, которая немного вводит в заблуждение.Прочитайте здесь :

"Обратите внимание, что правила, описанные выше, применяются только к объекту базового уровня, написанному с помощью writeUnshared, а не к любым транзитивно ссылочным подобъектам в графе объектовбыть сериализованным. "

Это означает, что объект проигрывателя не будет записан дважды, но будет использоваться старая ссылка на этот объект в дереве сериализации.

Решение этой проблемыбудет вызывать метод reset после каждого вызова записи, чтобы гарантировать, что на старые записанные объекты больше не будут ссылаться.

Итак:

out.writeUnshared(main.world);
out.flush();
out.reset();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...