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

51
include/game/BaseGame.h Normal file
View File

@@ -0,0 +1,51 @@
#pragma once
#include "game/Team.h"
#include "game/World.h"
#include "game/Player.h"
namespace td {
namespace game {
enum class GameState : std::uint8_t{
Lobby,
Game,
EndGame
};
typedef std::map<std::uint8_t, Player> PlayerList;
class Game{
protected:
World* m_World;
std::array<Team, 2> m_Teams = {Team{TeamColor::Red}, Team{TeamColor::Blue}};
GameState m_GameState = GameState::Lobby;
PlayerList m_Players;
public:
Game(World* world);
virtual ~Game();
virtual void tick(std::uint64_t delta);
Team& getRedTeam(){ return m_Teams[(std::uint8_t)TeamColor::Red]; }
const Team& getRedTeam() const{ return m_Teams[(std::uint8_t)TeamColor::Red]; }
Team& getBlueTeam(){ return m_Teams[(std::uint8_t)TeamColor::Blue]; }
const Team& getBlueTeam() const{ return m_Teams[(std::uint8_t)TeamColor::Blue]; }
Team& getTeam(TeamColor team){ return m_Teams[(std::uint8_t)team]; }
const Team& getTeam(TeamColor team) const{ return m_Teams[(std::uint8_t)team]; }
GameState getGameState() const{ return m_GameState; }
void setGameState(GameState gameState){ m_GameState = gameState; };
const World* getWorld() const{ return m_World; }
World* getWorld(){ return m_World; }
const PlayerList& getPlayers() const{ return m_Players; }
PlayerList& getPlayers(){ return m_Players; }
};
} // namespace game
} // namespace td

36
include/game/Connexion.h Normal file
View File

@@ -0,0 +1,36 @@
#pragma once
#include "network/TCPSocket.h"
#include "protocol/PacketHandler.h"
#include "protocol/PacketDispatcher.h"
#include "game/Player.h"
namespace td {
namespace protocol {
class Connexion : public protocol::PacketHandler{
protected:
protocol::PacketDispatcher m_Dispatcher;
private:
network::TCPSocket m_Socket;
public:
Connexion();
Connexion(Connexion&& move);
Connexion(protocol::PacketDispatcher* dispatcher);
Connexion(protocol::PacketDispatcher* dispatcher, network::TCPSocket& socket);
virtual ~Connexion();
virtual bool updateSocket();
void closeConnection();
bool connect(const std::string& address, std::uint16_t port);
network::Socket::Status getSocketStatus() const{return m_Socket.GetStatus();}
void sendPacket(protocol::Packet* packet);
REMOVE_COPY(Connexion);
};
} // namespace server
} // namespace td

View File

@@ -0,0 +1,25 @@
/*
* GameManager.h
*
* Created on: 4 nov. 2020
* Author: simon
*/
#ifndef GAME_GAMEMANAGER_H_
#define GAME_GAMEMANAGER_H_
namespace GameManager{
void render();
void init();
void destroy();
void tick();
void startServer();
}
#endif /* GAME_GAMEMANAGER_H_ */

139
include/game/Mobs.h Normal file
View File

@@ -0,0 +1,139 @@
#pragma once
#include "Towers.h"
#include <cstdint>
#include <vector>
#include <memory>
namespace td {
namespace game {
enum class Direction : std::uint8_t{
PositiveX = 1 << 0,
NegativeX = 1 << 1,
PositiveY = 1 << 2,
NegativeY = 1 << 3,
};
enum class EffectType : std::uint8_t{
Slowness = 0,
Stun,
Fire,
Poison,
Heal,
};
enum class MobType : std::uint8_t{
Zombie = 0,
Spider,
Skeleton,
Pigman,
Creeper,
Silverfish,
Blaze,
Witch,
Slime,
Giant
};
typedef std::uint8_t PlayerID;
typedef std::uint32_t MobID;
typedef std::uint8_t MobLevel;
typedef std::vector<TowerType> TowerImmunities;
typedef std::vector<EffectType> EffectImmunities;
class MobStats{
private:
float m_Damage;
float m_Speed;
std::uint16_t m_MoneyCost;
std::uint16_t m_ExpCost;
std::uint16_t m_MaxLife;
std::uint16_t m_ExpReward;
public:
MobStats(float damage, float speed, std::uint16_t moneyCost,
std::uint16_t expCost, std::uint16_t maxLife,
std::uint16_t expReward): m_Damage(damage), m_Speed(speed),
m_MoneyCost(moneyCost), m_ExpCost(expCost), m_MaxLife(maxLife),
m_ExpReward(expReward){
}
float getDamage() const{ return m_Damage; }
float getMovementSpeed() const{ return m_Speed; }
std::uint16_t getMoneyCost() const{ return m_MoneyCost; }
std::uint16_t getExpCost() const{ return m_ExpCost; }
std::uint16_t getExpReward() const{ return m_ExpReward; }
std::uint16_t getMaxLife() const{ return m_MaxLife; }
};
const MobStats* getMobStats(MobType type, std::uint8_t level);
const TowerImmunities& getMobTowerImmunities(MobType type, std::uint8_t level);
const EffectImmunities& getMobEffectImmunities(MobType type, std::uint8_t level);
class Mob{
protected:
float m_Health;
private:
MobID m_ID;
PlayerID m_Sender;
MobLevel m_Level;
Direction m_Direction;
float m_X = 0, m_Y = 0;
public:
Mob(MobID id, MobLevel level, PlayerID sender): m_Sender(sender), m_Level(level){
}
virtual MobType getType() const = 0;
virtual void tick(std::uint64_t delta){}
const TowerImmunities& getTowerImmunities() const{ return getMobTowerImmunities(getType(), m_Level); }
const EffectImmunities& getEffectImmunities() const{ return getMobEffectImmunities(getType(), m_Level); }
PlayerID getSender() const{ return m_Sender; }
MobLevel getLevel() const{ return m_Level; }
const MobStats* getStats() const{ return getMobStats(getType(), m_Level); }
float getHealth() const{ return m_Health; }
bool isAlive() const{ return m_Health > 0; }
void damage(float dmg){ m_Health -= dmg; }
void heal(float heal){ m_Health = std::min((float)getStats()->getMaxLife(), m_Health + heal); }
float getX() const{ return m_X; }
float setX(float x){ m_X = x; }
float getY() const{ return m_Y; }
float setY(float y){ m_Y = y; }
Direction getDirection() const{ return m_Direction; }
void setDirection(Direction dir){ m_Direction = dir; }
protected:
void initHealth(){m_Health = (float)getStats()->getMaxLife();}
};
typedef std::shared_ptr<Mob> MobPtr;
class Zombie : public Mob{
public:
Zombie(MobID id, std::uint8_t level, PlayerID sender): Mob(id, level, sender){initHealth();}
virtual MobType getType() const{ return MobType::Zombie; }
};
class Spider : public Mob{
public:
Spider(MobID id, std::uint8_t level, PlayerID sender): Mob(id, level, sender){initHealth();}
virtual MobType getType() const{ return MobType::Spider; }
};
namespace MobFactory{
MobPtr createMob(MobID id, MobType type, std::uint8_t level, PlayerID sender);
}
} // namespace game
} // namespace td

40
include/game/Player.h Normal file
View File

@@ -0,0 +1,40 @@
#pragma once
#include <cstdint>
#include <string>
#include "game/Team.h"
namespace td{
namespace game{
class Player{
private:
game::TeamColor m_TeamColor = game::TeamColor::None;
std::uint32_t m_Gold = 0;
std::int32_t m_EXP;
std::string m_Name;
std::uint8_t m_ID;
std::uint8_t m_GoldPerSecond = 5;
public:
Player(std::uint8_t id = 0) : m_ID(id){}
const std::string& getName() const{return m_Name;}
void setName(const std::string& name){m_Name = name;}
game::TeamColor getTeamColor() const{return m_TeamColor;}
void setTeamColor(game::TeamColor teamColor){m_TeamColor = teamColor;}
std::uint8_t getGoldPerSecond() const{ return m_GoldPerSecond;}
void setGoldPerSecond(std::uint8_t goldPerSecond){m_GoldPerSecond = goldPerSecond;}
std::uint32_t getGold() const{ return m_Gold;}
void setGold(std::uint32_t gold){m_Gold = gold;}
std::uint8_t getID() const{return m_ID;}
};
} // namespace game
} // namespace td

