1er commit

This commit is contained in:
2021-08-21 10:14:47 +02:00
commit a99ecf7c2d
99 changed files with 66605 additions and 0 deletions

76
src/game/server/Lobby.cpp Normal file
View File

@@ -0,0 +1,76 @@
#include "game/server/Lobby.h"
#include "game/server/Server.h"
#include "misc/Time.h"
#include <iostream>
namespace td {
namespace server {
/*static constexpr std::uint8_t timeNotifications[] = {
2 * 60, // 2 min
60 + 30, // 1 min 30 s
60, // 1 min
30, // 30 s
15, // 15 s
10, // 10 s
5, // 5 s
4, // 4 s
3, // 3 s
2, // 2 s
1, // 1 s
};*/
Lobby::Lobby(Server* server) : m_Server(server), m_Timer(1000, std::bind(&Lobby::sendTimeRemaining, this)){
}
void Lobby::tick(){
if (m_GameStarted || m_StartTimerTime == 0)
return;
if(utils::getTime() - m_StartTimerTime >= LOBBY_WAITING_TIME){
protocol::UpdateGameStatePacket packet(game::GameState::Game);
m_Server->broadcastPacket(&packet);
m_GameStarted = true;
m_Server->lauchGame();
return;
}
m_Timer.update();
}
void Lobby::sendTimeRemaining(){
protocol::UpdateLobbyTimePacket packet(LOBBY_WAITING_TIME - (utils::getTime() - m_StartTimerTime)); // converting second to millis
m_Server->broadcastPacket(&packet);
}
void Lobby::OnPlayerJoin(std::uint8_t playerID){
if(m_GameStarted)
return;
std::cout << "(Server) Player Joined Lobby !\n";
m_Players.push_back(playerID);
if (m_Players.size() == 2){ // start timer if a second player join the match
m_StartTimerTime = utils::getTime();
m_Timer.reset();
}
}
void Lobby::OnPlayerLeave(std::uint8_t playerID){
if(m_GameStarted)
return;
std::cout << "(Server) Player Leaved Lobby !\n";
auto it = std::find(m_Players.begin(), m_Players.end(), playerID);
if (it == m_Players.end())
return;
m_Players.erase(it);
if (m_Players.size() == 1){
protocol::UpdateLobbyTimePacket packet(0);
m_Server->broadcastPacket(&packet);
m_StartTimerTime = 0; // reset timer if there is only one player left
}
}
} // namespace server
} // namespace td

105
src/game/server/Server.cpp Normal file
View File

@@ -0,0 +1,105 @@
#include "game/server/Server.h"
#include <iostream>
#include "protocol/PacketFactory.h"
namespace td {
namespace server {
Server::Server(const std::string& worldFilePath){
m_Game.getWorld()->loadMapFromFile(worldFilePath);
}
void Server::lauchGame(){
m_Game.startGame();
}
bool Server::start(std::uint16_t port){
if(!m_Listener.listen(port, 10)){
std::cout << "Failed to bind port " << port << " !\n";
return false;
}
if(!m_Listener.setBlocking(false)){
std::cout << "Failed to block server socket !\n";
return false;
}
std::cout << "Server started at port " << port << " !\n";
m_TickCounter.reset();
return true;
}
void Server::stop(){
protocol::DisconnectPacket packet("Server closed");
broadcastPacket(&packet);
m_Listener.close();
m_Listener.destroy();
m_Connections.clear();
getPlayers().clear();
}
void Server::tick(std::uint64_t delta){
accept();
updateSockets();
m_Lobby.tick();
m_Game.tick(delta);
if(m_TickCounter.update()){
protocol::ServerTpsPacket packet(m_TickCounter.getTPS(), utils::getTime());
broadcastPacket(&packet);
}
}
void Server::accept(){
static std::uint8_t newPlayerID = 0;
network::TCPSocket newSocket;
if (m_Listener.accept(newSocket)){
ServerConnexion con(newSocket, newPlayerID);
m_Connections.insert(std::move(ConnexionMap::value_type{newPlayerID, std::move(con)}));
OnPlayerJoin(newPlayerID);
m_Connections[newPlayerID].setServer(this);
newPlayerID++;
}
}
void Server::updateSockets(){
std::int16_t closedConnexionID = -1;
for (auto& connection : m_Connections){
ServerConnexion& con = connection.second;
if(con.getSocketStatus() != network::Socket::Status::Connected){
closedConnexionID = connection.first;
}else{
con.updateSocket();
}
}
if(closedConnexionID != -1){
removeConnexion(closedConnexionID);
}
}
void Server::broadcastPacket(protocol::Packet* packet){
for (auto& connection : m_Connections){
ServerConnexion& con = connection.second;
con.sendPacket(packet);
}
}
void Server::removeConnexion(std::uint8_t connexionID){
getPlayers().erase(getPlayers().find(connexionID));
m_Connections.erase(connexionID);
m_Lobby.OnPlayerLeave(connexionID);
OnPlayerLeave(connexionID);
}
void Server::OnPlayerJoin(std::uint8_t id){
m_Lobby.OnPlayerJoin(id);
getPlayers().insert({id, game::Player{id}});
}
void Server::OnPlayerLeave(std::uint8_t id){
protocol::PlayerLeavePacket packet(id);
broadcastPacket(&packet);
}
} // namespace server
} // namespace td

