Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Error iterating clients.  (Read 3175 times)

0 Members and 2 Guests are viewing this topic.

yovano_c

  • Newbie
  • *
  • Posts: 40
    • View Profile
    • Email
Error iterating clients.
« on: August 11, 2016, 02:32:43 am »
Hello, I need help, I don't know my error at all please... :/

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10998
    • View Profile
    • development blog
    • Email
AW: Error iterating clients.
« Reply #1 on: August 11, 2016, 03:28:20 am »
Please provide a minimal and complete code example, so we actually see what's going on.
Additionally you should specify what your OS, IDE and compiler are.
And add some info to the problem. When does crash exactly? Etc.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

yovano_c

  • Newbie
  • *
  • Posts: 40
    • View Profile
    • Email
Re: Error iterating clients.
« Reply #2 on: August 11, 2016, 03:35:38 am »
We see it on my screen on attachments. i'm on MacOS, with Xcode, this crash happen each time i connect clients, and when I disconnected and the last client of list of clients disconnect ...

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10998
    • View Profile
    • development blog
    • Email
Re: Error iterating clients.
« Reply #3 on: August 11, 2016, 11:17:54 am »
We see it on my screen on attachments.
We don't, because the code is not complete. There are things missing like what clients is and where all this code is located in, etc.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

yovano_c

  • Newbie
  • *
  • Posts: 40
    • View Profile
    • Email
Re: Error iterating clients.
« Reply #4 on: August 11, 2016, 11:32:53 am »
Character.hpp
#ifndef Character_hpp
#define Character_hpp

#include <iostream>
#include <SFML/Graphics.hpp>

class Character {
   
public:
    std::string name;
    int lvl;
    int money;
    int positionX;
    int positionY;
    sf::Color color;
    sf::RectangleShape view();
};

#endif /* Character_hpp */

 

Character.cpp
#include "Character.hpp"

sf::RectangleShape Character::view()
{
    sf::RectangleShape rectangle;
    rectangle.setSize(sf::Vector2f(40, 40));
    rectangle.setPosition(sf::Vector2f(positionX, positionY));
    return rectangle;
}
 

server.cpp
#include <SFML/Network.hpp>
#include <iostream>
#include <vector>
#include "Character.hpp"

sf::Packet& operator <<(sf::Packet& packet, const Character& character)
{
    return packet << character.name << character.lvl << character.money << character.positionX << character.positionY << character.color.r << character.color.g << character.color.b;
}

sf::Packet& operator >>(sf::Packet& packet, Character& character)
{
    return packet >> character.name >> character.lvl >> character.money >> character.positionX >> character.positionY >> character.color.r >> character.color.g >> character.color.b;
}

int main(int argc, char const** argv)
{
    unsigned short port = 9080;
    sf::TcpListener listener;
    sf::SocketSelector selector;
    bool done = false;
    std::map<std::string, sf::TcpSocket*> clients;
    std::map<std::string, Character*> persos;
   
    std::cout << "Server is running : "  << sf::IpAddress::getPublicAddress() << ":" << port << " ..." << std::endl;
   
    listener.listen(port);
    selector.add(listener);
   
    while (!done)
    {
        if (selector.wait())
        {
            if (selector.isReady(listener))
            {
                sf::TcpSocket *socket = new sf::TcpSocket;
                listener.accept(*socket);
                sf::Packet packet;
               
                if (socket->receive(packet) == sf::Socket::Done)
                {
                    Character perso;
                    packet >> perso;
                    std::cout << "Connected Client: (Name: " << perso.name << ", Level: " << perso.lvl << ", Money: " << perso.money  << ", Position: (X: " << perso.positionX << ", Y: " << perso.positionY << ")). From: " << socket->getRemoteAddress() << std::endl;
                    // show the new connected client on all clients
                    std::map<std::string, sf::TcpSocket*>::iterator it;
                    for (it = clients.begin(); it != clients.end(); it++)
                        it->second->send(packet);
                    // show all conected clients on the new client
                    std::map<std::string, Character*>::iterator it2;
                    for (it2 = persos.begin(); it2 != persos.end(); it2++)
                    {
                        sf::Packet packet;
                        packet << it2->second;
                        socket->send(packet);
                    }
                    // add the new client to the lists
                    persos[perso.name] = &perso;
                    clients[perso.name] = socket;
                    selector.add(*socket);
                }
            }
            else
            {
                std::map<std::string, sf::TcpSocket*>::iterator it;
                for (it = clients.begin(); it != clients.end(); ++it)
                {
                    sf::TcpSocket& client = *it->second;
                    if (selector.isReady(client))
                    {
                        sf::Packet packet, sendPacket;
                        if (client.receive(packet) == sf::Socket::Done)
                        {
                            Character perso;
                            packet >> perso;
                           
                            std::cout << "Updated Client: (Name: " << perso.name << ", Level: " << perso.lvl << ", Money: " << perso.money  << ", Position: (X: " << perso.positionX << ", Y: " << perso.positionY << ")). From: " << client.getRemoteAddress() << std::endl;
                           
                            persos[perso.name] = &perso;
                           
                            sendPacket << perso;
                           
                            std::map<std::string, sf::TcpSocket*>::iterator it2;
                            for (it2 = clients.begin(); it2 != clients.end(); it2++)
                            {
                                if (it != it2)
                                    it2->second->send(sendPacket);
                            }
                        }
                        else if (client.receive(packet) == sf::Socket::Disconnected)
                        {
                            std::string name = it->first;
                            std::cout << "Client (" << name << ") disconnected." << std::endl;
                            std::cout << "List size: " << clients.size();
                            selector.remove(client);
                            client.disconnect();
                            delete(&client);
                            clients.erase(it);
                            it--;
                            std::cout << " then: " << clients.size() << std::endl;
                            persos.erase(name);
                        }
                    }
                }
            }
        }
    }
   
    std::map<std::string, sf::TcpSocket*>::iterator it;
    for (it = clients.begin(); it != clients.end(); it++)
        delete it->second;
   
    return EXIT_SUCCESS;
}

 