34
include/game/Team.h Normal file
View File

@@ -0,0 +1,34 @@
#pragma once
#include <vector>
#include <memory>
#include <algorithm>
namespace td {
namespace game {
class Player;
enum class TeamColor : std::int8_t{
None = -1,
Red,
Blue
};
class Team{
private:
std::vector<Player*> m_Players;
TeamColor m_Color;
public:
Team(TeamColor color);
void addPlayer(Player* newPlayer);
void removePlayer(const Player* player);
TeamColor getColor() const;
std::uint8_t getPlayerCount() const;
};
} // namespace game
} // namespace td

212
include/game/Towers.h Normal file
View File

@@ -0,0 +1,212 @@
#pragma once
#include <cstdint>
#include "misc/Time.h"
namespace td {
namespace game {
enum class TowerType : std::uint8_t{
Archer = 0,
Ice,
Sorcerer,
Zeus,
Mage,
Artillery,
Quake,
Poison,
Leach,
Turret,
Necromancer
};
enum class TowerSize : bool{
Little = 0, // 3x3
Big, // 5x5
};
enum class TowerPath : std::uint8_t{
Top = 1, // Base path
Bottom
};
class TowerStats{
private:
float m_Rate;
float m_Damage;
std::uint8_t m_Range;
public:
TowerStats(float rate, float damage, std::uint8_t range): m_Rate(rate), m_Damage(damage),
m_Range(range){
}
float getDamageRate() const{ return m_Rate; }
float getDamage() const{ return m_Damage; }
std::uint8_t getRange() const{ return m_Range; }
};
class TowerLevel{
private:
// 1, 2, 3, 4
std::uint8_t m_Level : 3;
// 0 : base path 1 : top path (if there is bottom path) 2 : bottom path (if there is top path)
TowerPath m_Path : 1;
public:
TowerLevel(): m_Level(1), m_Path(TowerPath::Top){}
TowerLevel(std::uint8_t level, TowerPath path): m_Level(level), m_Path(path){}
std::uint8_t getLevel() const{ return m_Level; }
TowerPath getPath() const{ return m_Path; }
void setLevel(std::uint8_t level){ m_Level = level; }
void setPath(TowerPath path){ m_Path = path; }
// operator to sort maps
friend bool operator<(const TowerLevel& level, const TowerLevel& other){
return level.getLevel() * (std::uint8_t)level.getPath() <
other.getLevel() * (std::uint8_t)other.getPath();
}
};
const TowerStats* getTowerStats(TowerType type, TowerLevel level);
class Tower{
private:
std::uint16_t m_X, m_Y;
TowerLevel m_Level{};
protected:
utils::Timer m_Timer;
public: // converting seconds to millis
Tower(std::uint16_t x, std::uint16_t y): m_X(x), m_Y(y), m_Timer(getStats()->getDamageRate() * 1000){}
virtual TowerType getType() const = 0;
virtual TowerSize getSize() const = 0;
virtual void tick(std::uint64_t delta) = 0;
void upgrade(std::uint8_t level, TowerPath path){
m_Level.setLevel(level);
m_Level.setPath(path);
}
std::uint16_t getX() const{ return m_X; }
std::uint16_t getY() const{ return m_Y; }
const TowerLevel& getLevel() const{ return m_Level; }
const TowerStats* getStats() const{ return getTowerStats(getType(), m_Level); }
};
// ---------- Little Towers ----------
class LittleTower : public Tower{
public:
LittleTower(std::uint16_t x, std::uint16_t y): Tower(x, y){}
virtual TowerSize getSize() const{ return TowerSize::Little; }
virtual TowerType getType() const = 0;
virtual void tick(std::uint64_t delta) = 0;
};
class ArcherTower : public LittleTower{
public:
ArcherTower(std::uint16_t x, std::uint16_t y): LittleTower(x, y){}
virtual TowerType getType() const{ return TowerType::Archer; }
virtual void tick(std::uint64_t delta);
};
class IceTower : public LittleTower{
public:
IceTower(std::uint16_t x, std::uint16_t y): LittleTower(x, y){}
virtual TowerType getType() const{ return TowerType::Ice; }
virtual void tick(std::uint64_t delta);
};
class MageTower : public LittleTower{
public:
MageTower(std::uint16_t x, std::uint16_t y): LittleTower(x, y){}
virtual TowerType getType() const{ return TowerType::Mage; }
virtual void tick(std::uint64_t delta);
};
class PoisonTower : public LittleTower{
public:
PoisonTower(std::uint16_t x, std::uint16_t y): LittleTower(x, y){}
virtual TowerType getType() const{ return TowerType::Poison; }
virtual void tick(std::uint64_t delta);
};
class QuakeTower : public LittleTower{
public:
QuakeTower(std::uint16_t x, std::uint16_t y): LittleTower(x, y){}
virtual TowerType getType() const{ return TowerType::Quake; }
virtual void tick(std::uint64_t delta);
};
class ArtilleryTower : public LittleTower{
public:
ArtilleryTower(std::uint16_t x, std::uint16_t y): LittleTower(x, y){}
virtual TowerType getType() const{ return TowerType::Artillery; }
virtual void tick(std::uint64_t delta);
};
class SorcererTower : public LittleTower{
public:
SorcererTower(std::uint16_t x, std::uint16_t y): LittleTower(x, y){}
virtual TowerType getType() const{ return TowerType::Sorcerer; }
virtual void tick(std::uint64_t delta);
};
class ZeusTower : public LittleTower{
public:
ZeusTower(std::uint16_t x, std::uint16_t y): LittleTower(x, y){}
virtual TowerType getType() const{ return TowerType::Zeus; }
virtual void tick(std::uint64_t delta);
};
// ---------- Big Towers ----------
class BigTower : public Tower{
public:
BigTower(std::uint16_t x, std::uint16_t y): Tower(x, y){}
virtual TowerSize getSize() const{ return TowerSize::Big; }
virtual TowerType getType() const = 0;
virtual void tick(std::uint64_t delta) = 0;
};
class TurretTower : public BigTower{
public:
TurretTower(std::uint16_t x, std::uint16_t y): BigTower(x, y){}
virtual TowerType getType() const{ return TowerType::Turret; }
virtual void tick(std::uint64_t delta);
};
class NecromancerTower : public BigTower{
public:
NecromancerTower(std::uint16_t x, std::uint16_t y): BigTower(x, y){}
virtual TowerType getType() const{ return TowerType::Necromancer; }
virtual void tick(std::uint64_t delta);
};
class LeachTower : public BigTower{
public:
LeachTower(std::uint16_t x, std::uint16_t y): BigTower(x, y){}
virtual TowerType getType() const{ return TowerType::Leach; }
virtual void tick(std::uint64_t delta);
};
} // namespace game
} // namespace td

190
include/game/World.h Normal file
View File

