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

Author Topic: Threads in network game  (Read 2755 times)

0 Members and 1 Guest are viewing this topic.

fosheus

  • Newbie
  • *
  • Posts: 1
    • View Profile
Threads in network game
« on: September 02, 2018, 12:41:36 pm »
Hello everyone,

I'm here because I want to develop a basic TCP network game where 2 or more players are in a maze and have to find the exit. The first one get the points, and it loads a new maze.

My first question is, is it a good approch to send the position of the player to the server ? or should i send an event like "player 1 moved left" and the server broadcasts the informations to all players. The problem of this method is, if one player is desynchornised, it will always get the position of the other players wrong.

Second question, are thread a good method to handle sent and received packets from the server.

I have already tested a blank application where players connect to the server and can move around. Each time a player moves, it sends its position to the server that broadcasts the position to all the clients.
Actually I have something like this on the server side :
Code: [Select]
std::map<sf::Uint16,TcpSocket*> clients;
while (running) {
if (selector.wait() {
if (selector.isReady(listener)) {
if (listener.accept(*client) == sf::Socket::Done) {
//accept client, send welcome message, player id and intial position
                                //add client to list

}
else {
delete client;
}
}
else {

for (it=clients.begin();it!=clients.end();++it)
{
if (selector.isReady(*(it->second))) {
sf::Socket::Status status;
status = it->second->receive(packet);
if (status == sf::Socket::Done) {

//handlepacket and broadcast it to all players
}
else if (status == sf::Socket::Error) {
it = clients.remove(it);
}
}
}
}
}
//handle disconnection
}
//clear clients
Server code runs in a dedicated thread because i use the same application for client and server (server just has to select "HOST" at startup)

My client looks like this :
Code: [Select]
#include "GameState.h"
#include "DEFINITIONS.h"
#include "MainMenuState.h"
#include "Common.h"



GameState::GameState(GameDataRef data,sf::String address,bool local) :_data(data),threadSend(&GameState::threadSendData,this), threadReceive(&GameState::threadReceiveData,this)
{

if (!local) {
this->address =  address.toAnsiString();
this->_data->window.setTitle("CLIENT");
std::cout << "CLIENT" << std::endl;
}
else {
server = new Server(data, LISTEN_PORT);
server->startServer();
this->address = "127.0.0.1";
this->_data->window.setTitle("SERVER");
std::cout << "SERVER" << std::endl;
}

state = State::NO_STATE;

}

GameState::~GameState()
{
clearData();
}

void GameState::Init()
{

//init assets
...

if (this->socket.connect(this->address, LISTEN_PORT) != sf::Socket::Done) {
std::cout << "Error on connection" << std::endl;
this->_data->machine.AddState(StateRef(new MainMenuState(this->_data)), true);
}
else {
started = true;
threadReceive.launch();
threadSend.launch();
}

}

void GameState::HandleInput()
{
//poll window event and set updated
}

void GameState::Update(float dt)
{
mutex.lock();
if (updated) {
mapIdEntities[identifier]->move(deltaX, deltaY,dt);
dataToSend.push(mapIdEntities[identifier]->toModel());
updated = false;
}
mutex.unlock();

}

void GameState::Draw(float dt)
{
//CLEAR AND SET WINDOW//

this->_data->window.clear();

this->_data->window.draw(_background);

std::map<sf::Uint16, Entity*>::iterator it;
mutex.lock();
for (it = mapIdEntities.begin(); it != mapIdEntities.end(); it++) {
this->_data->window.draw(*it->second);
}
mutex.unlock();

this->_data->window.display();
}

void GameState::threadSendData()
{
sf::Packet packet;
while (started) {
mutex.lock();
if (dataToSend.size() > 0) {
packet.clear();
EntityModel em = dataToSend.front();
mutex.unlock();
packet << em;
if (socket.send(packet) == sf::Socket::Done) {

}else {
std::cout << "Error sending data from id = "+em.getId() << std::endl;
}
mutex.lock();
dataToSend.pop();

}
mutex.unlock();
}


}

void GameState::threadReceiveData()
{
sf::Packet packet;

while (started) {
packet.clear();
if (socket.receive(packet) != sf::Socket::Done)
{
std::cout << "Error receiving" << std::endl;
}
else {
sf::Uint8 code;
packet >> code;
EntityModel em;
switch (code)
{
case Common::WELCOME :
packet >> this->identifier;
std::cout << "id received : "<<std::hex<<identifier << std::endl;
break;
case Common::GAMEDATA:
while (!packet.endOfPacket()) {
packet >> em;
handleEntityModel(em);
}
break;
default:
std::cout << "undefined packet received" << std::endl;
break;
}
}
}
}

void GameState::handleEntityModel(EntityModel & entityModel)
{
std::map<sf::Uint16, Entity*>::iterator it;
mutex.lock();
//if new enity, add it to entity list with his id
//else affect entity X and Y by id
mutex.unlock();
}

void GameState::clearData()
{
//handle disconnection and clear everything
}


For the moment it works fine with 2 clients. But is it the right way to develop a network game ?