View File

@@ -0,0 +1,153 @@
#include "game/server/ServerConnexion.h"
#include "protocol/PacketDispatcher.h"
#include "protocol/PacketFactory.h"
#include "game/server/Server.h"
#include "misc/Time.h"
#include "misc/Random.h"
#include <chrono>
#define KEEP_ALIVE_TIMEOUT 10 * 1000 // 10s
namespace td{
namespace server{
/*
NEVER TRUST USER INPUT
*/
ServerConnexion::ServerConnexion(): m_Player(0){
}
ServerConnexion::ServerConnexion(network::TCPSocket& socket, std::uint8_t id) : Connexion::Connexion(&m_Dispatcher, socket), m_ID(id), m_Player(0){
Connexion::updateSocket();
}
ServerConnexion::ServerConnexion(ServerConnexion&& move) : Connexion::Connexion(std::move(move)), m_Server(move.m_Server),
m_ID(move.m_ID), m_KeepAlive(move.m_KeepAlive), m_Player(move.m_Player){
move.m_Server = nullptr;
registerHandlers();
}
void ServerConnexion::registerHandlers(){
GetDispatcher()->RegisterHandler(protocol::PacketType::PlayerLogin, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::KeepAlive, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::SelectTeam, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::Disconnect, this);
}
bool ServerConnexion::updateSocket(){
checkKeepAlive();
return Connexion::updateSocket();
}
void ServerConnexion::checkKeepAlive(){
std::uint64_t time = utils::getTime();
if (time - m_KeepAlive.sendTime > KEEP_ALIVE_TIMEOUT){
if (m_KeepAlive.recievedResponse){
sendKeepAlive();
}
else{
protocol::DisconnectPacket packet("Time out");
sendPacket(&packet);
closeConnection();
}
}
}
void ServerConnexion::sendKeepAlive(){
m_KeepAlive.keepAliveID = utils::getRandomNumber(UINT64_MAX);
m_KeepAlive.recievedResponse = false;
protocol::KeepAlivePacket keepAlivePacket(m_KeepAlive.keepAliveID);
sendPacket(&keepAlivePacket);
std::uint64_t time = utils::getTime();
m_KeepAlive.sendTime = time;
}
void ServerConnexion::HandlePacket(protocol::PlayerLoginPacket* packet){
if (m_Player->getName().empty() && !packet->getPlayerName().empty()){
m_Player->setName(packet->getPlayerName());
protocol::PlayerJoinPacket joinPacket(m_ID, m_Player->getName());
m_Server->broadcastPacket(&joinPacket);
std::map<std::uint8_t, protocol::PlayerInfo> playerNames;
for (const auto& pair : m_Server->getPlayers()){
const game::Player& player = pair.second;
if (!player.getName().empty()){
protocol::PlayerInfo playerInfo;
playerInfo.name = player.getName();
playerInfo.team = player.getTeamColor();
playerNames.insert({player.getID(), playerInfo});
}
}
protocol::PlayerListPacket listPacket(playerNames);
sendPacket(&listPacket);
}
}
void ServerConnexion::HandlePacket(protocol::SelectTeamPacket* packet){
if(m_Server->getGame().getGameState() != game::GameState::Lobby)
return;
if((std::int8_t) packet->getSelectedTeam() >= -1 || (std::int8_t) packet->getSelectedTeam() <= 1){
//m_Player->setTeamColor(packet->getSelectedTeam());
if(m_Player->getTeamColor() == game::TeamColor::None){ //join a team
m_Server->getGame().getTeam(packet->getSelectedTeam()).addPlayer(m_Player);
}else if(packet->getSelectedTeam() == game::TeamColor::None){ // leave a team
m_Server->getGame().getTeam(m_Player->getTeamColor()).removePlayer(m_Player);
m_Player->setTeamColor(game::TeamColor::None);
}else{ // change team
m_Server->getGame().getTeam(m_Player->getTeamColor()).removePlayer(m_Player);
m_Server->getGame().getTeam(packet->getSelectedTeam()).addPlayer(m_Player);
}
protocol::UpdatePlayerTeamPacket updateTeamPacket(m_ID, packet->getSelectedTeam());
m_Server->broadcastPacket(&updateTeamPacket);
}
}
void ServerConnexion::HandlePacket(protocol::KeepAlivePacket* packet){
if(packet->getAliveID() == m_KeepAlive.keepAliveID)
m_KeepAlive.recievedResponse = true;
}
void ServerConnexion::HandlePacket(protocol::DisconnectPacket* packet){
closeConnection();
}
void ServerConnexion::setServer(Server* server){
m_Server = server;
m_Player = &m_Server->getPlayers().at(m_ID);
initConnection();
sendKeepAlive();
}
void ServerConnexion::initConnection(){
protocol::UpdateGameStatePacket statePacket(m_Server->getGame().getGameState());
sendPacket(&statePacket);
protocol::ConnexionInfoPacket conPacket(m_ID);
sendPacket(&conPacket);
if (m_Server->getGame().getGameState() == game::GameState::Game){
protocol::WorldBeginDataPacket headerDataPacket(m_Server->getGame().getWorld());
protocol::WorldBeginDataPacket dataPacket(m_Server->getGame().getWorld());
sendPacket(&headerDataPacket);
sendPacket(&dataPacket);
}
}
ServerConnexion::~ServerConnexion(){
if (GetDispatcher() != nullptr)
GetDispatcher()->UnregisterHandler(this);
}
} // namespace server
} // namespace td