@@ -0,0 +1,190 @@
#pragma once
#include <memory>
#include <vector>
#include <map>
#include <unordered_map>
#include "Mobs.h"
#include "Team.h"
namespace td{
namespace game{
typedef std::pair<std::int16_t, std::int16_t> ChunkCoord;
}
}
namespace std{
template <>
struct hash<td::game::ChunkCoord>{
std::size_t operator()(const td::game::ChunkCoord& key) const{
// Compute individual hash values for first,
// second and third and combine them using XOR
// and bit shifting:
return ((std::hash<std::int16_t>()(key.first) ^ (std::hash<std::int16_t>()(key.second) << 1)) >> 1);
}
};
}
namespace td {
namespace protocol {
class WorldBeginDataPacket;
class WorldDataPacket;
}
namespace game {
class Game;
enum class TileType : std::uint8_t{
None = 0,
Tower,
Walk,
Decoration,
/*Heal,
Lava,
Bedrock,
Freeze,
Ice,*/
};
struct Color{
std::uint8_t r, g, b;
};
struct Tile{
virtual TileType getType() const = 0;
};
struct TowerTile : Tile{
std::uint8_t color_palette_ref;
TeamColor team_owner;
virtual TileType getType() const{ return TileType::Tower; }
};
struct WalkableTile : Tile{
Direction direction;
virtual TileType getType() const{ return TileType::Walk; }
};
struct DecorationTile : Tile{
std::uint16_t color_palette_ref;
virtual TileType getType() const{ return TileType::Decoration; }
};
struct Spawn{
Direction direction;
std::int32_t x, y;
};
struct TeamCastle{
std::int32_t x, y;
std::uint16_t life = 1000;
};
typedef std::shared_ptr<Tile> TilePtr;
typedef std::vector<std::uint16_t> ChunkPalette;
typedef std::shared_ptr<WalkableTile> WalkableTilePtr;
typedef std::array<std::uint16_t, 32 * 32> ChunkData;
typedef std::uint32_t TileIndex;
//32 x 32 area
struct Chunk{
enum{ ChunkWidth = 32, ChunkHeight = 32, ChunkSize = ChunkWidth * ChunkHeight };
// stores index of tile palette
ChunkData tiles{0};
ChunkPalette palette;
TileIndex getTileIndex(std::uint16_t tileNumber) const{
TileIndex chunkPaletteIndex = tiles.at(tileNumber);
if(chunkPaletteIndex == 0) // index 0 means empty tile index 1 = first tile
return 0;
return palette.at(chunkPaletteIndex);
}
};
typedef std::shared_ptr<Chunk> ChunkPtr;
typedef std::array<Color, 2> TowerTileColorPalette;
typedef std::vector<TilePtr> TilePalette;
typedef std::vector<MobPtr> MobList;
typedef std::array<Color, 2> SpawnColorPalette;
class World{
protected:
TowerTileColorPalette m_TowerPlacePalette;
Color m_WalkablePalette;
std::vector<Color> m_DecorationPalette;
std::unordered_map<ChunkCoord, ChunkPtr> m_Chunks;
SpawnColorPalette m_SpawnColorPalette;
Spawn m_Spawns[2];
TeamCastle m_Castles[2];
TilePalette m_TilePalette;
MobList m_Mobs;
Game* m_Game;
public:
World(Game* game);
bool loadMap(const protocol::WorldBeginDataPacket* worldHeader);
bool loadMap(const protocol::WorldDataPacket* worldData);
bool loadMapFromFile(const std::string& fileName);
bool saveMap(const std::string& fileName) const;
void tick(std::uint64_t delta);
void spawnMobAt(MobID id, MobType type, std::uint8_t level, PlayerID sender, float x, float y, Direction dir);
TilePtr getTile(std::int32_t x, std::int32_t y);
const TowerTileColorPalette& getTowerTileColorPalette() const{ return m_TowerPlacePalette; }
const Color& getWalkableTileColor() const{ return m_WalkablePalette; }
const std::vector<Color>& getDecorationPalette() const{ return m_DecorationPalette; }
const TilePalette& getTilePalette() const{ return m_TilePalette; }
TilePtr getTilePtr(TileIndex index) const{
if(index == 0)
return nullptr;
return m_TilePalette.at(index - 1);
}
const std::unordered_map<ChunkCoord, ChunkPtr>& getChunks() const{ return m_Chunks; }
const Spawn& getRedSpawn() const{ return m_Spawns[(std::size_t) TeamColor::Red]; }
const Spawn& getBlueSpawn() const{ return m_Spawns[(std::size_t) TeamColor::Blue]; }
const Spawn& getSpawn(TeamColor color) const{ return m_Spawns[(std::size_t) color]; }
const Color& getSpawnColor(TeamColor color) const{ return m_SpawnColorPalette[(std::size_t) color]; }
const SpawnColorPalette& getSpawnColors() const{ return m_SpawnColorPalette; }
const TeamCastle& getRedCastle() const{ return m_Castles[(std::size_t) TeamColor::Red]; }
const TeamCastle& getBlueCastle() const{ return m_Castles[(std::size_t) TeamColor::Blue]; }
const MobList& getMobList() const{ return m_Mobs; }
MobList& getMobList(){ return m_Mobs; }
const Color& getTileColor(TilePtr tile) const;
private:
void moveMobs(std::uint64_t delta);
};
} // namespace game
} // namespace td

View File

@@ -0,0 +1,34 @@
#pragma once
#include "ClientConnexion.h"
#include "ClientGame.h"
#include "game/Team.h"
#include "game/Player.h"
namespace td {
namespace client {
class Client{
private:
ClientConnexion m_Connexion;
ClientGame m_Game{m_Connexion.GetDispatcher()};
bool m_Connected;
public:
Client(){}
const ClientGame& getGame() const{ return m_Game; }
const ClientConnexion& getConnexion() const{ return m_Connexion; }
void tick(std::uint64_t delta);
void connect(const std::string& address, std::uint16_t port);
void closeConnection();
bool isConnected() const{ return m_Connexion.getSocketStatus() == network::Socket::Connected; }
void selectTeam(game::TeamColor team);
};
} // namespace client
} // namespace td

View File

@@ -0,0 +1,37 @@
#pragma once
#include "protocol/PacketHandler.h"
#include "network/TCPSocket.h"
#include "game/Connexion.h"
namespace td {
namespace client {
class ClientConnexion : public protocol::Connexion{
private:
std::uint8_t m_ConnectionID;
std::string m_DisconnectReason;
float m_ServerTPS;
int m_Ping = 0;
public:
ClientConnexion();
virtual bool updateSocket();
virtual void HandlePacket(protocol::KeepAlivePacket* packet);
virtual void HandlePacket(protocol::ConnexionInfoPacket* packet);
virtual void HandlePacket(protocol::DisconnectPacket* packet);
virtual void HandlePacket(protocol::ServerTpsPacket* packet);
const std::string& getDisconnectReason() const{ return m_DisconnectReason; }
float getServerTPS() const{ return m_ServerTPS; }
int getServerPing() const {return m_Ping;}
REMOVE_COPY(ClientConnexion);
private:
void registerHandlers();
void login();
};
} // namespace client
} // namespace td

View File

@@ -0,0 +1,36 @@
#pragma once
#include "game/BaseGame.h"
#include "protocol/PacketHandler.h"
#include "WorldClient.h"
namespace td {
namespace client {
class ClientGame : public protocol::PacketHandler, public game::Game{
private:
std::uint8_t m_ConnexionID;
std::uint32_t m_LobbyTime = 0;
game::Player* m_Player = nullptr;
client::WorldClient m_WorldClient{this};
public:
ClientGame(protocol::PacketDispatcher* dispatcher);
virtual ~ClientGame();
virtual void tick(std::uint64_t delta);
std::uint32_t getLobbyTime() const{return m_LobbyTime;}
const game::Player* getPlayer() const{return m_Player;}
virtual void HandlePacket(protocol::ConnexionInfoPacket* packet);
virtual void HandlePacket(protocol::PlayerJoinPacket* packet);
virtual void HandlePacket(protocol::PlayerLeavePacket* packet);
virtual void HandlePacket(protocol::PlayerListPacket* packet);
virtual void HandlePacket(protocol::UpdatePlayerTeamPacket* packet);
virtual void HandlePacket(protocol::UpdateGameStatePacket* packet);
virtual void HandlePacket(protocol::UpdateLobbyTimePacket* packet);
virtual void HandlePacket(protocol::UpdateMoneyPacket* packet);
};
} // namespace client
} // namespace td

View File

@@ -0,0 +1,23 @@
#pragma once
#include "game/World.h"
#include "protocol/PacketHandler.h"
namespace td {
namespace client {
class ClientGame;
class WorldClient : public game::World, public protocol::PacketHandler{
private:
ClientGame* m_Game;
public:
WorldClient(ClientGame* game);
virtual void HandlePacket(protocol::WorldBeginDataPacket* packet);
virtual void HandlePacket(protocol::WorldDataPacket* packet);
virtual void HandlePacket(protocol::SpawnMobPacket* packet);
};
} // namespace client
} // namespace td

View File

