More networking code implementation
Move connection code from Client.cpp to ServerConnection.cpp GameScene connects to the server and sets player position based on it. Server 'authenticates' client from (currently unused) token before giving it data. Packets now support encoding floats and strings. Server now acknowledges port argument. ServerPlayer class for keeping track of client Player entities.master
parent
0639c3b655
commit
d50cc1c072
|
@ -89,10 +89,9 @@ add_executable(zeus
|
|||
zeus/game/MenuScene.h
|
||||
zeus/server/Server.cpp
|
||||
zeus/server/Server.h
|
||||
zeus/client/ClientPacket.cpp
|
||||
zeus/server/ClientConnection.cpp
|
||||
zeus/server/ClientConnection.h
|
||||
zeus/server/Packet.cpp
|
||||
zeus/server/Packet.h)
|
||||
zeus/server/Packet.h zeus/server/ServerPlayer.cpp zeus/server/ServerPlayer.h zeus/client/ServerConnection.cpp zeus/client/ServerConnection.h)
|
||||
|
||||
target_link_libraries(zeus ${OPENGL_gl_LIBRARY} glfw libGLEW.so pthread lua dl)
|
||||
|
|
|
@ -46,58 +46,6 @@ void Client::start(char* path) {
|
|||
Scene* m = new MenuScene(state);
|
||||
sceneManager.setScene(m);
|
||||
|
||||
//Try to connect to a server
|
||||
try {
|
||||
asio::io_context io_context;
|
||||
udp::resolver resolver(io_context);
|
||||
udp::endpoint receiver_endpoint = *resolver.resolve(udp::v4(), "127.0.0.1", "12346").begin();
|
||||
|
||||
udp::socket socket(io_context);
|
||||
socket.open(udp::v4());
|
||||
|
||||
int attempts = 0;
|
||||
bool connected = false;
|
||||
while (!connected) {
|
||||
if (attempts > 5) {
|
||||
break;
|
||||
}
|
||||
|
||||
Packet p(Packet::HANDSHAKE);
|
||||
p.addInt(attempts);
|
||||
auto send_buf = p.serialize();
|
||||
|
||||
socket.send_to(asio::buffer(send_buf, send_buf.size()), receiver_endpoint);
|
||||
attempts++;
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
|
||||
if (socket.available() > 0) {
|
||||
std::cout << "Connected" << std::endl;
|
||||
connected = true;
|
||||
}
|
||||
else {
|
||||
std::cout << "Failed to connect..." << std::endl;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds((attempts < 3 ? 50 : 700)));
|
||||
}
|
||||
}
|
||||
if (!connected) {
|
||||
std::cout << "Connection timed out!" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
char recv_buf[20];
|
||||
|
||||
udp::endpoint sender_endpoint; //Populated by the next line
|
||||
size_t len = socket.receive_from(asio::buffer(recv_buf), sender_endpoint);
|
||||
|
||||
std::cout.write(recv_buf, len);
|
||||
std::cout << "Done " << len << std::endl;
|
||||
}
|
||||
catch (std::exception &e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
|
||||
|
||||
while (!renderer->getWindow()->getShouldClose()) loop();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
//
|
||||
// Created by aurailus on 11/01/19.
|
||||
//
|
||||
|
||||
#include "ServerConnection.h"
|
||||
|
||||
ServerConnection::ServerConnection(std::string address, int port) {
|
||||
this->address = std::move(address);
|
||||
this->port = port;
|
||||
this->connected = false;
|
||||
}
|
||||
|
||||
ServerConfig* ServerConnection::connect() {
|
||||
try {
|
||||
asio::ip::udp::resolver resolver(io_context);
|
||||
remote_endpoint = *resolver.resolve(asio::ip::udp::v4(), address, std::to_string(port)).begin();
|
||||
|
||||
asio::ip::udp::socket socket(io_context);
|
||||
socket.open(asio::ip::udp::v4());
|
||||
|
||||
int attempts = 0;
|
||||
bool handshook = false;
|
||||
|
||||
Timer t("Connection time");
|
||||
while (t.elapsedNs() < 10L*1000000L*1000L) {
|
||||
|
||||
if (!handshook) {
|
||||
Packet p;
|
||||
p = Packet(Packet::HANDSHAKE);
|
||||
p.addInt(attempts++);
|
||||
auto data = p.serialize();
|
||||
|
||||
socket.send_to(asio::buffer(data, data.size()), remote_endpoint);
|
||||
std::cout << "Sent handshake." << std::endl;
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
|
||||
size_t pendingSize = socket.available();
|
||||
if (pendingSize > 0) {
|
||||
std::vector<Packet::PacketByte> recv_buf((unsigned long)pendingSize);
|
||||
|
||||
auto remote_endpoint = new asio::ip::udp::endpoint();
|
||||
socket.receive_from(asio::buffer(recv_buf, pendingSize), *remote_endpoint);
|
||||
|
||||
auto packet = Packet::deserialize(recv_buf);
|
||||
|
||||
if (packet.type == Packet::HANDSHAKE) {
|
||||
std::cout << "Handshake received." << std::endl;
|
||||
t = Timer("Authenticate time");
|
||||
handshook = true;
|
||||
|
||||
Packet p;
|
||||
p = Packet(Packet::AUTHTOKEN);
|
||||
p.addString("Hello! I'm a string!!!");
|
||||
auto data = p.serialize();
|
||||
|
||||
socket.send_to(asio::buffer(data, data.size()), *remote_endpoint);
|
||||
}
|
||||
else if (packet.type == Packet::PLAYRINFO) {
|
||||
std::cout << "Player info received." << std::endl;
|
||||
connected = true;
|
||||
|
||||
float x = Packet::decodeFloat(&packet.data[0]);
|
||||
float y = Packet::decodeFloat(&packet.data[4]);
|
||||
float z = Packet::decodeFloat(&packet.data[8]);
|
||||
|
||||
return new ServerConfig {
|
||||
.playerPos = glm::vec3(x, y, z)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!connected) {
|
||||
std::cout << "Connection timed out!" << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
catch (std::exception &e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
ServerConnection::~ServerConnection() {
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
//
|
||||
// Created by aurailus on 11/01/19.
|
||||
//
|
||||
|
||||
#ifndef ZEUS_SERVERCONNECTION_H
|
||||
#define ZEUS_SERVERCONNECTION_H
|
||||
|
||||
#include <string>
|
||||
#include <vec3.hpp>
|
||||
#include <asio.hpp>
|
||||
#include "../engine/Timer.h"
|
||||
#include "../server/Packet.h"
|
||||
|
||||
struct ServerConfig {
|
||||
glm::vec3 playerPos;
|
||||
};
|
||||
|
||||
class ServerConnection {
|
||||
public:
|
||||
ServerConnection(std::string address, int port);
|
||||
|
||||
ServerConfig* connect();
|
||||
|
||||
~ServerConnection();
|
||||
|
||||
private:
|
||||
bool connected;
|
||||
|
||||
asio::io_context io_context;
|
||||
asio::ip::udp::endpoint remote_endpoint;
|
||||
|
||||
std::string address;
|
||||
int port;
|
||||
};
|
||||
|
||||
|
||||
#endif //ZEUS_SERVERCONNECTION_H
|
|
@ -7,6 +7,9 @@
|
|||
#include "../lua_api/l_register_blockmodel.h"
|
||||
|
||||
GameScene::GameScene(ClientState* state) : Scene(state) {
|
||||
server = new ServerConnection("127.0.0.1", 12345);
|
||||
auto info = server->connect();
|
||||
|
||||
textureAtlas = new TextureAtlas("../tex");
|
||||
blockAtlas = new BlockAtlas(textureAtlas);
|
||||
|
||||
|
@ -33,7 +36,7 @@ GameScene::GameScene(ClientState* state) : Scene(state) {
|
|||
|
||||
player = new Player();
|
||||
player->create(world, state->renderer->getCamera());
|
||||
player->setPos(glm::vec3(16, 24, 0));
|
||||
player->setPos(info->playerPos);
|
||||
|
||||
world->genNewChunk(glm::vec3(0, 0, 0));
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "../engine/Ray.h"
|
||||
#include "../client/Scene.h"
|
||||
#include "../server/Server.h"
|
||||
#include "../client/ServerConnection.h"
|
||||
|
||||
class GameScene : public Scene {
|
||||
public:
|
||||
|
@ -30,18 +31,13 @@ public:
|
|||
|
||||
void cleanup() override;
|
||||
public:
|
||||
ServerConnection* server;
|
||||
Player* player;
|
||||
|
||||
//The World object represents the physical game region that is played in. It handles chunk updates and entities.
|
||||
World* world;
|
||||
|
||||
//The texture atlas makes a single patched texture from an asset folder.
|
||||
TextureAtlas* textureAtlas;
|
||||
|
||||
//The block atlas holds block definitions and models.
|
||||
BlockAtlas* blockAtlas;
|
||||
|
||||
//Entities
|
||||
//Entities to be drawn with world shaders
|
||||
std::vector<Entity*> entities;
|
||||
|
||||
//GUI Related things
|
||||
|
|
|
@ -8,6 +8,7 @@ ClientConnection::ClientConnection() = default;
|
|||
|
||||
ClientConnection::ClientConnection(asio::ip::udp::endpoint* endpoint) {
|
||||
this->endpoint = endpoint;
|
||||
this->authenticated = false;
|
||||
}
|
||||
|
||||
ClientConnection::~ClientConnection() {
|
||||
|
|
|
@ -14,6 +14,7 @@ public:
|
|||
explicit ClientConnection(asio::ip::udp::endpoint* endpoint);
|
||||
|
||||
asio::ip::udp::endpoint* endpoint;
|
||||
bool authenticated;
|
||||
long lastAliveTime;
|
||||
|
||||
~ClientConnection();
|
||||
|
|
|
@ -65,6 +65,31 @@ void Packet::encodeInt(std::vector<Packet::PacketByte> &target, int num) {
|
|||
}
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
void Packet::encodeFloat(std::vector<Packet::PacketByte> &target, float num) {
|
||||
typedef union {
|
||||
float a;
|
||||
unsigned char b[4];
|
||||
} float_union;
|
||||
|
||||
float_union fl {num};
|
||||
|
||||
target.push_back(fl.b[0]);
|
||||
target.push_back(fl.b[1]);
|
||||
target.push_back(fl.b[2]);
|
||||
target.push_back(fl.b[3]);
|
||||
}
|
||||
|
||||
float Packet::decodeFloat(Packet::PacketByte *floatStart) {
|
||||
typedef union {
|
||||
float a;
|
||||
unsigned char b[4];
|
||||
} float_union;
|
||||
|
||||
float_union fl { .b = {*floatStart, *(floatStart+1), *(floatStart+2), *(floatStart+3)} };
|
||||
|
||||
return fl.a;
|
||||
}
|
||||
|
||||
int Packet::decodeInt(PacketByte* intStart) {
|
||||
int num = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
|
@ -84,4 +109,26 @@ void Packet::addIntegers(std::vector<int> &integers) {
|
|||
void Packet::addInt(int integer) {
|
||||
encodeInt(this->data, integer);
|
||||
this->length = data.size();
|
||||
}
|
||||
|
||||
void Packet::addFloats(std::vector<float> &floats) {
|
||||
for (float f : floats) {
|
||||
encodeFloat(this->data, f);
|
||||
}
|
||||
this->length = data.size();
|
||||
}
|
||||
|
||||
void Packet::addFloat(float floatVal) {
|
||||
encodeFloat(this->data, floatVal);
|
||||
this->length = data.size();
|
||||
}
|
||||
|
||||
void Packet::addString(std::string *string) {
|
||||
addInt((int)string->length());
|
||||
std::copy(string->begin(), string->end(), std::back_inserter(data));
|
||||
this->length = data.size();
|
||||
}
|
||||
|
||||
void Packet::addString(std::string string) {
|
||||
addString(&string);
|
||||
}
|
|
@ -6,6 +6,8 @@
|
|||
#define ZEUS_PACKET_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <asio.hpp>
|
||||
|
||||
class Packet {
|
||||
public:
|
||||
|
@ -17,9 +19,13 @@ public:
|
|||
|
||||
void addIntegers(std::vector<int> &integers);
|
||||
void addInt(int integer);
|
||||
void addFloats(std::vector<float> &floats);
|
||||
void addFloat(float floatVal);
|
||||
void addString(std::string *string);
|
||||
void addString(std::string string);
|
||||
|
||||
unsigned long length;
|
||||
PacketType type;
|
||||
unsigned long length = 0;
|
||||
PacketType type = UNDEFINED;
|
||||
std::vector<PacketByte> data;
|
||||
|
||||
~Packet() = default;
|
||||
|
@ -27,12 +33,17 @@ public:
|
|||
static Packet deserialize(std::vector<PacketByte> data);
|
||||
std::vector<Packet::PacketByte> serialize();
|
||||
|
||||
static void encodeInt(std::vector<PacketByte> &target, int num);
|
||||
static int decodeInt(PacketByte* intStart);
|
||||
static void encodeInt(std::vector<PacketByte> &target, int num);
|
||||
static int decodeInt(PacketByte* intStart);
|
||||
static void encodeFloat(std::vector<PacketByte> &target, float num);
|
||||
static float decodeFloat(PacketByte* floatStart);
|
||||
public:
|
||||
const static PacketType HANDSHAKE = 0;
|
||||
const static PacketType REQCHUNKS = 1;
|
||||
const static PacketType KEEPALIVE = 2;
|
||||
const static PacketType UNDEFINED = 0;
|
||||
const static PacketType HANDSHAKE = 1;
|
||||
const static PacketType AUTHTOKEN = 2;
|
||||
const static PacketType PLAYRINFO = 2;
|
||||
// const static PacketType REQCHUNKS = 2;
|
||||
// const static PacketType KEEPALIVE = 3;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -3,17 +3,17 @@
|
|||
//
|
||||
|
||||
#include "Server.h"
|
||||
#include "../game/world/Player.h"
|
||||
|
||||
Server::Server() = default;
|
||||
|
||||
Server::Server(int port) {
|
||||
//TODO: Use the port in the server initializer
|
||||
this->port = port;
|
||||
alive = true;
|
||||
}
|
||||
|
||||
void Server::start() {
|
||||
server_socket = new asio::ip::udp::socket(io_context, udp::endpoint(udp::v4(), 12346));
|
||||
server_socket = new asio::ip::udp::socket(io_context, udp::endpoint(udp::v4(), port));
|
||||
|
||||
while (alive) loop();
|
||||
}
|
||||
|
@ -37,28 +37,72 @@ void Server::loop() {
|
|||
std::this_thread::sleep_for(std::chrono::nanoseconds(sleep_for));
|
||||
}
|
||||
|
||||
void Server::handlePacket(Packet &packet, udp::endpoint* endpoint) {
|
||||
std::string identifier = endpoint->address().to_string() + ":" + std::to_string(endpoint->port());
|
||||
std::string Server::createIdentifier(udp::endpoint *endpoint) {
|
||||
return endpoint->address().to_string() + ":" + std::to_string(endpoint->port());
|
||||
}
|
||||
|
||||
if (packet.type == Packet::HANDSHAKE) {
|
||||
if (connections.count(identifier) == 0) {
|
||||
std::cout << "Added " << identifier << " to client connections." << std::endl;
|
||||
auto conn = new ClientConnection(endpoint);
|
||||
connections.insert(std::pair<std::string, ClientConnection*>(identifier, conn));
|
||||
}
|
||||
else {
|
||||
std::cout << identifier << " is already added to client connections." << std::endl;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (connections.count(identifier) == 0) {
|
||||
std::cout << "Non-handshake packet from identifier " << identifier << "." << std::endl;
|
||||
void Server::handlePacket(Packet &packet, udp::endpoint* endpoint) {
|
||||
auto identifier = createIdentifier(endpoint);
|
||||
|
||||
if (connections.count(identifier) == 0 || !connections[identifier]->authenticated) {
|
||||
handleAuthPacket(identifier, packet, endpoint);
|
||||
return;
|
||||
}
|
||||
|
||||
std::cout << packet.type << ", " << Packet::decodeInt(&packet.data[0]) << std::endl;
|
||||
}
|
||||
|
||||
void Server::handleAuthPacket(std::string& identifier, Packet &packet, udp::endpoint* endpoint) {
|
||||
if (connections.count(identifier) == 0) {
|
||||
if (packet.type == Packet::HANDSHAKE) {
|
||||
addConnection(identifier, endpoint);
|
||||
|
||||
Packet p;
|
||||
p = Packet(Packet::HANDSHAKE);
|
||||
auto data = p.serialize();
|
||||
|
||||
server_socket->send_to(asio::buffer(data, data.size()), *endpoint);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (packet.type == Packet::AUTHTOKEN) {
|
||||
int strLen = Packet::decodeInt(&packet.data[0]);
|
||||
|
||||
std::string token(packet.data.begin() + 4, packet.data.begin() + 4 + strLen);
|
||||
|
||||
//TODO: Validate this token somehow
|
||||
std::cout << "Token: " << token << std::endl;
|
||||
|
||||
createPlayer(connections[identifier]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Server::addConnection(std::string &identifier, udp::endpoint *endpoint) {
|
||||
std::cout << "[INFO] Recieved handshake from new client " << identifier << std::endl;
|
||||
auto conn = new ClientConnection(endpoint);
|
||||
connections.insert(std::pair<std::string, ClientConnection*>(identifier, conn));
|
||||
}
|
||||
|
||||
void Server::createPlayer(ClientConnection *connection) {
|
||||
|
||||
auto player = new ServerPlayer(connection, glm::vec3(0, 64, 0));
|
||||
players.insert(std::pair<std::string, ServerPlayer*>("USERNAME", player));
|
||||
|
||||
Packet p;
|
||||
p = Packet(Packet::PLAYRINFO);
|
||||
|
||||
p.addFloat(player->pos.x);
|
||||
p.addFloat(player->pos.y);
|
||||
p.addFloat(player->pos.z);
|
||||
|
||||
auto data = p.serialize();
|
||||
|
||||
server_socket->send_to(asio::buffer(data, data.size()), *connection->endpoint);
|
||||
}
|
||||
|
||||
void Server::cleanup() {
|
||||
alive = false;
|
||||
|
||||
|
@ -67,4 +111,4 @@ void Server::cleanup() {
|
|||
|
||||
Server::~Server() {
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "../engine/Timer.h"
|
||||
#include "ClientConnection.h"
|
||||
#include "Packet.h"
|
||||
#include "ServerPlayer.h"
|
||||
#include <iostream>
|
||||
#include <asio.hpp>
|
||||
|
||||
|
@ -27,9 +28,18 @@ private:
|
|||
void loop();
|
||||
void cleanup();
|
||||
|
||||
void handlePacket(Packet& packet, udp::endpoint* endpoint);
|
||||
std::string createIdentifier(udp::endpoint* endpoint);
|
||||
|
||||
void handlePacket(Packet& packet, udp::endpoint* endpoint);
|
||||
void handleAuthPacket(std::string& identifier, Packet& packet, udp::endpoint* endpoint);
|
||||
|
||||
void addConnection(std::string& identifier, udp::endpoint* endpoint);
|
||||
void createPlayer(ClientConnection* connection);
|
||||
|
||||
//string is IP:Port
|
||||
std::map<std::string, ClientConnection*> connections;
|
||||
//string is username
|
||||
std::map<std::string, ServerPlayer*> players;
|
||||
|
||||
int port;
|
||||
bool alive;
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
//
|
||||
// Created by aurailus on 11/01/19.
|
||||
//
|
||||
|
||||
#include "ServerPlayer.h"
|
||||
|
||||
ServerPlayer::ServerPlayer(ClientConnection *connection, glm::vec3 pos) {
|
||||
this->pos = pos;
|
||||
this->connection = connection;
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
//
|
||||
// Created by aurailus on 11/01/19.
|
||||
//
|
||||
|
||||
#ifndef ZEUS_SERVERPLAYER_H
|
||||
#define ZEUS_SERVERPLAYER_H
|
||||
|
||||
|
||||
#include <vec3.hpp>
|
||||
#include "ClientConnection.h"
|
||||
|
||||
class ServerPlayer {
|
||||
public:
|
||||
ServerPlayer() = default;
|
||||
ServerPlayer(ClientConnection* connection, glm::vec3 pos);
|
||||
|
||||
ClientConnection* connection;
|
||||
glm::vec3 pos;
|
||||
};
|
||||
|
||||
|
||||
#endif //ZEUS_SERVERPLAYER_H
|
Loading…
Reference in New Issue