View File

@@ -0,0 +1,57 @@
#include "game/server/ServerGame.h"
#include "game/server/Server.h"
namespace td {
namespace server {
ServerGame::ServerGame(server::Server* server) : m_Server(server), m_ServerWorld(server, this), game::Game(&m_ServerWorld){
}
void ServerGame::tick(std::uint64_t delta){
Game::tick(delta);
m_GoldMineTimer.update();
}
void ServerGame::startGame(){
protocol::WorldBeginDataPacket headerMapData(m_World);
m_Server->broadcastPacket(&headerMapData);
protocol::WorldDataPacket mapData(m_World);
m_Server->broadcastPacket(&mapData);
m_GameState = game::GameState::Game;
balanceTeams();
m_ServerWorld.spawnMobs(game::MobType::Zombie, 1, 0, 12);
}
void ServerGame::updateGoldMines(){
for(auto& pair : m_Server->getPlayers()){
game::Player* player = &pair.second;
player->setGold(player->getGold() + player->getGoldPerSecond());
protocol::UpdateMoneyPacket packet(player->getGold());
m_Server->getConnexions()[player->getID()].sendPacket(&packet);
}
}
void ServerGame::balanceTeams(){
for(auto playerInfo : m_Players){
game::Player& player = playerInfo.second;
if(player.getTeamColor() == game::TeamColor::None){
game::Team& redTeam = getRedTeam();
game::Team& blueTeam = getBlueTeam();
if(blueTeam.getPlayerCount() > redTeam.getPlayerCount()){
redTeam.addPlayer(&player);
}else{
blueTeam.addPlayer(&player);
}
protocol::UpdatePlayerTeamPacket packet(player.getID(), player.getTeamColor());
m_Server->broadcastPacket(&packet);
}
}
}
} // namespace game
} // namespace td

View File

@@ -0,0 +1,50 @@
#include "game/server/ServerWorld.h"
#include "game/server/Server.h"
#include "misc/Random.h"
#define MOB_SPAWN_PRECISION 100.0f
namespace td {
namespace server {
ServerWorld::ServerWorld(Server* server, ServerGame* game) : m_Server(server), game::World(game){
}
void ServerWorld::spawnMobs(game::MobType type, std::uint8_t level, game::PlayerID sender, std::uint8_t count){
for (int i = 0; i < count; i++){
game::TeamColor senderTeam = m_Game->getPlayers().at(sender).getTeamColor();
game::Spawn* enemyMobSpawn;
if(senderTeam == game::TeamColor::Red){
enemyMobSpawn = &m_Spawns[(std::size_t) game::TeamColor::Blue];
}else{
enemyMobSpawn = &m_Spawns[(std::size_t) game::TeamColor::Red];
}
std::int32_t spawnCenterX = enemyMobSpawn->x;
std::int32_t spawnCenterY = enemyMobSpawn->y;
std::int32_t minSpawnY = spawnCenterY - 2;
std::int32_t maxSpawnY = spawnCenterY + 2;
std::int32_t minSpawnX = spawnCenterX - 2;
std::int32_t maxSpawnX = spawnCenterX + 2;
std::uint64_t randomX = utils::getRandomNumber(std::abs(minSpawnX - maxSpawnX) * MOB_SPAWN_PRECISION);
float mobX = (float) randomX / MOB_SPAWN_PRECISION + (float) minSpawnX;
std::uint64_t randomY = utils::getRandomNumber(std::abs(minSpawnY - maxSpawnY) * MOB_SPAWN_PRECISION);
float mobY = (float) randomY / MOB_SPAWN_PRECISION + (float) minSpawnY;
spawnMobAt(m_CurrentMobID, type, level, sender, mobX, mobY, enemyMobSpawn->direction);
protocol::SpawnMobPacket packet(m_CurrentMobID, type, level, sender, mobX, mobY, enemyMobSpawn->direction);
m_Server->broadcastPacket(&packet);
m_CurrentMobID++;
}
}
} // namespace server
} // namespace td