@@ -0,0 +1,31 @@
#pragma once
#include <vector>
#include "misc/Time.h"
namespace td {
namespace server {
class Server;
class Lobby{
private:
Server* m_Server;
bool m_GameStarted = false;
std::uint64_t m_StartTimerTime = 0;
std::vector<std::uint8_t> m_Players;
utils::Timer m_Timer;
public:
Lobby(Server* server);
void OnPlayerJoin(std::uint8_t playerID);
void OnPlayerLeave(std::uint8_t playerID);
void sendTimeRemaining();
void tick();
};
} // namespace server
} // namespace td

View File

@@ -0,0 +1,96 @@
#pragma once
#include <cstdint>
#include <map>
#include "network/TCPListener.h"
#include "protocol/Protocol.h"
#include "protocol/PacketDispatcher.h"
#include "protocol/PacketHandler.h"
#include "ServerGame.h"
#include "ServerConnexion.h"
#include "Lobby.h"
//#define LOBBY_WAITING_TIME 2 * 60 * 1000
#define LOBBY_WAITING_TIME 5 * 1000
#define SERVER_TPS 20
#define SERVER_TICK 1000 / SERVER_TPS
namespace td {
namespace server {
typedef std::map<std::uint8_t, ServerConnexion> ConnexionMap;
class TickCounter{
private:
float m_TPS;
std::uint64_t m_LastTPSTime;
std::uint8_t m_TickCount;
public:
TickCounter(){}
void reset(){
m_TPS = SERVER_TPS;
m_LastTPSTime = utils::getTime();
m_TickCount = 0;
}
bool update(){ // return true when tps is updated
m_TickCount++;
if (m_TickCount >= SERVER_TPS){
std::uint64_t timeElapsedSinceLast20Ticks = td::utils::getTime() - m_LastTPSTime;
m_TPS = (float)SERVER_TPS / (float)(timeElapsedSinceLast20Ticks / 1000.0f);
m_TickCount = 0;
m_LastTPSTime = td::utils::getTime();
return true;
}
return false;
}
float getTPS() const{ return m_TPS; }
};
class Server{
private:
network::TCPListener m_Listener;
ConnexionMap m_Connections;
ServerGame m_Game{this};
Lobby m_Lobby{this};
TickCounter m_TickCounter;
public:
Server(const std::string& worldFilePath);
virtual ~Server(){}
bool start(std::uint16_t port);
void tick(std::uint64_t delta);
void stop();
void lauchGame();
void removeConnexion(std::uint8_t connexionID);
void broadcastPacket(protocol::Packet* packet);
float getTPS() const{ return m_TickCounter.getTPS(); }
const ServerGame& getGame() const{ return m_Game; }
ServerGame& getGame() { return m_Game; }
const Lobby& getLobby() const{ return m_Lobby; }
const ConnexionMap& getConnexions() const{ return m_Connections; }
ConnexionMap& getConnexions(){ return m_Connections; }
const game::PlayerList& getPlayers() const{ return m_Game.getPlayers(); }
game::PlayerList& getPlayers(){ return m_Game.getPlayers(); }
private:
void accept();
void updateSockets();
void OnPlayerJoin(std::uint8_t id);
void OnPlayerLeave(std::uint8_t id);
};
} // namespace server
} // namespace td

View File

@@ -0,0 +1,56 @@
#pragma once
#include "network/TCPSocket.h"
#include "protocol/PacketHandler.h"
#include "protocol/PacketDispatcher.h"
#include "game/Player.h"
#include "game/Connexion.h"
namespace td{
namespace server{
class Server;
struct KeepAlive
{
std::uint64_t keepAliveID = 0;
std::uint64_t sendTime;
bool recievedResponse = false;
};
class ServerConnexion : public protocol::Connexion{
private:
Server* m_Server = nullptr;
std::uint8_t m_ID;
KeepAlive m_KeepAlive;
game::Player* m_Player;
public:
ServerConnexion();
ServerConnexion(network::TCPSocket& socket, std::uint8_t id);
ServerConnexion(ServerConnexion&& move);
virtual ~ServerConnexion();
void setServer(Server* server);
virtual void HandlePacket(protocol::PlayerLoginPacket* packet);
virtual void HandlePacket(protocol::KeepAlivePacket* packet);
virtual void HandlePacket(protocol::SelectTeamPacket* packet);
virtual void HandlePacket(protocol::DisconnectPacket* packet);
std::uint8_t getID() const{return m_ID;}
const game::Player* getPlayer() const{return m_Player;}
game::Player* getPlayer() {return m_Player;}
virtual bool updateSocket();
REMOVE_COPY(ServerConnexion);
private:
void registerHandlers();
void checkKeepAlive();
void sendKeepAlive();
void initConnection();
};
} // namespace server
} // namespace td

View File

@@ -0,0 +1,29 @@
#pragma once
#include "game/BaseGame.h"
#include "misc/Time.h"
#include "ServerWorld.h"
namespace td {
namespace server {
class Server;
class ServerGame : public game::Game{
private:
Server* m_Server;
ServerWorld m_ServerWorld;
utils::Timer m_GoldMineTimer{1000, std::bind(&ServerGame::updateGoldMines, this)};
public:
ServerGame(Server* server);
~ServerGame(){}
virtual void tick(std::uint64_t delta);
void startGame();
private:
void balanceTeams();
void updateGoldMines();
};
} // namespace game
} // namespace td

View File

@@ -0,0 +1,21 @@
#pragma once
#include "game/World.h"
namespace td {
namespace server {
class Server;
class ServerGame;
class ServerWorld : public game::World{
private:
game::MobID m_CurrentMobID = 0;
Server* m_Server;
public:
ServerWorld(Server* server, ServerGame* game);
void spawnMobs(game::MobType type, std::uint8_t level, game::PlayerID sender, std::uint8_t count);
};
} // namespace server
} // namespace td

View File

@@ -0,0 +1,14 @@
#pragma once
#include <cstdint>
#include "network/DataBuffer.h"
namespace td {
namespace utils {
DataBuffer Compress(const DataBuffer& buffer);
DataBuffer Decompress(DataBuffer& buffer);
DataBuffer Decompress(DataBuffer& buffer, std::size_t packetLength);
} // namespace utils
} // namespace td

12
include/misc/Random.h Normal file
View File

@@ -0,0 +1,12 @@
#pragma once
#include <cstdint>
namespace td {
namespace utils {
void initRandomizer();
std::uint64_t getRandomNumber(std::size_t max);
} // namespace utils
} // namespace td

41
include/misc/Time.h Normal file
View File

@@ -0,0 +1,41 @@
#pragma once
#include <cstdint>
#include <functional>
namespace td {
namespace utils {
std::uint64_t getTime();
typedef std::function<void()> TimerExecFunction;
// utililty class to call function at regular period of time
class Timer{
private:
std::uint64_t m_Interval;
TimerExecFunction m_Function;
std::uint64_t m_LastTime = getTime();
std::uint64_t m_InternalTime = 0;
public:
Timer() : m_Interval(0), m_Function(nullptr){}
Timer(std::uint64_t interval) : m_Interval(interval), m_Function(nullptr){}
Timer(std::uint64_t interval, TimerExecFunction callback) : m_Interval(interval), m_Function(callback){}
void update();
void update(std::uint64_t delta);
void reset();
void setInterval(std::uint64_t newInterval){m_Interval = newInterval;}
std::uint64_t getInterval() const{return m_Interval;}
void setCallbackFunction(TimerExecFunction newCallback){m_Function = newCallback;}
TimerExecFunction getCallbackFunction() const{return m_Function;}
};
} // namespace utils
} // namespace td

View File