client.cpp
#include <SFML/Audio.hpp>
#include <SFML/Graphics.hpp>
#include <SFML/Network.hpp>
#include "ResourcePath.hpp"
#include "Character.hpp"
#include "MyPacket.hpp"


sf::Packet& operator <<(sf::Packet& packet, const Character& character)
{
    return packet << character.name << character.lvl << character.money << character.positionX << character.positionY;
}

sf::Packet& operator >>(sf::Packet& packet, Character& character)
{
    return packet >> character.name >> character.lvl >> character.money >> character.positionX >> character.positionY;
}

char genRandom()
{
    const char alphanum[] =
    "0123456789"
    "!@#$%^&*"
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    "abcdefghijklmnopqrstuvwxyz";
   
    int stringLength = sizeof(alphanum) - 1;
    return alphanum[rand() % stringLength];
}

std::string generator(int length)
{
    std::string str;
    for(unsigned int i = 0; i < length; ++i)
        str += genRandom();
    return str;
}

int main(int, char const**)
{
    srand(time(0));
   
    sf::IpAddress ip = sf::IpAddress().getLocalAddress();
    unsigned short port = 9080;
    std::string publicIp = ip.toString();
    sf::TcpSocket socket;
    bool done = false;
    std::string id;
   
    id = generator(8);
    Character me;
    me.name = id;
    me.color = sf::Color(rand() % 256, rand() % 256, rand() % 256);
    me.lvl = 1;
    me.money = 1000;
    me.positionX = rand() % 700 + 5;
    me.positionY = rand() % 500 + 5;
   
    socket.connect(ip, port);
   
    sf::RenderWindow window(sf::VideoMode(800, 600), "Game", sf::Style::Titlebar | sf::Style::Close);
    sf::Image icon;
    if (!icon.loadFromFile(resourcePath() + "icon.png"))
        return EXIT_FAILURE;
    window.setIcon(icon.getSize().x, icon.getSize().y, icon.getPixelsPtr());
   
    std::map<std::string, Character> persos;
   
    sf::Packet packet;
    packet << me;
    socket.send(packet);
    socket.setBlocking(false);
   
    window.setTitle(id);
   
    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            switch (event.type)
            {
                case sf::Event::Closed:
                    socket.disconnect();
                    window.close();
                    break;
                   
                case sf::Event::KeyPressed:
                {
                    if (event.key.code == sf::Keyboard::Escape)
                    {
                        socket.disconnect();
                        window.close();
                    }
                    else if (event.key.code == sf::Keyboard::Up)
                        me.positionY -= 5;
                    else if (event.key.code == sf::Keyboard::Down)
                        me.positionY += 5;
                    else if (event.key.code == sf::Keyboard::Left)
                        me.positionX -= 5;
                    else if (event.key.code == sf::Keyboard::Right)
                        me.positionX += 5;
                    sf::Packet packet;
                    packet << me;
                    socket.send(packet);
                    sf::RectangleShape rect = me.view();
                    rect.setFillColor(me.color);
                    window.draw(rect);
                    break;
                }
                   
                default:
                    break;
            }
        }
       
        sf::Packet packet;
        socket.receive(packet);
       
        Character tmpChar;
       
        if (packet >> tmpChar)
            persos[tmpChar.name] = tmpChar;
       
        std::map<std::string, Character>::iterator it;
        for (it = persos.begin(); it != persos.end(); it++)
        {
            sf::RectangleShape rect = it->second.view();
            rect.setFillColor(it->second.color);
            window.draw(rect);
        }

       
        sf::RectangleShape rect = me.view();
        rect.setFillColor(sf::Color::Red);
        window.draw(rect);
       
        window.display();
        window.clear(sf::Color::White);
    }

    return EXIT_SUCCESS;
}

 

yovano_c

  • Newbie
  • *
  • Posts: 40
    • View Profile
    • Email
Re: Error iterating clients.
« Reply #5 on: August 11, 2016, 11:37:20 am »
PS: It's not solve the problem but i forgot the color in sf::Packet operators for my Character class of the client.cpp

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Error iterating clients.
« Reply #6 on: August 11, 2016, 12:02:34 pm »
You can't erase an element pointed by an iterator, while iterating with this same iterator. The call to erase will invalidate the iterator, and the next ++it will give undefined behaviour.

The correct way to erase elements while iterating on the container is:

for (auto it = c.begin(); it != c.end; /* empty */)
{
    if (some_condition)
        ++it;
    else
        it = c.erase(it);
}
Laurent Gomila - SFML developer

yovano_c

  • Newbie
  • *
  • Posts: 40
    • View Profile
    • Email
Re: Error iterating clients.
« Reply #7 on: August 11, 2016, 12:45:03 pm »
Thanks it's working perfectly!! So, now,  how can I delete the character disconnected to all clients already connected, to sync the players on the map?

it's after the persos.erase(name), but i don't know how to send the info to connected clients, and in the client side, reload all connected clients, or erase the just deconnected one

else if (client.receive(packet) == sf::Socket::Disconnected)
                        {
                            std::string name = it->first;
                            std::cout << "Client (" << name << ") disconnected." << std::endl;
                            std::cout << "List size: " << clients.size();
                            selector.remove(client);
                            client.disconnect();
                            delete(&client);
                            it = clients.erase(it);
                            std::cout << " then: " << clients.size() << std::endl;
                            persos.erase(name);
                        }