@@ -0,0 +1,167 @@
#ifndef MCLIB_COMMON_DATA_BUFFER_H_
#define MCLIB_COMMON_DATA_BUFFER_H_
#include <vector>
#include <algorithm>
#include <cstring>
#include <cassert>
#include <string>
namespace td{
class DataBuffer{
private:
typedef std::vector<std::uint8_t> Data;
Data m_Buffer;
std::size_t m_ReadOffset = 0;
public:
typedef Data::iterator iterator;
typedef Data::const_iterator const_iterator;
typedef Data::reference reference;
typedef Data::const_reference const_reference;
DataBuffer();
DataBuffer(const DataBuffer& other);
DataBuffer(const DataBuffer& other, std::size_t offset);
DataBuffer(DataBuffer&& other);
DataBuffer(const std::string& str);
DataBuffer& operator=(const DataBuffer& other);
DataBuffer& operator=(DataBuffer&& other);
template <typename T>
void Append(T data){
std::size_t size = sizeof(data);
std::size_t end_pos = m_Buffer.size();
m_Buffer.resize(m_Buffer.size() + size);
memcpy(&m_Buffer[end_pos], &data, size);
}
template <typename T>
DataBuffer& operator<<(T data){
// Switch to big endian
//std::reverse((std::uint8_t*)&data, (std::uint8_t*)&data + sizeof(T));
Append(data);
return *this;
}
DataBuffer& operator<<(std::string str){
m_Buffer.insert(m_Buffer.end(), str.begin(), str.end());
return *this;
}
DataBuffer& operator<<(DataBuffer& data){
m_Buffer.insert(m_Buffer.end(), data.begin(), data.end());
return *this;
}
DataBuffer& operator<<(const DataBuffer& data){
m_Buffer.insert(m_Buffer.end(), data.begin(), data.end());
return *this;
}
template <typename T>
DataBuffer& operator>>(T& data){
assert(m_ReadOffset + sizeof(T) <= GetSize());
data = *(T*)&m_Buffer[m_ReadOffset];
//std::reverse((std::uint8_t*)&data, (std::uint8_t*)&data + sizeof(T));
m_ReadOffset += sizeof(T);
return *this;
}
DataBuffer& operator>>(DataBuffer& data){
data.Resize(GetSize() - m_ReadOffset);
std::copy(m_Buffer.begin() + m_ReadOffset, m_Buffer.end(), data.begin());
m_ReadOffset = m_Buffer.size();
return *this;
}
DataBuffer& operator>>(std::string& str){
std::size_t stringSize = strlen((const char*) m_Buffer.data() + m_ReadOffset) + 1; // including null character
str.resize(stringSize);
std::copy(m_Buffer.begin() + m_ReadOffset, m_Buffer.begin() + m_ReadOffset + stringSize, str.begin());
m_ReadOffset += stringSize;
return *this;
}
void ReadSome(char* buffer, std::size_t amount){
assert(m_ReadOffset + amount <= GetSize());
std::copy_n(m_Buffer.begin() + m_ReadOffset, amount, buffer);
m_ReadOffset += amount;
}
void ReadSome(std::uint8_t* buffer, std::size_t amount){
assert(m_ReadOffset + amount <= GetSize());
std::copy_n(m_Buffer.begin() + m_ReadOffset, amount, buffer);
m_ReadOffset += amount;
}
void ReadSome(DataBuffer& buffer, std::size_t amount){
assert(m_ReadOffset + amount <= GetSize());
buffer.Resize(amount);
std::copy_n(m_Buffer.begin() + m_ReadOffset, amount, buffer.begin());
m_ReadOffset += amount;
}
void ReadSome(std::string& buffer, std::size_t amount){
assert(m_ReadOffset + amount <= GetSize());
buffer.resize(amount);
std::copy_n(m_Buffer.begin() + m_ReadOffset, amount, buffer.begin());
m_ReadOffset += amount;
}
void Resize(std::size_t size){
m_Buffer.resize(size);
}
void Reserve(std::size_t amount){
m_Buffer.reserve(amount);
}
void erase(iterator it){
m_Buffer.erase(it);
}
void Clear(){
m_Buffer.clear();
m_ReadOffset = 0;
}
bool IsFinished() const{
return m_ReadOffset >= m_Buffer.size();
}
std::uint8_t* data(){
return m_Buffer.data();
}
const std::uint8_t* data() const{
return m_Buffer.data();
}
std::size_t GetReadOffset() const{ return m_ReadOffset; }
void SetReadOffset(std::size_t pos);
std::string ToString() const;
std::size_t GetSize() const;
bool IsEmpty() const;
std::size_t GetRemaining() const;
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
reference operator[](Data::size_type i){ return m_Buffer[i]; }
const_reference operator[](Data::size_type i) const{ return m_Buffer[i]; }
bool ReadFile(const std::string& fileName);
bool WriteFile(const std::string& fileName);
};
std::ostream& operator<<(std::ostream& os, const DataBuffer& buffer);
} // ns td
#endif

View File

@@ -0,0 +1,56 @@
#ifndef NETWORK_IPADDRESS_H_
#define NETWORK_IPADDRESS_H_
#include <string>
#include <iosfwd>
#include <vector>
namespace td {
namespace network {
/* IPv4 address */
class IPAddress {
private:
std::uint32_t m_Address;
bool m_Valid;
public:
/* Create an invalid address */
IPAddress() noexcept;
/* Initialize by string IP */
IPAddress(const std::string& str);
/* Initialize by string IP */
IPAddress(const std::wstring& str);
/* Initialize by octets */
IPAddress(std::uint8_t octet1, std::uint8_t octet2, std::uint8_t octet3, std::uint8_t octet4) noexcept;
/* Get the specific octet. 1-4 */
std::uint8_t GetOctet(std::uint8_t num) const;
/* Set the specific octet. 1-4 */
void SetOctet(std::uint8_t num, std::uint8_t value);
/* Make sure the IP is valid. It will be invalid if the host wasn't found. */
bool IsValid() const noexcept { return m_Valid; }
std::string ToString() const;
static IPAddress LocalAddress();
bool operator==(const IPAddress& right);
bool operator!=(const IPAddress& right);
bool operator==(bool b);
};
typedef std::vector<IPAddress> IPAddresses;
std::ostream& operator<<(std::ostream& os, const IPAddress& addr);
std::wostream& operator<<(std::wostream& os, const IPAddress& addr);
} // ns network
} // ns td
#endif

32
include/network/Network.h Normal file
View File

@@ -0,0 +1,32 @@
#ifndef NETWORK_NETWORK_H_
#define NETWORK_NETWORK_H_
#ifdef _WIN32
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#endif
#include "network/Socket.h"
#include "network/IPAddress.h"
#include "network/UDPSocket.h"
#include "network/TCPSocket.h"
namespace td {
namespace network {
class Dns {
public:
static IPAddresses Resolve(const std::string& host);
};
} // ns network
} // ns td
#endif

90
include/network/Socket.h Normal file
View File

@@ -0,0 +1,90 @@
#ifndef NETWORK_SOCKET_H_
#define NETWORK_SOCKET_H_
#include <string>
#include <vector>
#include <memory>
#include "network/DataBuffer.h"
#ifdef _WIN32
#include <ws2tcpip.h>
#include <winsock2.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/ioctl.h>
#define closesocket close
#endif
#ifndef INVALID_SOCKET
#define INVALID_SOCKET -1
#endif
#define REMOVE_COPY(className) \
className(const className &) = delete;\
className& operator=(const className &) = delete
namespace td {
namespace network {
class IPAddress;
typedef int SocketHandle;
class Socket {
public:
enum Status { Connected, Disconnected, Error };
enum Type { TCP, UDP };
private:
bool m_Blocking;
Type m_Type;
Status m_Status;
protected:
SocketHandle m_Handle;
Socket(Type type);
void SetStatus(Status status);
public:
virtual ~Socket();
Socket(Socket&& rhs) = default;
Socket& operator=(Socket&& rhs) = default;
bool SetBlocking(bool block);
bool IsBlocking() const noexcept;
Type GetType() const noexcept;
Status GetStatus() const noexcept;
SocketHandle GetHandle() const noexcept;
bool Connect(const std::string& ip, std::uint16_t port);
virtual bool Connect(const IPAddress& address, std::uint16_t port) = 0;
void Disconnect();
std::size_t Send(const std::string& data);
std::size_t Send(DataBuffer& buffer);
virtual std::size_t Send(const uint8_t* data, std::size_t size) = 0;
virtual DataBuffer Receive(std::size_t amount) = 0;
virtual std::size_t Receive(DataBuffer& buffer, std::size_t amount) = 0;
};
typedef std::shared_ptr<Socket> SocketPtr;
} // ns network
} // ns td
#endif

View File

@@ -0,0 +1,34 @@
#pragma once
#include "TCPSocket.h"
namespace td{
namespace network{
class TCPListener{
int m_Handle;
std::uint16_t m_Port;
int m_MaxConnections;
public:
TCPListener();
~TCPListener();
bool listen(std::uint16_t port, int maxConnections);
bool accept(TCPSocket& newSocket);
void destroy();
bool close();
bool setBlocking(bool blocking);
std::uint16_t getListeningPort() const{
return m_Port;
}
int getMaximumConnections() const{
return m_MaxConnections;
}
REMOVE_COPY(TCPListener);
};
} // namespace network
} // namespace td

View File

@@ -0,0 +1,39 @@
#ifndef NETWORK_TCP_SOCKET_H_
#define NETWORK_TCP_SOCKET_H_
#include "network/IPAddress.h"
#include "network/Socket.h"
#include <cstdint>
namespace td {
namespace network {
class TCPListener;
class TCPSocket : public Socket {
private:
IPAddress m_RemoteIP;
uint16_t m_Port;
sockaddr_in m_RemoteAddr;
public:
TCPSocket();
TCPSocket(TCPSocket&& other);
virtual bool Connect(const IPAddress& address, std::uint16_t port);
virtual std::size_t Send(const std::uint8_t* data, std::size_t size);
virtual DataBuffer Receive(std::size_t amount);
virtual std::size_t Receive(DataBuffer& buffer, std::size_t amount);
REMOVE_COPY(TCPSocket);
friend class TCPListener;
};
void SendPacket(const DataBuffer& data, network::TCPSocket& socket);
} // ns network
} // ns td
#endif

View File

@@ -0,0 +1,29 @@
#ifndef NETWORK_UDP_SOCKET_H_
#define NETWORK_UDP_SOCKET_H_
#include "network/IPAddress.h"
#include "network/Socket.h"
#include <cstdint>
namespace td {
namespace network {
class UDPSocket : public Socket {
private:
IPAddress m_RemoteIP;
uint16_t m_Port;
sockaddr_in m_RemoteAddr;
public:
UDPSocket();
bool Connect(const IPAddress& address, std::uint16_t port);
std::size_t Send(const std::uint8_t* data, std::size_t size);
DataBuffer Receive(std::size_t amount);
};
} // ns network
} // ns td
#endif

View File

@@ -0,0 +1,33 @@
#pragma once
#include "protocol/Protocol.h"
#include <map>
#include <vector>
namespace td {
namespace protocol {
class PacketHandler;
class PacketDispatcher {
private:
std::map<PacketType, std::vector<PacketHandler*>> m_Handlers;
public:
PacketDispatcher() = default;
PacketDispatcher(const PacketDispatcher& rhs) = delete;
PacketDispatcher& operator=(const PacketDispatcher& rhs) = delete;
PacketDispatcher(PacketDispatcher&& rhs) = delete;
PacketDispatcher& operator=(PacketDispatcher&& rhs) = delete;
void Dispatch(Packet* packet);
void RegisterHandler(PacketType type, PacketHandler* handler);
void UnregisterHandler(PacketType type, PacketHandler* handler);
void UnregisterHandler(PacketHandler* handler);
};
} // namespace protocol
} // namespace td

View File

@@ -0,0 +1,13 @@
#pragma once
#include "protocol/Protocol.h"
namespace td {
namespace protocol {
namespace PacketFactory {
Packet* createPacket(PacketType type, DataBuffer& buffer);
}
} // namespace protocol
} // namespace td

View File

@@ -0,0 +1,39 @@
#pragma once
#include "protocol/Protocol.h"
namespace td {
namespace protocol {
class PacketDispatcher;
class PacketHandler{
private:
PacketDispatcher* m_Dispatcher;
public:
PacketHandler(PacketDispatcher* dispatcher) : m_Dispatcher(dispatcher){}
virtual ~PacketHandler(){}
PacketDispatcher* GetDispatcher(){return m_Dispatcher;}
virtual void HandlePacket(PlayerLoginPacket* packet){}
virtual void HandlePacket(WorldBeginDataPacket* packet){}
virtual void HandlePacket(WorldDataPacket* packet){}
virtual void HandlePacket(KeepAlivePacket* packet){}
virtual void HandlePacket(UpdateMoneyPacket* packet){}
virtual void HandlePacket(UpdateExpPacket* packet){}
virtual void HandlePacket(UpdateLobbyTimePacket* packet){}
virtual void HandlePacket(UpdateGameStatePacket* packet){}
virtual void HandlePacket(PlayerListPacket* packet){}
virtual void HandlePacket(PlayerJoinPacket* packet){}
virtual void HandlePacket(PlayerLeavePacket* packet){}
virtual void HandlePacket(ConnexionInfoPacket* packet){}
virtual void HandlePacket(SelectTeamPacket* packet){}
virtual void HandlePacket(UpdatePlayerTeamPacket* packet){}
virtual void HandlePacket(DisconnectPacket* packet){}
virtual void HandlePacket(ServerTpsPacket* packet){}
virtual void HandlePacket(SpawnMobPacket* packet){}
};
} // namespace protocol
} // namespace td

384
include/protocol/Protocol.h Normal file
View File

@@ -0,0 +1,384 @@
#pragma once
#include "network/DataBuffer.h"
#include "game/World.h"
#include "game/BaseGame.h"
namespace td {
namespace protocol {
class PacketHandler;
enum class PacketType : std::uint8_t{
PlayerLogin = 0,
PlayerJoin,
PlayerLeave,
WorldBeginData,
WorldData,
ChunkData,
KeepAlive,
UpdateMoney,
UpdateEXP,
UpdateLobbyTime,
UpdateGameState,
Disconnect,
PlayerList,
ConnectionInfo,
SelectTeam,
UpdatePlayerTeam,
ServerTps,
SpawnMob,
};
class Packet{
public:
Packet(){}
virtual ~Packet(){}
virtual DataBuffer Serialize() const = 0;
virtual void Deserialize(DataBuffer& data) = 0;
virtual void Dispatch(PacketHandler* handler) = 0;
virtual PacketType getType() const = 0;
std::uint8_t getID() const{ return (std::uint8_t)getType(); }
};
class KeepAlivePacket : public Packet{
private:
std::uint64_t m_AliveID;
public:
KeepAlivePacket(){}
KeepAlivePacket(std::uint64_t aliveID): m_AliveID(aliveID){}
virtual ~KeepAlivePacket(){}
virtual DataBuffer Serialize() const;
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler);
std::uint64_t getAliveID(){ return m_AliveID; }
virtual PacketType getType() const{ return PacketType::KeepAlive; }
};
class PlayerLoginPacket : public Packet{
private:
std::string m_PlayerName;
public:
PlayerLoginPacket(){}
PlayerLoginPacket(std::string playerName): m_PlayerName(playerName){}
virtual ~PlayerLoginPacket(){}
virtual DataBuffer Serialize() const;
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler);
virtual PacketType getType() const{ return PacketType::PlayerLogin; }
const std::string& getPlayerName(){ return m_PlayerName; }
};
class WorldBeginDataPacket : public Packet{
private:
game::TowerTileColorPalette m_TowerPlacePalette;
game::Color m_WalkablePalette;
std::vector<game::Color> m_DecorationPalette;
game::SpawnColorPalette m_SpawnColorPalette;
game::TilePalette m_TilePalette;
game::Spawn m_RedSpawn, m_BlueSpawn;
game::TeamCastle m_RedTower, m_BlueTower;
const game::World* m_World;
public:
WorldBeginDataPacket(){}
WorldBeginDataPacket(const game::World* world): m_World(world){}
virtual ~WorldBeginDataPacket(){}
virtual DataBuffer Serialize() const;
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler);
virtual PacketType getType() const{ return PacketType::WorldBeginData; }
const game::TowerTileColorPalette& getTowerTilePalette() const{ return m_TowerPlacePalette; }
const game::Color& getWalkableTileColor() const{ return m_WalkablePalette; }
const std::vector<game::Color>& getDecorationPalette() const{ return m_DecorationPalette; }
const game::Spawn& getRedSpawn() const{ return m_RedSpawn; }
const game::Spawn& getBlueSpawn() const{ return m_BlueSpawn; }
const game::SpawnColorPalette& getSpawnPalette() const{ return m_SpawnColorPalette; }
const game::TeamCastle& getRedCastle() const{ return m_RedTower; }
const game::TeamCastle& getBlueCastle() const{ return m_BlueTower; }
const game::TilePalette getTilePalette() const{ return m_TilePalette; }
};
class WorldDataPacket : public Packet{
private:
std::unordered_map<game::ChunkCoord, game::ChunkPtr> m_Chunks;
const game::World* m_World;
public:
WorldDataPacket(){}
WorldDataPacket(const game::World* world): m_World(world){}
virtual ~WorldDataPacket(){}
virtual DataBuffer Serialize() const;
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler);
virtual PacketType getType() const{ return PacketType::WorldData; }
const std::unordered_map<game::ChunkCoord, game::ChunkPtr>& getChunks() const{ return m_Chunks; }
};
class UpdateMoneyPacket : public Packet{
private:
std::uint32_t m_NewAmount;
public:
UpdateMoneyPacket(){}
UpdateMoneyPacket(std::uint32_t newAmount): m_NewAmount(newAmount){}
virtual ~UpdateMoneyPacket(){}
std::uint32_t getGold() const{ return m_NewAmount; }
virtual DataBuffer Serialize() const;
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler);
virtual PacketType getType() const{ return PacketType::UpdateMoney; }
};
class UpdateExpPacket : public Packet{
private:
std::uint32_t m_NewAmount;
public:
UpdateExpPacket(){}
UpdateExpPacket(std::uint32_t newAmount): m_NewAmount(newAmount){}
virtual ~UpdateExpPacket(){}
virtual DataBuffer Serialize() const;
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler);
virtual PacketType getType() const{ return PacketType::UpdateEXP; }
};
class UpdateLobbyTimePacket : public Packet{
private:
std::uint32_t m_RemainingTime;
public:
UpdateLobbyTimePacket(){}
UpdateLobbyTimePacket(std::uint32_t remainingTime): m_RemainingTime(remainingTime){}
virtual ~UpdateLobbyTimePacket(){}
virtual DataBuffer Serialize() const;
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler);
std::uint32_t getRemainingTime() const{ return m_RemainingTime; }
virtual PacketType getType() const{ return PacketType::UpdateLobbyTime; }
};
class UpdateGameStatePacket : public Packet{
private:
game::GameState m_GameState;
public:
UpdateGameStatePacket(){}
UpdateGameStatePacket(game::GameState gameState): m_GameState(gameState){}
virtual ~UpdateGameStatePacket(){}
virtual DataBuffer Serialize() const;
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler);
game::GameState getGameState() const{ return m_GameState; }
virtual PacketType getType() const{ return PacketType::UpdateGameState; }
};
struct PlayerInfo{
std::string name;
game::TeamColor team;
};
class PlayerListPacket : public Packet{
private:
std::map<std::uint8_t, PlayerInfo> m_Players;
public:
PlayerListPacket(){}
PlayerListPacket(std::map<std::uint8_t, PlayerInfo> players): m_Players(players){}
virtual ~PlayerListPacket(){}
virtual DataBuffer Serialize() const;
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler);
const std::map<std::uint8_t, PlayerInfo>& getPlayers() const{ return m_Players; }
virtual PacketType getType() const{ return PacketType::PlayerList; }
};
class PlayerJoinPacket : public Packet{
private:
std::uint8_t m_PlayerID;
std::string m_PlayerName;
public:
PlayerJoinPacket(){}
PlayerJoinPacket(std::uint8_t playerID, const std::string& playerName): m_PlayerID(playerID), m_PlayerName(playerName){}
virtual ~PlayerJoinPacket(){}
virtual DataBuffer Serialize() const;
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler);
std::uint8_t getPlayerID() const{ return m_PlayerID; }
const std::string& getPlayerName() const{ return m_PlayerName; }
virtual PacketType getType() const{ return PacketType::PlayerJoin; }
};
class PlayerLeavePacket : public Packet{
private:
std::uint8_t m_PlayerID;
public:
PlayerLeavePacket(){}
PlayerLeavePacket(std::uint8_t playerID): m_PlayerID(playerID){}
virtual ~PlayerLeavePacket(){}
virtual DataBuffer Serialize() const;
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler);
std::uint8_t getPlayerID() const{ return m_PlayerID; }
virtual PacketType getType() const{ return PacketType::PlayerLeave; }
};
class ConnexionInfoPacket : public Packet{
private:
std::uint8_t m_ConnectionID;
public:
ConnexionInfoPacket(){}
ConnexionInfoPacket(std::uint8_t connectionID): m_ConnectionID(connectionID){}
virtual ~ConnexionInfoPacket(){}
virtual DataBuffer Serialize() const;
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler);
std::uint8_t getConnectionID() const{ return m_ConnectionID; }
virtual PacketType getType() const{ return PacketType::ConnectionInfo; }
};
class SelectTeamPacket : public Packet{
private:
game::TeamColor m_SelectedTeam;
public:
SelectTeamPacket(){}
SelectTeamPacket(game::TeamColor selectedTeam): m_SelectedTeam(selectedTeam){}
virtual ~SelectTeamPacket(){}
virtual DataBuffer Serialize() const;
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler);
game::TeamColor getSelectedTeam() const{ return m_SelectedTeam; }
virtual PacketType getType() const{ return PacketType::SelectTeam; }
};
class UpdatePlayerTeamPacket : public Packet{
private:
std::uint8_t m_PlayerID;
game::TeamColor m_SelectedTeam;
public:
UpdatePlayerTeamPacket(){}
UpdatePlayerTeamPacket(std::uint8_t playerID, game::TeamColor selectedTeam): m_PlayerID(playerID), m_SelectedTeam(selectedTeam){}
virtual ~UpdatePlayerTeamPacket(){}
virtual DataBuffer Serialize() const;
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler);
game::TeamColor getSelectedTeam() const{ return m_SelectedTeam; }
std::uint8_t getPlayerID() const{ return m_PlayerID; }
virtual PacketType getType() const{ return PacketType::UpdatePlayerTeam; }
};
class DisconnectPacket : public Packet{
private:
std::string m_Reason; // only when sent from server
public:
DisconnectPacket(){}
DisconnectPacket(std::string reason): m_Reason(reason){}
virtual ~DisconnectPacket(){}
virtual DataBuffer Serialize() const;
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler);
const std::string& getReason() const{ return m_Reason; }
virtual PacketType getType() const{ return PacketType::Disconnect; }
};
class ServerTpsPacket : public Packet{
private:
float m_TPS;
std::uint64_t m_PacketSendTime; // used to calculate ping
public:
ServerTpsPacket(){}
ServerTpsPacket(float tps, std::uint64_t sendTime): m_TPS(tps), m_PacketSendTime(sendTime){}
virtual ~ServerTpsPacket(){}
virtual DataBuffer Serialize() const;
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler);
float getTPS() const{ return m_TPS; }
std::uint64_t getPacketSendTime() const {return m_PacketSendTime;}
virtual PacketType getType() const{ return PacketType::ServerTps; }
};
class SpawnMobPacket : public Packet{
private:
game::MobID m_MobID;
game::MobType m_MobType;
game::MobLevel m_MobLevel;
game::Direction m_MobDirection;
game::PlayerID m_Sender;
float m_MobX, m_MobY;
public:
SpawnMobPacket(){}
SpawnMobPacket(game::MobID id, game::MobType type, std::uint8_t level, game::PlayerID sender,
float x, float y, game::Direction dir) : m_MobID(id), m_MobType(type), m_MobLevel(level),
m_MobDirection(dir), m_Sender(sender), m_MobX(x), m_MobY(y){}
virtual ~SpawnMobPacket(){}
virtual DataBuffer Serialize() const;
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler);
game::MobID getMobID() const{ return m_MobID; }
game::MobType getMobType() const{ return m_MobType; }
game::MobLevel getMobLevel() const{ return m_MobLevel; }
game::Direction getMobDirection() const{ return m_MobDirection; }
game::PlayerID getSender() const{ return m_Sender; }
float getMobX() const{ return m_MobX; }
float getMobY() const{ return m_MobY; }
virtual PacketType getType() const{ return PacketType::SpawnMob; }
};
}
}

44
include/render/Renderer.h Normal file
View File

@@ -0,0 +1,44 @@
/*
* Renderer.h
*
* Created on: 4 nov. 2020
* Author: simon
*/
#ifndef RENDER_RENDERER_H_
#define RENDER_RENDERER_H_
#include <glm/glm.hpp>
#include "loader/GLLoader.h"
namespace td {
namespace render{
namespace Renderer{
struct Model{
GL::VAO* vao;
glm::vec2 positon;
};
bool init();
void destroy();
void prepare();
void resize(const int width, const int height);
void renderVAO(const GL::VAO& vao);
void renderModel(const Model& model);
void setZoom(float zoom);
void setCamMovement(const glm::vec2& mov);
void setCamPos(const glm::vec2& newPos);
void setIsometricView(bool isometric); // false = 2D true = Isometric
}
} // namespace render
} // namespace td
#endif /* RENDER_RENDERER_H_ */

View File

@@ -0,0 +1,23 @@
#pragma once
#include "game/World.h"
namespace td {
namespace render {
namespace WorldRenderer{
void init(const game::World* world);
void update();
void render();
void destroy();
void moveCam(float relativeX, float relativeY, float aspectRatio);
void changeZoom(float zoom);
void click(int mouseX, int mouseY);
} // namespace WorldRenderer
} // namespace render
} // namespace td

View File

@@ -0,0 +1,23 @@
/*
* TowerGUI.h
*
* Created on: 5 nov. 2020
* Author: simon
*/
#ifndef RENDER_GUI_TOWERGUI_H_
#define RENDER_GUI_TOWERGUI_H_
struct GLFWwindow;
namespace TowerGui{
void init(GLFWwindow* window);
void render();
void destroy();
}
#endif /* RENDER_GUI_TOWERGUI_H_ */

View File

@@ -0,0 +1,67 @@
/*
* GLLoader.h
*
* Created on: 4 nov. 2020
* Author: simon
*/
#pragma once
#include <vector>
#define REMOVE_COPY(className) \
className(const className &) = delete;\
className& operator=(const className &) = delete
namespace GL{
struct VertexAttribPointer{
unsigned int m_Index, m_Size;
int m_Offset;
};
class VBO{
private:
unsigned int m_ID, m_DataStride;
std::vector<VertexAttribPointer> m_VertexAttribs;
public:
REMOVE_COPY(VBO);
VBO(VBO&& other){
m_VertexAttribs = std::move(other.m_VertexAttribs);
m_ID = other.m_ID;
m_DataStride = other.m_DataStride;
other.m_ID = 0;
other.m_DataStride = 0;
}
VBO(const std::vector<float>& data, unsigned int stride);
~VBO();
void bind() const;
void unbind() const;
void addVertexAttribPointer(unsigned int index, unsigned int coordinateSize, unsigned int offset);
void bindVertexAttribs() const;
};
class VAO{
private:
unsigned int m_ID, m_VertexCount;
std::vector<VBO> m_Vbos; //use to destroy vbos when become unused
public:
REMOVE_COPY(VAO);
VAO(VAO&& other){
m_ID = other.m_ID;
m_VertexCount = other.m_VertexCount;
m_Vbos = std::move(other.m_Vbos);
other.m_VertexCount = 0;
other.m_ID = 0;
}
VAO(unsigned int vertexCount);
~VAO();
unsigned int getVertexCount() const {return m_VertexCount;}
void bindVBO(VBO& vbo);
void bind() const;
void unbind() const;
};
}

View File

@@ -0,0 +1,16 @@
/*
* TextureLoader.h
*
* Created on: 15 nov. 2020
* Author: simon
*/
#ifndef RENDER_LOADER_TEXTURELOADER_H_
#define RENDER_LOADER_TEXTURELOADER_H_
namespace TextureLoader{
const unsigned int loadGLTexture(const char* fileName);
}
#endif /* RENDER_LOADER_TEXTURELOADER_H_ */

View File

@@ -0,0 +1,18 @@
#pragma once
#include "game/World.h"
#include "GLLoader.h"
namespace td {
namespace render {
namespace WorldLoader {
GL::VAO loadMobModel();
GL::VAO loadWorldModel(const td::game::World* world);
} // namespace WorldLoader
} // namespace render
} // namespace td

7559
include/render/loader/stb_image.h Executable file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,18 @@
#pragma once
#include "ShaderProgram.h"
class EntityShader : public ShaderProgram{
private:
unsigned int location_cam = 0, location_zoom = 0, location_aspect_ratio = 0, location_translation = 0, location_viewtype = 0;
protected:
void getAllUniformLocation();
public:
EntityShader();
void loadShader();
void setCamPos(const glm::vec2& camPos);
void setZoom(float zoom);
void setAspectRatio(float aspectRatio);
void setModelPos(const glm::vec2& modelPos);
void setIsometricView(float isometric);
};

View File

@@ -0,0 +1,47 @@
/*
* ShaderProgram.h
*
* Created on: 31 janv. 2020
* Author: simon
*/
#ifndef RENDER_SHADERS_SHADERPROGRAM_H_
#define RENDER_SHADERS_SHADERPROGRAM_H_
#include <string>
#include <glm/glm.hpp>
namespace gl{
enum class GLenum : unsigned int;
}
class ShaderProgram {
public:
ShaderProgram();
virtual ~ShaderProgram();
void start() const;
void stop() const;
void loadProgramFile(const std::string& vertexFile, const std::string& fragmentFile);
void loadProgram(const std::string& vertexSource, const std::string& fragmentSource);
protected:
virtual void getAllUniformLocation() = 0;
int getUniformLocation(const std::string& uniformName)const;
void loadFloat(const int location, const float value)const;
void loadInt(const int& location, const int& value)const;
void loadVector(const int& location, const glm::vec2& vector)const;
void loadVector(const int& location, const glm::vec3& vector)const;
void loadVector(const int& location, const glm::vec4& vector)const;
void loadBoolean(const int& location, const bool& value)const;
void loadMatrix(const int& location, const glm::mat4& matrix);
void cleanUp() const;
private:
unsigned int programID;
unsigned int vertexShaderID;
unsigned int fragmentShaderID;
int loadShaderFromFile(const std::string& file, gl::GLenum type);
int loadShader(const std::string& source, gl::GLenum type);
};
#endif /* RENDER_SHADERS_SHADERPROGRAM_H_ */

View File

@@ -0,0 +1,27 @@
/*
* GameShader.h
*
* Created on: 4 nov. 2020
* Author: simon
*/
#ifndef RENDER_SHADERS_GAMESHADER_H_
#define RENDER_SHADERS_GAMESHADER_H_
#include "ShaderProgram.h"
class WorldShader : public ShaderProgram{
private:
unsigned int location_cam = 0, location_zoom = 0, location_aspect_ratio = 0, location_viewtype = 0;
protected:
void getAllUniformLocation();
public:
WorldShader();
void loadShader();
void setCamPos(const glm::vec2& camPos);
void setZoom(float zoom);
void setAspectRatio(float aspectRatio);
void setIsometricView(float isometric);
};
#endif /* RENDER_SHADERS_GAMESHADER_H_ */

31
include/window/Display.h Normal file
View File

@@ -0,0 +1,31 @@
/*
* Display.h
*
* Created on: 4 nov. 2020
* Author: simon
*/
#ifndef WINDOW_DISPLAY_H_
#define WINDOW_DISPLAY_H_
namespace Display{
void create();
void render();
void update();
void destroy();
void pollEvents();
bool isCloseRequested();
const bool isMouseDown(int button);
float getAspectRatio();
int getWindowWidth();
int getWindowHeight();
}
#endif /* WINDOW_DISPLAY_H_ */