62 Commits

Author SHA1 Message Date
36f37b6548 Revert "Merge branch 'discord'"
This reverts commit e7b9a57723, reversing
changes made to 02b4aa3c91.

Revert "moved rapidjson files"

This reverts commit f5012f770c.
2023-06-21 23:36:20 +02:00
1dde1dbf1e fix vertex cache 2023-06-20 16:27:41 +02:00
f5012f770c moved rapidjson files 2023-06-08 12:30:05 +02:00
e7b9a57723 Merge branch 'discord' 2023-06-08 12:21:54 +02:00
02b4aa3c91 xmake add_files 2023-06-08 12:16:50 +02:00
f184982bc1 change release optimization 2023-06-07 12:39:58 +02:00
1cdc738839 refactor: rename zoom function 2023-06-07 12:36:31 +02:00
368bc450ce better cam controls 2023-06-07 12:33:10 +02:00
148b5f397a more vect operators 2023-06-07 12:32:24 +02:00
f62322752d use of td pi 2023-06-06 17:59:48 +02:00
fb9e125f16 refactor: format 2023-06-06 17:58:27 +02:00
b70e8f7790 approximative cam movement 2023-06-06 17:56:19 +02:00
39bdd0a11e remove useless pi digits 2023-06-06 17:17:00 +02:00
c95c8b7fde clamp camera + pi 2023-06-06 17:15:44 +02:00
e984ed9085 fixed cam distance 2023-06-06 17:04:17 +02:00
92035d7b9e remove useless variable 2023-06-06 13:09:02 +02:00
48841fa4e9 camera fixing 2023-06-06 13:07:42 +02:00
83ab8c70f0 cache transpose 2023-06-06 12:45:34 +02:00
ccdcdac7c6 working mouse picking 2023-06-06 12:36:05 +02:00
a2b5424888 fix inverse assert 2023-06-05 18:06:02 +02:00
a4fb56b549 camera yaw and pitch 2023-06-05 13:50:45 +02:00
22e62df04d remove unused variables 2023-06-05 13:17:04 +02:00
faf544f997 basic camera movement 2023-06-05 13:15:27 +02:00
b72f4a7673 fix inverted zoom 2023-06-05 13:12:43 +02:00
19c03010cb remove useless computation 2023-06-05 13:07:56 +02:00
41f8c152eb really bad controls 2023-06-04 13:02:41 +02:00
051c9d8744 fix format error 2023-06-04 12:42:58 +02:00
193e4db651 fix mouse picking 2023-06-03 20:43:40 +02:00
cb5f5a4cf8 fixing transpose 2023-06-03 19:46:37 +02:00
bc7e5914ce invert assert 2023-06-03 19:44:05 +02:00
0365902971 moved Mat4 definition 2023-06-03 19:40:50 +02:00
f2fcc348d7 more maths 2023-06-03 18:22:01 +02:00
95c92ec6c9 rename lookat function 2023-06-03 17:54:59 +02:00
721f15b601 fix tower rendering 2023-06-03 17:49:00 +02:00
3970103b01 kinda 3d 2023-06-03 17:41:46 +02:00
4e866c1032 shaders to 3d 2023-06-03 16:35:17 +02:00
ca268781fd shader better logging 2023-06-03 16:30:32 +02:00
a2d8984199 shader matrix support 2023-06-03 16:30:23 +02:00
e7f9ca2b6c fix maths warning 2023-06-03 16:23:56 +02:00
deb0075aac add maths utils 2023-06-02 17:54:58 +02:00
28b8659e16 fix linux compiling 2023-06-02 16:26:17 +02:00
0b9fc0520e fix compiling mingw 2023-06-02 16:19:42 +02:00
c54017c7be update presence 2023-06-02 13:34:01 +02:00
bbfe341d23 base discord rpc 2023-06-02 13:18:09 +02:00
14efe2cc39 simplified health bar display 2023-01-02 16:58:31 +01:00
fcda12e321 add hit "animation" 2023-01-02 16:37:18 +01:00
1200a6e087 moved TowerUpgradePopop into its own file 2023-01-02 15:56:20 +01:00
512fb23d0e add server mspt (+procotol format) 2023-01-02 15:07:34 +01:00
5a547b6514 move towers implementations 2023-01-02 14:47:02 +01:00
ed45995645 add mob send cooldown 2023-01-02 14:32:37 +01:00
0b6d826eba remove unused glm package 2023-01-02 13:55:54 +01:00
6d0c6be166 server side safe checks 2023-01-02 13:18:49 +01:00
222b79b40a indent with tabs 2023-01-02 13:05:43 +01:00
8f95b1a750 remove format warning 2023-01-02 12:27:08 +01:00
7d30017742 moved Color to Defines.h 2023-01-02 12:21:27 +01:00
386ea5b6ad forward declare Updater 2023-01-02 12:05:20 +01:00
8949c37891 chore: bump version to alpha-0.3.0 2023-01-01 19:42:49 +01:00
019174128c fix: COMPRESSION 2023-01-01 19:40:23 +01:00
4e8b095e31 xmake.lua show wine console output 2022-12-11 13:04:00 +01:00
0e0368cada add wine xmake.lua 2022-12-11 12:59:57 +01:00
Simon Pribylski
6e0923ac75 remove glm dependency 2022-10-13 12:24:15 +02:00
Simon Pribylski
bba9ef8219 Add glm dependency 2022-09-07 18:54:10 +02:00
121 changed files with 5611 additions and 4944 deletions

148
include/Defines.h Normal file
View File

@@ -0,0 +1,148 @@
#pragma once
#include <cstdint>
namespace td {
static constexpr float PI = 3.141592653f;
template<typename T>
struct Vec2 {
union {
T x;
T r;
};
union {
T y;
T g;
};
constexpr Vec2(T X = 0, T Y = 0) : x(X), y(Y) {}
};
template<typename T>
inline bool operator==(const Vec2<T>& vec2, const Vec2<T>& other) {
return vec2.x == other.x && vec2.y == other.y;
}
template<typename T>
struct Vec3 {
union {
T x;
T r;
};
union {
T y;
T g;
};
union {
T z;
T b;
};
constexpr Vec3(T X = 0, T Y = 0, T Z = 0) : x(X), y(Y), z(Z) {}
};
template<typename T>
inline bool operator==(const Vec3<T>& vec3, const Vec3<T>& other) {
return vec3.x == other.x && vec3.y == other.y && vec3.z == other.z;
}
template<typename T>
struct Vec4 {
union {
T x;
T r;
};
union {
T y;
T g;
};
union {
T z;
T b;
};
union {
T w;
T a;
};
constexpr Vec4(Vec3<T> vec, T W = 1) : x(vec.x), y(vec.y), z(vec.z), w(W) {}
constexpr Vec4(T X = 0, T Y = 0, T Z = 0, T W = 0) : x(X), y(Y), z(Z), w(W) {}
};
template<typename T>
inline bool operator==(const Vec4<T>& vec4, const Vec4<T>& other) {
return vec4.x == other.x && vec4.y == other.y && vec4.z == other.z && vec4.w = other.w;
}
using Vec2i = Vec2<int>;
using Vec2u = Vec2<unsigned int>;
using Vec2f = Vec2<float>;
using Vec2d = Vec2<double>;
using Vec3i = Vec3<int>;
using Vec3u = Vec3<unsigned int>;
using Vec3f = Vec3<float>;
using Vec3d = Vec3<double>;
using Vec4i = Vec4<int>;
using Vec4u = Vec4<unsigned int>;
using Vec4f = Vec4<float>;
using Vec4d = Vec4<double>;
using Color = Vec3<unsigned char>;
template<typename T>
struct Mat4 {
static const std::size_t MATRIX_SIZE = 4;
T x0, x1, x2, x3;
T y0, y1, y2, y3;
T z0, z1, z2, z3;
T w0, w1, w2, w3;
T operator[] (std::size_t offset) const {
return reinterpret_cast<const T*>(this)[offset];
}
T& operator[] (std::size_t offset) {
return reinterpret_cast<T*>(this)[offset];
}
T* data() {
return reinterpret_cast<T*>(this);
}
const T* data() const{
return reinterpret_cast<const T*>(this);
}
T at(std::size_t row, std::size_t column) const {
return operator[](row * MATRIX_SIZE + column);
}
T& at(std::size_t row, std::size_t column) {
return operator[](row * MATRIX_SIZE + column);
}
};
typedef Mat4<float> Mat4f;
typedef Mat4<int> Mat4i;
typedef Mat4<double> Mat4d;
template<typename T>
inline bool operator==(const Mat4<T>& mat, const Mat4<T>& other) {
return mat.x0 == other.x0 && mat.y0 == other.y0 && mat.z0 == other.z0 && mat.w0 == other.w0 &&
mat.x1 == other.x1 && mat.y1 == other.y1 && mat.z1 == other.z1 && mat.w1 == other.w1 &&
mat.x2 == other.x2 && mat.y2 == other.y2 && mat.z2 == other.z2 && mat.w2 == other.w2 &&
mat.x3 == other.x3 && mat.y3 == other.y3 && mat.z3 == other.z3 && mat.w3 == other.w3;
}
} // namespace td

View File

@@ -8,62 +8,62 @@ namespace td {
namespace game { namespace game {
enum class GameState : std::uint8_t { enum class GameState : std::uint8_t {
Lobby, Lobby,
Game, Game,
EndGame, EndGame,
Disconnected, Disconnected,
Closed Closed
}; };
typedef std::map<std::uint8_t, Player> PlayerList; typedef std::map<std::uint8_t, Player> PlayerList;
class GameListener { class GameListener {
public: public:
virtual void OnPlayerJoin(PlayerID player) {} virtual void OnPlayerJoin(PlayerID player) {}
virtual void OnPlayerLeave(PlayerID player) {} virtual void OnPlayerLeave(PlayerID player) {}
virtual void OnGameStateUpdate(GameState newState) {} virtual void OnGameStateUpdate(GameState newState) {}
virtual void OnGameBegin() {} virtual void OnGameBegin() {}
virtual void OnGameEnd() {} virtual void OnGameEnd() {}
virtual void OnGameClose() {} virtual void OnGameClose() {}
}; };
typedef utils::ObjectNotifier<GameListener> GameNotifier; typedef utils::ObjectNotifier<GameListener> GameNotifier;
class Game : public GameNotifier { class Game : public GameNotifier {
protected: protected:
World* m_World; World* m_World;
TeamList m_Teams = { Team{TeamColor::Red}, Team{TeamColor::Blue} }; TeamList m_Teams = { Team{TeamColor::Red}, Team{TeamColor::Blue} };
GameState m_GameState = GameState::Lobby; GameState m_GameState = GameState::Lobby;
PlayerList m_Players; PlayerList m_Players;
public: public:
Game(World* world); Game(World* world);
virtual ~Game(); virtual ~Game();
virtual void Tick(std::uint64_t delta); virtual void Tick(std::uint64_t delta);
Team& GetRedTeam() { return m_Teams[static_cast<std::uint8_t>(TeamColor::Red)]; } Team& GetRedTeam() { return m_Teams[static_cast<std::uint8_t>(TeamColor::Red)]; }
const Team& GetRedTeam() const { return m_Teams[static_cast<std::uint8_t>(TeamColor::Red)]; } const Team& GetRedTeam() const { return m_Teams[static_cast<std::uint8_t>(TeamColor::Red)]; }
Team& GetBlueTeam() { return m_Teams[static_cast<std::uint8_t>(TeamColor::Blue)]; } Team& GetBlueTeam() { return m_Teams[static_cast<std::uint8_t>(TeamColor::Blue)]; }
const Team& GetBlueTeam() const { return m_Teams[static_cast<std::uint8_t>(TeamColor::Red)]; } const Team& GetBlueTeam() const { return m_Teams[static_cast<std::uint8_t>(TeamColor::Red)]; }
Team& GetTeam(TeamColor team) { return m_Teams[static_cast<std::uint8_t>(team)]; } Team& GetTeam(TeamColor team) { return m_Teams[static_cast<std::uint8_t>(team)]; }
const Team& GetTeam(TeamColor team) const { return m_Teams[static_cast<std::uint8_t>(team)]; } const Team& GetTeam(TeamColor team) const { return m_Teams[static_cast<std::uint8_t>(team)]; }
GameState GetGameState() const { return m_GameState; } GameState GetGameState() const { return m_GameState; }
void SetGameState(GameState gameState) { m_GameState = gameState; }; void SetGameState(GameState gameState) { m_GameState = gameState; };
const World* GetWorld() const { return m_World; } const World* GetWorld() const { return m_World; }
World* GetWorld() { return m_World; } World* GetWorld() { return m_World; }
const PlayerList& GetPlayers() const { return m_Players; } const PlayerList& GetPlayers() const { return m_Players; }
PlayerList& GetPlayers() { return m_Players; } PlayerList& GetPlayers() { return m_Players; }
const Player* GetPlayerById(PlayerID id) const; const Player* GetPlayerById(PlayerID id) const;
Player* GetPlayerById(PlayerID id); Player* GetPlayerById(PlayerID id);
const TeamList& GetTeams() const { return m_Teams; } const TeamList& GetTeams() const { return m_Teams; }
}; };

View File

@@ -10,26 +10,26 @@ namespace protocol {
class Connexion : public protocol::PacketHandler { class Connexion : public protocol::PacketHandler {
protected: protected:
protocol::PacketDispatcher m_Dispatcher; protocol::PacketDispatcher m_Dispatcher;
private: private:
network::TCPSocket m_Socket; network::TCPSocket m_Socket;
public: public:
Connexion(); Connexion();
Connexion(Connexion&& move); Connexion(Connexion&& move);
Connexion(protocol::PacketDispatcher* dispatcher); Connexion(protocol::PacketDispatcher* dispatcher);
Connexion(protocol::PacketDispatcher* dispatcher, network::TCPSocket& socket); Connexion(protocol::PacketDispatcher* dispatcher, network::TCPSocket& socket);
virtual ~Connexion(); virtual ~Connexion();
virtual bool UpdateSocket(); virtual bool UpdateSocket();
void CloseConnection(); void CloseConnection();
bool Connect(const std::string& address, std::uint16_t port); bool Connect(const std::string& address, std::uint16_t port);
network::Socket::Status GetSocketStatus() const { return m_Socket.GetStatus(); } network::Socket::Status GetSocketStatus() const { return m_Socket.GetStatus(); }
void SendPacket(const protocol::Packet* packet); void SendPacket(const protocol::Packet* packet);
REMOVE_COPY(Connexion); REMOVE_COPY(Connexion);
}; };
} // namespace server } // namespace server

View File

@@ -1,5 +1,6 @@
#pragma once #pragma once
#include "Defines.h"
#include "Towers.h" #include "Towers.h"
#include "Types.h" #include "Types.h"
#include "Team.h" #include "Team.h"
@@ -9,34 +10,32 @@
#include <vector> #include <vector>
#include <memory> #include <memory>
#include <glm/glm.hpp>
namespace td { namespace td {
namespace game { namespace game {
struct WalkableTile; struct WalkableTile;
enum class EffectType : std::uint8_t { enum class EffectType : std::uint8_t {
Slowness = 0, Slowness = 0,
Stun, Stun,
Fire, Fire,
Poison, Poison,
Heal, Heal,
}; };
enum class MobType : std::uint8_t { enum class MobType : std::uint8_t {
Zombie = 0, Zombie = 0,
Spider, Spider,
Skeleton, Skeleton,
Pigman, Pigman,
Creeper, Creeper,
Silverfish, Silverfish,
Blaze, Blaze,
Witch, Witch,
Slime, Slime,
Giant, Giant,
MOB_COUNT MOB_COUNT
}; };
typedef std::uint32_t MobID; typedef std::uint32_t MobID;
@@ -46,34 +45,34 @@ typedef std::vector<EffectType> EffectImmunities;
class MobStats { class MobStats {
private: private:
float m_Damage; float m_Damage;
float m_Speed; float m_Speed;
glm::vec2 m_Size; Vec2f m_Size;
std::uint16_t m_MoneyCost; std::uint16_t m_MoneyCost;
std::uint16_t m_ExpCost; std::uint16_t m_ExpCost;
std::uint16_t m_MaxLife; std::uint16_t m_MaxLife;
std::uint16_t m_ExpReward; std::uint16_t m_ExpReward;
public: public:
MobStats(float damage, float speed, glm::vec2 size, std::uint16_t moneyCost, MobStats(float damage, float speed, Vec2f size, std::uint16_t moneyCost,
std::uint16_t expCost, std::uint16_t expReward, std::uint16_t expCost, std::uint16_t expReward,
std::uint16_t maxLife) : m_Damage(damage), m_Speed(speed), std::uint16_t maxLife) : m_Damage(damage), m_Speed(speed),
m_Size(size), m_MoneyCost(moneyCost), m_ExpCost(expCost), m_Size(size), m_MoneyCost(moneyCost), m_ExpCost(expCost),
m_MaxLife(maxLife), m_ExpReward(expReward) { m_MaxLife(maxLife), m_ExpReward(expReward) {
} }
float GetDamage() const { return m_Damage; } float GetDamage() const { return m_Damage; }
float GetMovementSpeed() const { return m_Speed; } float GetMovementSpeed() const { return m_Speed; }
const glm::vec2& GetSize() const { return m_Size; } const Vec2f& GetSize() const { return m_Size; }
std::uint16_t GetMoneyCost() const { return m_MoneyCost; } std::uint16_t GetMoneyCost() const { return m_MoneyCost; }
std::uint16_t GetExpCost() const { return m_ExpCost; } std::uint16_t GetExpCost() const { return m_ExpCost; }
std::uint16_t GetExpReward() const { return m_ExpReward; } std::uint16_t GetExpReward() const { return m_ExpReward; }
std::uint16_t GetMaxLife() const { return m_MaxLife; } std::uint16_t GetMaxLife() const { return m_MaxLife; }
}; };
struct EffectDuration { struct EffectDuration {
EffectType type; EffectType type;
float duration; // in seconds float duration; // in seconds
Tower* tower; // the tower that gived the effect Tower* tower; // the tower that gived the effect
}; };
const MobStats* GetMobStats(MobType type, std::uint8_t level); const MobStats* GetMobStats(MobType type, std::uint8_t level);
@@ -82,149 +81,160 @@ const EffectImmunities& GetMobEffectImmunities(MobType type, std::uint8_t level)
class Mob : public utils::shape::Rectangle { class Mob : public utils::shape::Rectangle {
protected: protected:
float m_Health; float m_Health;
private: private:
MobID m_ID; MobID m_ID;
PlayerID m_Sender; PlayerID m_Sender;
MobLevel m_Level; MobLevel m_Level;
Direction m_Direction; Direction m_Direction;
std::vector<EffectDuration> m_Effects; std::vector<EffectDuration> m_Effects;
const Tower* m_LastDamage; // the last tower that damaged the mob const Tower* m_LastDamage; // the last tower that damaged the mob
float m_HitCooldown;
utils::Timer m_EffectFireTimer; utils::Timer m_EffectFireTimer;
utils::Timer m_EffectPoisonTimer; utils::Timer m_EffectPoisonTimer;
utils::Timer m_EffectHealTimer; utils::Timer m_EffectHealTimer;
TeamCastle* m_CastleTarget; TeamCastle* m_CastleTarget;
utils::CooldownTimer m_AttackTimer; utils::CooldownTimer m_AttackTimer;
public: public:
Mob(MobID id, MobLevel level, PlayerID sender) : m_Sender(sender), m_Level(level), Mob(MobID id, MobLevel level, PlayerID sender) : m_Sender(sender), m_Level(level),
m_EffectFireTimer(1000), m_EffectPoisonTimer(1000), m_HitCooldown(0), m_EffectFireTimer(1000), m_EffectPoisonTimer(1000),
m_EffectHealTimer(1000), m_CastleTarget(nullptr), m_AttackTimer(1000) { m_EffectHealTimer(1000), m_CastleTarget(nullptr), m_AttackTimer(1000) {
} }
virtual MobType GetType() const = 0; virtual MobType GetType() const = 0;
virtual void Tick(std::uint64_t delta, World* world); virtual void Tick(std::uint64_t delta, World* world);
virtual bool OnDeath(World* world) { return true; } virtual bool OnDeath(World* world) { return true; }
MobID GetMobID() const { return m_ID; } MobID GetMobID() const { return m_ID; }
const TowerImmunities& GetTowerImmunities() const { return GetMobTowerImmunities(GetType(), m_Level); } const TowerImmunities& GetTowerImmunities() const { return GetMobTowerImmunities(GetType(), m_Level); }
const EffectImmunities& GetEffectImmunities() const { return GetMobEffectImmunities(GetType(), m_Level); } const EffectImmunities& GetEffectImmunities() const { return GetMobEffectImmunities(GetType(), m_Level); }
PlayerID GetSender() const { return m_Sender; } PlayerID GetSender() const { return m_Sender; }
MobLevel GetLevel() const { return m_Level; } MobLevel GetLevel() const { return m_Level; }
const MobStats* GetStats() const { return GetMobStats(GetType(), m_Level); } const MobStats* GetStats() const { return GetMobStats(GetType(), m_Level); }
void SetHealth(float newHealth) { m_Health = newHealth; } void SetHealth(float newHealth) { m_Health = newHealth; }
float GetHealth() const { return m_Health; } float GetHealth() const { return m_Health; }
bool IsDead() const { return m_Health <= 0; } bool IsDead() const { return m_Health <= 0; }
bool IsAlive() const { return m_Health > 0; } bool IsAlive() const { return m_Health > 0; }
const Tower* GetLastDamageTower() { return m_LastDamage; } const Tower* GetLastDamageTower() { return m_LastDamage; }
bool HasReachedEnemyCastle() { return m_CastleTarget != nullptr; } bool HasReachedEnemyCastle() { return m_CastleTarget != nullptr; }
void Damage(float dmg, const Tower* damager) { m_Health = std::max(0.0f, m_Health - dmg); m_LastDamage = damager; } void Damage(float dmg, const Tower* damager) {
void Heal(float heal) { m_Health = std::min(static_cast<float>(GetStats()->GetMaxLife()), m_Health + heal); } m_Health = std::max(0.0f, m_Health - dmg);
void SetMobReachedCastle(TeamCastle* castle) { m_CastleTarget = castle; } // used when mob is in front of the castle m_LastDamage = damager;
m_HitCooldown = 0.1;
}
bool IsImmuneTo(TowerType type); void Heal(float heal) {
m_Health = std::min(static_cast<float>(GetStats()->GetMaxLife()), m_Health + heal);
}
bool IsImmuneTo(EffectType type); void SetMobReachedCastle(TeamCastle* castle) { m_CastleTarget = castle; } // used when mob is in front of the castle
void AddEffect(EffectType type, float durationSec, Tower* tower);
bool HasEffect(EffectType type);
float GetTileX() { return GetCenterX() - static_cast<float>(static_cast<std::int32_t>(GetCenterX())); } // returns a float between 0 and 1 excluded bool IsImmuneTo(TowerType type);
float GetTileY() { return GetCenterY() - static_cast<float>(static_cast<std::int32_t>(GetCenterY())); } // returns a float between 0 and 1 excluded
Direction GetDirection() const { return m_Direction; } bool IsImmuneTo(EffectType type);
void SetDirection(Direction dir) { m_Direction = dir; } void AddEffect(EffectType type, float durationSec, Tower* tower);
bool HasEffect(EffectType type);
bool HasTakenDamage() { return m_HitCooldown > 0; }
float GetTileX() { return GetCenterX() - static_cast<float>(static_cast<std::int32_t>(GetCenterX())); } // returns a float between 0 and 1 excluded
float GetTileY() { return GetCenterY() - static_cast<float>(static_cast<std::int32_t>(GetCenterY())); } // returns a float between 0 and 1 excluded
Direction GetDirection() const { return m_Direction; }
void SetDirection(Direction dir) { m_Direction = dir; }
protected: protected:
void InitMob() { void InitMob() {
m_Health = static_cast<float>(GetStats()->GetMaxLife()); m_Health = static_cast<float>(GetStats()->GetMaxLife());
SetSize(GetStats()->GetSize().x, GetStats()->GetSize().y); SetSize(GetStats()->GetSize().x, GetStats()->GetSize().y);
} }
private: private:
void UpdateEffects(std::uint64_t delta, World* world); void UpdateEffects(std::uint64_t delta, World* world);
void AttackCastle(std::uint64_t delta, World* world); void AttackCastle(std::uint64_t delta, World* world);
void Move(std::uint64_t delta, World* world); void Move(std::uint64_t delta, World* world);
void Walk(std::uint64_t delta, World* world); void Walk(std::uint64_t delta, World* world);
void MoveBack(const TeamCastle& castle, World* world); void MoveBack(const TeamCastle& castle, World* world);
void ChangeDirection(const WalkableTile& tile, World* world); void ChangeDirection(const WalkableTile& tile, World* world);
bool IsTouchingCastle(const TeamCastle& castle) const; bool IsTouchingCastle(const TeamCastle& castle) const;
EffectDuration& GetEffect(EffectType type); EffectDuration& GetEffect(EffectType type);
}; };
typedef std::shared_ptr<Mob> MobPtr; typedef std::shared_ptr<Mob> MobPtr;
class Zombie : public Mob { class Zombie : public Mob {
public: public:
Zombie(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); } Zombie(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); }
virtual MobType GetType() const { return MobType::Zombie; } virtual MobType GetType() const { return MobType::Zombie; }
}; };
class Spider : public Mob { class Spider : public Mob {
public: public:
Spider(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); } Spider(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); }
virtual MobType GetType() const { return MobType::Spider; } virtual MobType GetType() const { return MobType::Spider; }
}; };
class Skeleton : public Mob { class Skeleton : public Mob {
public: public:
Skeleton(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); } Skeleton(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); }
virtual MobType GetType() const { return MobType::Skeleton; } virtual MobType GetType() const { return MobType::Skeleton; }
}; };
class PigMan : public Mob { class PigMan : public Mob {
public: public:
PigMan(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); } PigMan(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); }
virtual MobType GetType() const { return MobType::Pigman; } virtual MobType GetType() const { return MobType::Pigman; }
}; };
class Creeper : public Mob { class Creeper : public Mob {
public: public:
Creeper(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); } Creeper(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); }
virtual MobType GetType() const { return MobType::Creeper; } virtual MobType GetType() const { return MobType::Creeper; }
}; };
class Silverfish : public Mob { class Silverfish : public Mob {
public: public:
Silverfish(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); } Silverfish(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); }
virtual MobType GetType() const { return MobType::Silverfish; } virtual MobType GetType() const { return MobType::Silverfish; }
}; };
class Blaze : public Mob { class Blaze : public Mob {
public: public:
Blaze(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); } Blaze(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); }
virtual MobType GetType() const { return MobType::Blaze; } virtual MobType GetType() const { return MobType::Blaze; }
}; };
class Witch : public Mob { class Witch : public Mob {
public: public:
Witch(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); } Witch(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); }
virtual MobType GetType() const { return MobType::Witch; } virtual MobType GetType() const { return MobType::Witch; }
}; };
class Slime : public Mob { class Slime : public Mob {
public: public:
Slime(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); } Slime(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); }
virtual MobType GetType() const { return MobType::Slime; } virtual MobType GetType() const { return MobType::Slime; }
}; };
class Giant : public Mob { class Giant : public Mob {
public: public:
Giant(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); } Giant(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); }
virtual MobType GetType() const { return MobType::Giant; } virtual MobType GetType() const { return MobType::Giant; }
}; };
namespace MobFactory { namespace MobFactory {
@@ -236,13 +246,13 @@ std::string GetMobName(MobType type);
class MobListener { class MobListener {
public: public:
virtual void OnMobSpawn(Mob* mob) {} virtual void OnMobSpawn(Mob* mob) {}
virtual void OnMobDie(Mob* mob) {} virtual void OnMobDie(Mob* mob) {}
virtual void OnMobDamage(Mob* target, float damage, Tower* damager) {} virtual void OnMobDamage(Mob* target, float damage, Tower* damager) {}
virtual void OnMobTouchCastle(Mob* damager, TeamCastle* enemyCastle) {} virtual void OnMobTouchCastle(Mob* damager, TeamCastle* enemyCastle) {}
virtual void OnMobCastleDamage(Mob* damager, TeamCastle* enemyCastle, float damage) {} virtual void OnMobCastleDamage(Mob* damager, TeamCastle* enemyCastle, float damage) {}
}; };
typedef utils::ObjectNotifier<MobListener> MobNotifier; typedef utils::ObjectNotifier<MobListener> MobNotifier;

View File

@@ -10,41 +10,41 @@ namespace game {
class Player { class Player {
private: private:
TeamColor m_TeamColor; TeamColor m_TeamColor;
PlayerUpgrades m_Upgrades; PlayerUpgrades m_Upgrades;
std::uint32_t m_Gold; std::uint32_t m_Gold;
std::uint32_t m_Exp; std::uint32_t m_Exp;
std::string m_Name; std::string m_Name;
PlayerID m_ID; PlayerID m_ID;
public: public:
Player(std::uint8_t id = 0) : m_TeamColor(TeamColor::None), m_Gold(0), m_Exp(0), m_ID(id) {} Player(std::uint8_t id = 0) : m_TeamColor(TeamColor::None), m_Gold(0), m_Exp(0), m_ID(id) {}
const std::string& GetName() const { return m_Name; } const std::string& GetName() const { return m_Name; }
void SetName(const std::string& name) { m_Name = name; } void SetName(const std::string& name) { m_Name = name; }
TeamColor GetTeamColor() const { return m_TeamColor; } TeamColor GetTeamColor() const { return m_TeamColor; }
void SetTeamColor(TeamColor teamColor) { m_TeamColor = teamColor; } void SetTeamColor(TeamColor teamColor) { m_TeamColor = teamColor; }
std::uint32_t GetGold() const { return m_Gold; } std::uint32_t GetGold() const { return m_Gold; }
void SetGold(std::uint32_t gold) { m_Gold = gold; } void SetGold(std::uint32_t gold) { m_Gold = gold; }
void AddGold(std::uint32_t gold) { m_Gold += gold; } void AddGold(std::uint32_t gold) { m_Gold += gold; }
void RemoveGold(std::uint32_t gold) { m_Gold -= gold; } void RemoveGold(std::uint32_t gold) { m_Gold -= gold; }
std::uint32_t GetExp() const { return m_Exp; } std::uint32_t GetExp() const { return m_Exp; }
void SetExp(std::uint32_t exp) { m_Exp = exp; } void SetExp(std::uint32_t exp) { m_Exp = exp; }
void AddExp(std::uint32_t exp) { m_Exp += exp; } void AddExp(std::uint32_t exp) { m_Exp += exp; }
void RemoveExp(std::uint32_t exp) { m_Exp -= exp; } void RemoveExp(std::uint32_t exp) { m_Exp -= exp; }
const PlayerUpgrades& getUpgrades() const { return m_Upgrades; } const PlayerUpgrades& getUpgrades() const { return m_Upgrades; }
PlayerUpgrades& getUpgrades() { return m_Upgrades; } PlayerUpgrades& getUpgrades() { return m_Upgrades; }
bool HasEnoughGold(std::uint32_t gold) const { return m_Gold >= gold; } bool HasEnoughGold(std::uint32_t gold) const { return m_Gold >= gold; }
bool HasEnoughExp(std::uint32_t exp) const { return m_Exp >= exp; } bool HasEnoughExp(std::uint32_t exp) const { return m_Exp >= exp; }
PlayerID GetID() const { return m_ID; } PlayerID GetID() const { return m_ID; }
}; };
} // namespace game } // namespace game

View File

@@ -7,27 +7,27 @@ namespace game {
class PlayerUpgrades { class PlayerUpgrades {
private: private:
std::uint8_t m_ClickerLevel; std::uint8_t m_ClickerLevel;
std::uint8_t m_GoldPerSecond; std::uint8_t m_GoldPerSecond;
std::array<std::uint8_t, static_cast<std::size_t>(MobType::MOB_COUNT)> m_MobsUpgradeLevel; std::array<std::uint8_t, static_cast<std::size_t>(MobType::MOB_COUNT)> m_MobsUpgradeLevel;
public: public:
static const int MAX_MOB_LEVEL = 5; static const int MAX_MOB_LEVEL = 5;
static const int MAX_CLICKER_LEVEL = 3; static const int MAX_CLICKER_LEVEL = 3;
PlayerUpgrades() : m_ClickerLevel(1), m_GoldPerSecond(5) {} PlayerUpgrades() : m_ClickerLevel(1), m_GoldPerSecond(5) {}
std::uint8_t GetClickerLevel() const { return m_ClickerLevel; } std::uint8_t GetClickerLevel() const { return m_ClickerLevel; }
std::uint8_t GetMobUpgradeLevel(MobType mob) const { return m_MobsUpgradeLevel.at(static_cast<std::size_t>(mob)); } std::uint8_t GetMobUpgradeLevel(MobType mob) const { return m_MobsUpgradeLevel.at(static_cast<std::size_t>(mob)); }
std::uint8_t GetGoldPerSecond() const { return m_GoldPerSecond; } std::uint8_t GetGoldPerSecond() const { return m_GoldPerSecond; }
void UpgradeMob(MobType mob) { void UpgradeMob(MobType mob) {
std::uint8_t& mobLevel = m_MobsUpgradeLevel.at(static_cast<std::size_t>(mob)); std::uint8_t& mobLevel = m_MobsUpgradeLevel.at(static_cast<std::size_t>(mob));
mobLevel = std::min(mobLevel + 1, MAX_MOB_LEVEL); mobLevel = std::min(mobLevel + 1, MAX_MOB_LEVEL);
} }
void UpgradeClicker() { m_ClickerLevel = std::min(m_ClickerLevel + 1, MAX_CLICKER_LEVEL); } void UpgradeClicker() { m_ClickerLevel = std::min(m_ClickerLevel + 1, MAX_CLICKER_LEVEL); }
void SetGoldPerSecond(std::uint8_t goldPerSecond) { m_GoldPerSecond = goldPerSecond; } void SetGoldPerSecond(std::uint8_t goldPerSecond) { m_GoldPerSecond = goldPerSecond; }
}; };
} // namespace game } // namespace game

View File

@@ -14,76 +14,76 @@ namespace game {
class Player; class Player;
enum class TeamColor : std::int8_t { enum class TeamColor : std::int8_t {
None = -1, None = -1,
Red, Red,
Blue Blue
}; };
class Spawn : public utils::shape::Rectangle { class Spawn : public utils::shape::Rectangle {
private: private:
Direction m_Direction; Direction m_Direction;
public: public:
Spawn() { Spawn() {
SetWidth(5); SetWidth(5);
SetHeight(5); SetHeight(5);
} }
Direction GetDirection() const { return m_Direction; } Direction GetDirection() const { return m_Direction; }
void SetDirection(Direction direction) { m_Direction = direction; } void SetDirection(Direction direction) { m_Direction = direction; }
}; };
class Team; class Team;
class TeamCastle : public utils::shape::Rectangle { class TeamCastle : public utils::shape::Rectangle {
private: private:
const Team* m_Team; const Team* m_Team;
float m_Life; float m_Life;
public: public:
static constexpr int CastleMaxLife = 1000; static constexpr int CastleMaxLife = 1000;
TeamCastle(const Team* team) : m_Team(team), m_Life(CastleMaxLife) { TeamCastle(const Team* team) : m_Team(team), m_Life(CastleMaxLife) {
SetWidth(5); SetWidth(5);
SetHeight(5); SetHeight(5);
} }
TeamCastle() : TeamCastle(nullptr) {} TeamCastle() : TeamCastle(nullptr) {}
float GetLife() const { return m_Life; } float GetLife() const { return m_Life; }
const Team* GetTeam() const { return m_Team; } const Team* GetTeam() const { return m_Team; }
void SetTeam(const Team* team) { m_Team = team; } void SetTeam(const Team* team) { m_Team = team; }
void SetLife(float life) { m_Life = life; } void SetLife(float life) { m_Life = life; }
void Damage(float damage) { m_Life = std::max(0.0f, m_Life - damage); } void Damage(float damage) { m_Life = std::max(0.0f, m_Life - damage); }
void SetShape(utils::shape::Rectangle rect) { void SetShape(utils::shape::Rectangle rect) {
SetCenter(rect.GetCenter()); SetCenter(rect.GetCenter());
SetSize(rect.GetSize()); SetSize(rect.GetSize());
} }
}; };
class Team { class Team {
private: private:
std::vector<Player*> m_Players; std::vector<Player*> m_Players;
TeamColor m_Color; TeamColor m_Color;
Spawn m_Spawn; Spawn m_Spawn;
TeamCastle m_TeamCastle; TeamCastle m_TeamCastle;
public: public:
Team(TeamColor color); Team(TeamColor color);
void AddPlayer(Player* newPlayer); void AddPlayer(Player* newPlayer);
void RemovePlayer(const Player* player); void RemovePlayer(const Player* player);
TeamColor GetColor() const; TeamColor GetColor() const;
const Spawn& GetSpawn() const { return m_Spawn; } const Spawn& GetSpawn() const { return m_Spawn; }
Spawn& GetSpawn() { return m_Spawn; } Spawn& GetSpawn() { return m_Spawn; }
const TeamCastle& GetCastle() const { return m_TeamCastle; } const TeamCastle& GetCastle() const { return m_TeamCastle; }
TeamCastle& GetCastle() { return m_TeamCastle; } TeamCastle& GetCastle() { return m_TeamCastle; }
std::uint8_t GetPlayerCount() const; std::uint8_t GetPlayerCount() const;
}; };
typedef std::array<Team, 2> TeamList; typedef std::array<Team, 2> TeamList;

View File

@@ -17,69 +17,69 @@ class Mob;
typedef std::shared_ptr<Mob> MobPtr; typedef std::shared_ptr<Mob> MobPtr;
enum class TowerType : std::uint8_t { enum class TowerType : std::uint8_t {
Archer = 0, Archer = 0,
Ice, Ice,
Sorcerer, Sorcerer,
Zeus, Zeus,
Mage, Mage,
Artillery, Artillery,
Quake, Quake,
Poison, Poison,
Leach, Leach,
Turret, Turret,
Necromancer, Necromancer,
TowerCount TowerCount
}; };
enum class TowerSize : std::uint8_t { enum class TowerSize : std::uint8_t {
Little = 3, // 3x3 Little = 3, // 3x3
Big = 5, // 5x5 Big = 5, // 5x5
}; };
enum class TowerPath : std::uint8_t { enum class TowerPath : std::uint8_t {
Top = 0, Top = 0,
Base, // Base Path Base, // Base Path
Bottom Bottom
}; };
class TowerStats { class TowerStats {
private: private:
float m_Rate; float m_Rate;
float m_Damage; float m_Damage;
std::uint8_t m_Range; std::uint8_t m_Range;
public: public:
TowerStats(float rate, float damage, std::uint8_t range) : m_Rate(rate), m_Damage(damage), TowerStats(float rate, float damage, std::uint8_t range) : m_Rate(rate), m_Damage(damage),
m_Range(range) { m_Range(range) {
} }
float GetDamageRate() const { return m_Rate; } float GetDamageRate() const { return m_Rate; }
float GetDamage() const { return m_Damage; } float GetDamage() const { return m_Damage; }
std::uint8_t GetRange() const { return m_Range; } std::uint8_t GetRange() const { return m_Range; }
}; };
class TowerLevel { class TowerLevel {
private: private:
// 1, 2, 3, 4 // 1, 2, 3, 4
std::uint8_t m_Level : 3; 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) // 0 : base path 1 : top path (if there is bottom path) 2 : bottom path (if there is top path)
TowerPath m_Path : 2; TowerPath m_Path : 2;
public: public:
TowerLevel() : m_Level(1), m_Path(TowerPath::Base) {} TowerLevel() : m_Level(1), m_Path(TowerPath::Base) {}
TowerLevel(std::uint8_t level, TowerPath path) : m_Level(level), m_Path(path) {} TowerLevel(std::uint8_t level, TowerPath path) : m_Level(level), m_Path(path) {}
std::uint8_t GetLevel() const { return m_Level; } std::uint8_t GetLevel() const { return m_Level; }
TowerPath GetPath() const { return m_Path; } TowerPath GetPath() const { return m_Path; }
void SetLevel(std::uint8_t level) { m_Level = level; } void SetLevel(std::uint8_t level) { m_Level = level; }
void SetPath(TowerPath path) { m_Path = path; } void SetPath(TowerPath path) { m_Path = path; }
// operator to sort maps // operator to sort maps
friend bool operator<(const TowerLevel& level, const TowerLevel& other) { friend bool operator<(const TowerLevel& level, const TowerLevel& other) {
return level.GetLevel() + static_cast<std::uint8_t>(level.GetPath()) * 4 < return level.GetLevel() + static_cast<std::uint8_t>(level.GetPath()) * 4 <
other.GetLevel() + static_cast<std::uint8_t>(other.GetPath()) * 4; other.GetLevel() + static_cast<std::uint8_t>(other.GetPath()) * 4;
} }
}; };
const TowerStats* GetTowerStats(TowerType type, TowerLevel level); const TowerStats* GetTowerStats(TowerType type, TowerLevel level);
@@ -88,36 +88,36 @@ typedef std::uint16_t TowerID;
class Tower : public utils::shape::Circle { class Tower : public utils::shape::Circle {
private: private:
TowerID m_ID; TowerID m_ID;
TowerType m_Type; TowerType m_Type;
TowerLevel m_Level{}; TowerLevel m_Level{};
PlayerID m_Builder; PlayerID m_Builder;
protected: protected:
utils::CooldownTimer m_Timer; utils::CooldownTimer m_Timer;
public: public:
Tower(TowerID id, TowerType type, std::int32_t x, std::int32_t y, PlayerID builder) : utils::shape::Circle(x + 0.5f, y + 0.5f, 0), m_ID(id), m_Type(type), m_Builder(builder), Tower(TowerID id, TowerType type, std::int32_t x, std::int32_t y, PlayerID builder) : utils::shape::Circle(x + 0.5f, y + 0.5f, 0), m_ID(id), m_Type(type), m_Builder(builder),
m_Timer(GetStats()->GetDamageRate() * 1000) { // converting seconds to millis m_Timer(GetStats()->GetDamageRate() * 1000) { // converting seconds to millis
SetRadius(GetStats()->GetRange()); SetRadius(GetStats()->GetRange());
} }
virtual TowerType GetType() const = 0; virtual TowerType GetType() const = 0;
virtual TowerSize GetSize() const = 0; virtual TowerSize GetSize() const = 0;
virtual void Tick(std::uint64_t delta, World* world) = 0; virtual void Tick(std::uint64_t delta, World* world) = 0;
void Upgrade(std::uint8_t level, TowerPath path) { void Upgrade(std::uint8_t level, TowerPath path) {
m_Level.SetLevel(level); m_Level.SetLevel(level);
m_Level.SetPath(path); m_Level.SetPath(path);
m_Timer.SetCooldown(GetStats()->GetDamageRate() * 1000); // converting seconds to millis m_Timer.SetCooldown(GetStats()->GetDamageRate() * 1000); // converting seconds to millis
m_Timer.Reset(); m_Timer.Reset();
SetRadius(GetStats()->GetRange()); SetRadius(GetStats()->GetRange());
} }
std::uint16_t GetID() const { return m_ID; } std::uint16_t GetID() const { return m_ID; }
const TowerLevel& GetLevel() const { return m_Level; } const TowerLevel& GetLevel() const { return m_Level; }
const TowerStats* GetStats() const { return GetTowerStats(m_Type, m_Level); } const TowerStats* GetStats() const { return GetTowerStats(m_Type, m_Level); }
PlayerID GetBuilder() const { return m_Builder; } PlayerID GetBuilder() const { return m_Builder; }
bool IsMobInRange(MobPtr mob); bool IsMobInRange(MobPtr mob);
}; };
typedef std::shared_ptr<Tower> TowerPtr; typedef std::shared_ptr<Tower> TowerPtr;
@@ -132,16 +132,17 @@ std::string GetTowerName(TowerType type);
class TowerInfo { class TowerInfo {
private: private:
std::string m_Name, m_Description; std::string m_Name, m_Description;
bool m_IsBigTower; bool m_IsBigTower;
public: public:
TowerInfo(std::string&& name, std::string&& description, bool big) : m_Name(std::move(name)), TowerInfo(std::string&& name, std::string&& description, bool big) : m_Name(std::move(name)),
m_Description(std::move(description)), m_IsBigTower(big) {} m_Description(std::move(description)), m_IsBigTower(big) {
}
const std::string& GetName() const { return m_Name; } const std::string& GetName() const { return m_Name; }
const std::string& GetDescription() const { return m_Description; } const std::string& GetDescription() const { return m_Description; }
bool IsBigTower() const { return m_IsBigTower; } bool IsBigTower() const { return m_IsBigTower; }
}; };
const TowerInfo& GetTowerInfo(TowerType type); const TowerInfo& GetTowerInfo(TowerType type);
@@ -150,115 +151,115 @@ const TowerInfo& GetTowerInfo(TowerType type);
class LittleTower : public Tower { class LittleTower : public Tower {
public: public:
LittleTower(TowerID id, TowerType type, std::uint16_t x, std::uint16_t y, PlayerID builder) : Tower(id, type, x, y, builder) {} LittleTower(TowerID id, TowerType type, std::uint16_t x, std::uint16_t y, PlayerID builder) : Tower(id, type, x, y, builder) {}
virtual TowerSize GetSize() const { return TowerSize::Little; } virtual TowerSize GetSize() const { return TowerSize::Little; }
virtual TowerType GetType() const = 0; virtual TowerType GetType() const = 0;
virtual void Tick(std::uint64_t delta, World* world) = 0; virtual void Tick(std::uint64_t delta, World* world) = 0;
}; };
class ArcherTower : public LittleTower { class ArcherTower : public LittleTower {
public: public:
ArcherTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {} ArcherTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {}
constexpr static float ExplosionRadius = 1.5f; constexpr static float ExplosionRadius = 1.5f;
constexpr static float FireDurationSec = 10.0f; constexpr static float FireDurationSec = 10.0f;
virtual TowerType GetType() const { return TowerType::Archer; } virtual TowerType GetType() const { return TowerType::Archer; }
virtual void Tick(std::uint64_t delta, World* world); virtual void Tick(std::uint64_t delta, World* world);
}; };
class IceTower : public LittleTower { class IceTower : public LittleTower {
public: public:
IceTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {} IceTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {}
virtual TowerType GetType() const { return TowerType::Ice; } virtual TowerType GetType() const { return TowerType::Ice; }
virtual void Tick(std::uint64_t delta, World* world); virtual void Tick(std::uint64_t delta, World* world);
}; };
class MageTower : public LittleTower { class MageTower : public LittleTower {
public: public:
MageTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {} MageTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {}
virtual TowerType GetType() const { return TowerType::Mage; } virtual TowerType GetType() const { return TowerType::Mage; }
virtual void Tick(std::uint64_t delta, World* world); virtual void Tick(std::uint64_t delta, World* world);
}; };
class PoisonTower : public LittleTower { class PoisonTower : public LittleTower {
public: public:
PoisonTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {} PoisonTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {}
virtual TowerType GetType() const { return TowerType::Poison; } virtual TowerType GetType() const { return TowerType::Poison; }
virtual void Tick(std::uint64_t delta, World* world); virtual void Tick(std::uint64_t delta, World* world);
}; };
class QuakeTower : public LittleTower { class QuakeTower : public LittleTower {
public: public:
QuakeTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {} QuakeTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {}
virtual TowerType GetType() const { return TowerType::Quake; } virtual TowerType GetType() const { return TowerType::Quake; }
virtual void Tick(std::uint64_t delta, World* world); virtual void Tick(std::uint64_t delta, World* world);
}; };
class ArtilleryTower : public LittleTower { class ArtilleryTower : public LittleTower {
public: public:
ArtilleryTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {} ArtilleryTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {}
virtual TowerType GetType() const { return TowerType::Artillery; } virtual TowerType GetType() const { return TowerType::Artillery; }
virtual void Tick(std::uint64_t delta, World* world); virtual void Tick(std::uint64_t delta, World* world);
}; };
class SorcererTower : public LittleTower { class SorcererTower : public LittleTower {
public: public:
SorcererTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {} SorcererTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {}
virtual TowerType GetType() const { return TowerType::Sorcerer; } virtual TowerType GetType() const { return TowerType::Sorcerer; }
virtual void Tick(std::uint64_t delta, World* world); virtual void Tick(std::uint64_t delta, World* world);
}; };
class ZeusTower : public LittleTower { class ZeusTower : public LittleTower {
public: public:
ZeusTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {} ZeusTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {}
virtual TowerType GetType() const { return TowerType::Zeus; } virtual TowerType GetType() const { return TowerType::Zeus; }
virtual void Tick(std::uint64_t delta, World* world); virtual void Tick(std::uint64_t delta, World* world);
}; };
// ---------- Big Towers ---------- // ---------- Big Towers ----------
class BigTower : public Tower { class BigTower : public Tower {
public: public:
BigTower(TowerID id, TowerType type, std::uint16_t x, std::uint16_t y, PlayerID builder) : Tower(id, type, x, y, builder) {} BigTower(TowerID id, TowerType type, std::uint16_t x, std::uint16_t y, PlayerID builder) : Tower(id, type, x, y, builder) {}
virtual TowerSize GetSize() const { return TowerSize::Big; } virtual TowerSize GetSize() const { return TowerSize::Big; }
virtual TowerType GetType() const = 0; virtual TowerType GetType() const = 0;
virtual void Tick(std::uint64_t delta, World* world) = 0; virtual void Tick(std::uint64_t delta, World* world) = 0;
}; };
class TurretTower : public BigTower { class TurretTower : public BigTower {
public: public:
TurretTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : BigTower(id, GetType(), x, y, builder) {} TurretTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : BigTower(id, GetType(), x, y, builder) {}
virtual TowerType GetType() const { return TowerType::Turret; } virtual TowerType GetType() const { return TowerType::Turret; }
virtual void Tick(std::uint64_t delta, World* world); virtual void Tick(std::uint64_t delta, World* world);
}; };
class NecromancerTower : public BigTower { class NecromancerTower : public BigTower {
public: public:
NecromancerTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : BigTower(id, GetType(), x, y, builder) {} NecromancerTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : BigTower(id, GetType(), x, y, builder) {}
virtual TowerType GetType() const { return TowerType::Necromancer; } virtual TowerType GetType() const { return TowerType::Necromancer; }
virtual void Tick(std::uint64_t delta, World* world); virtual void Tick(std::uint64_t delta, World* world);
}; };
class LeachTower : public BigTower { class LeachTower : public BigTower {
public: public:
LeachTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : BigTower(id, GetType(), x, y, builder) {} LeachTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : BigTower(id, GetType(), x, y, builder) {}
virtual TowerType GetType() const { return TowerType::Leach; } virtual TowerType GetType() const { return TowerType::Leach; }
virtual void Tick(std::uint64_t delta, World* world); virtual void Tick(std::uint64_t delta, World* world);
}; };
} // namespace game } // namespace game

View File

@@ -9,10 +9,10 @@ namespace td {
namespace game { namespace game {
enum class Direction : std::uint8_t { enum class Direction : std::uint8_t {
PositiveX = 1 << 0, PositiveX = 1 << 0,
NegativeX = 1 << 1, NegativeX = 1 << 1,
PositiveY = 1 << 2, PositiveY = 1 << 2,
NegativeY = 1 << 3, NegativeY = 1 << 3,
}; };
typedef std::uint8_t PlayerID; typedef std::uint8_t PlayerID;

View File

@@ -4,7 +4,6 @@
#include <vector> #include <vector>
#include <map> #include <map>
#include <unordered_map> #include <unordered_map>
#include <glm/glm.hpp>
#include <array> #include <array>
#include "Mobs.h" #include "Mobs.h"
@@ -14,11 +13,11 @@ namespace td {
namespace game { namespace game {
struct ChunkCoord { struct ChunkCoord {
std::int16_t x, y; std::int16_t x, y;
friend bool operator==(const td::game::ChunkCoord& first, const td::game::ChunkCoord& other) { friend bool operator==(const td::game::ChunkCoord& first, const td::game::ChunkCoord& other) {
return first.x == other.x && first.y == other.y; return first.x == other.x && first.y == other.y;
} }
}; };
@@ -29,9 +28,9 @@ struct ChunkCoord {
namespace std { namespace std {
template <> template <>
struct hash<td::game::ChunkCoord> { struct hash<td::game::ChunkCoord> {
std::size_t operator()(const td::game::ChunkCoord& key) const noexcept{ std::size_t operator()(const td::game::ChunkCoord& key) const noexcept {
return std::hash<std::int16_t>()(key.x << 16 | key.y); return std::hash<std::int16_t>()(key.x << 16 | key.y);
} }
}; };
} }
@@ -48,19 +47,15 @@ namespace game {
class Game; class Game;
enum class TileType : std::uint8_t { enum class TileType : std::uint8_t {
None = 0, None = 0,
Tower, Tower,
Walk, Walk,
Decoration, Decoration,
/*Heal, /*Heal,
Lava, Lava,
Bedrock, Bedrock,
Freeze, Freeze,
Ice,*/ Ice,*/
};
struct Color {
std::uint8_t r, g, b;
}; };
static constexpr Color BLACK{ 0, 0, 0 }; static constexpr Color BLACK{ 0, 0, 0 };
@@ -71,26 +66,26 @@ static constexpr Color GREEN{ 0, 255, 0 };
static constexpr Color BLUE{ 0, 0, 255 }; static constexpr Color BLUE{ 0, 0, 255 };
struct Tile { struct Tile {
virtual TileType GetType() const = 0; virtual TileType GetType() const = 0;
}; };
struct TowerTile : Tile { struct TowerTile : Tile {
std::uint8_t color_palette_ref; std::uint8_t color_palette_ref;
TeamColor team_owner; TeamColor team_owner;
virtual TileType GetType() const { return TileType::Tower; } virtual TileType GetType() const { return TileType::Tower; }
}; };
struct WalkableTile : Tile { struct WalkableTile : Tile {
Direction direction; Direction direction;
virtual TileType GetType() const { return TileType::Walk; } virtual TileType GetType() const { return TileType::Walk; }
}; };
struct DecorationTile : Tile { struct DecorationTile : Tile {
std::uint16_t color_palette_ref; std::uint16_t color_palette_ref;
virtual TileType GetType() const { return TileType::Decoration; } virtual TileType GetType() const { return TileType::Decoration; }
}; };
typedef std::shared_ptr<Tile> TilePtr; typedef std::shared_ptr<Tile> TilePtr;
@@ -102,19 +97,19 @@ typedef std::uint32_t TileIndex;
//32 x 32 area //32 x 32 area
struct Chunk { struct Chunk {
enum { ChunkWidth = 32, ChunkHeight = 32, ChunkSize = ChunkWidth * ChunkHeight }; enum { ChunkWidth = 32, ChunkHeight = 32, ChunkSize = ChunkWidth * ChunkHeight };
typedef std::array<std::uint16_t, ChunkSize> ChunkData; typedef std::array<std::uint16_t, ChunkSize> ChunkData;
// stores index of tile palette // stores index of tile palette
ChunkData tiles{ 0 }; ChunkData tiles{ 0 };
ChunkPalette palette; ChunkPalette palette;
TileIndex GetTileIndex(std::uint16_t tileNumber) const { TileIndex GetTileIndex(std::uint16_t tileNumber) const {
TileIndex chunkPaletteIndex = tiles.at(tileNumber); TileIndex chunkPaletteIndex = tiles.at(tileNumber);
if (chunkPaletteIndex == 0) // index 0 means empty tile index 1 = first tile if (chunkPaletteIndex == 0) // index 0 means empty tile index 1 = first tile
return 0; return 0;
return palette.at(chunkPaletteIndex); return palette.at(chunkPaletteIndex);
} }
}; };
typedef std::shared_ptr<Chunk> ChunkPtr; typedef std::shared_ptr<Chunk> ChunkPtr;
@@ -131,119 +126,119 @@ typedef std::vector<TowerPtr> TowerList;
class WorldListener { class WorldListener {
public: public:
WorldListener() {} WorldListener() {}
virtual void OnTowerAdd(TowerPtr tower) {} virtual void OnTowerAdd(TowerPtr tower) {}
virtual void OnTowerRemove(TowerPtr tower) {} virtual void OnTowerRemove(TowerPtr tower) {}
virtual void OnArcherTowerShot(MobPtr target, ArcherTower* shooter) {} virtual void OnArcherTowerShot(MobPtr target, ArcherTower* shooter) {}
virtual void OnArrowShot(MobPtr target, bool fire, Tower* shooter) {} virtual void OnArrowShot(MobPtr target, bool fire, Tower* shooter) {}
virtual void OnExplosion(utils::shape::Circle explosion, float centerDamage, Tower* shooter) {} virtual void OnExplosion(utils::shape::Circle explosion, float centerDamage, Tower* shooter) {}
}; };
typedef utils::ObjectNotifier<WorldListener> WorldNotifier; typedef utils::ObjectNotifier<WorldListener> WorldNotifier;
class World : public WorldListener, public MobListener { class World : public WorldListener, public MobListener {
protected: protected:
TowerTileColorPalette m_TowerPlacePalette; TowerTileColorPalette m_TowerPlacePalette;
Color m_WalkablePalette; Color m_WalkablePalette;
std::vector<Color> m_DecorationPalette; std::vector<Color> m_DecorationPalette;
Color m_Background; Color m_Background;
std::unordered_map<ChunkCoord, ChunkPtr> m_Chunks; std::unordered_map<ChunkCoord, ChunkPtr> m_Chunks;
SpawnColorPalette m_SpawnColorPalette; SpawnColorPalette m_SpawnColorPalette;
TilePalette m_TilePalette; TilePalette m_TilePalette;
MobList m_Mobs; MobList m_Mobs;
TowerList m_Towers; TowerList m_Towers;
Game* m_Game; Game* m_Game;
WorldNotifier m_WorldNotifier; WorldNotifier m_WorldNotifier;
MobNotifier m_MobNotifier; MobNotifier m_MobNotifier;
public: public:
World(Game* game); World(Game* game);
bool LoadMap(const protocol::WorldBeginDataPacket* worldHeader); bool LoadMap(const protocol::WorldBeginDataPacket* worldHeader);
bool LoadMap(const protocol::WorldDataPacket* worldData); bool LoadMap(const protocol::WorldDataPacket* worldData);
bool LoadMapFromFile(const std::string& fileName); bool LoadMapFromFile(const std::string& fileName);
bool SaveMap(const std::string& fileName) const; bool SaveMap(const std::string& fileName) const;
void Tick(std::uint64_t delta); void Tick(std::uint64_t delta);
void SpawnMobAt(MobID id, MobType type, std::uint8_t level, PlayerID sender, float x, float y, Direction dir); void SpawnMobAt(MobID id, MobType type, std::uint8_t level, PlayerID sender, float x, float y, Direction dir);
TowerPtr PlaceTowerAt(TowerID id, TowerType type, std::int32_t x, std::int32_t y, PlayerID builder); TowerPtr PlaceTowerAt(TowerID id, TowerType type, std::int32_t x, std::int32_t y, PlayerID builder);
TowerPtr RemoveTower(TowerID id); TowerPtr RemoveTower(TowerID id);
TilePtr GetTile(std::int32_t x, std::int32_t y) const; TilePtr GetTile(std::int32_t x, std::int32_t y) const;
const TowerTileColorPalette& GetTowerTileColorPalette() const { return m_TowerPlacePalette; } const TowerTileColorPalette& GetTowerTileColorPalette() const { return m_TowerPlacePalette; }
const Color& GetWalkableTileColor() const { return m_WalkablePalette; } const Color& GetWalkableTileColor() const { return m_WalkablePalette; }
const std::vector<Color>& GetDecorationPalette() const { return m_DecorationPalette; } const std::vector<Color>& GetDecorationPalette() const { return m_DecorationPalette; }
const Color& GetBackgroundColor() const { return m_Background; } const Color& GetBackgroundColor() const { return m_Background; }
const TilePalette& GetTilePalette() const { return m_TilePalette; } const TilePalette& GetTilePalette() const { return m_TilePalette; }
TilePtr GetTilePtr(TileIndex index) const { TilePtr GetTilePtr(TileIndex index) const {
if (index == 0) if (index == 0)
return nullptr; return nullptr;
return m_TilePalette.at(index - 1); return m_TilePalette.at(index - 1);
} }
bool CanPlaceLittleTower(const glm::vec2& worldPos, PlayerID player) const; bool CanPlaceLittleTower(const Vec2f& worldPos, PlayerID player) const;
bool CanPlaceBigTower(const glm::vec2& worldPos, PlayerID player) const; bool CanPlaceBigTower(const Vec2f& worldPos, PlayerID player) const;
TowerPtr GetTower(const glm::vec2& position) const; // returns null if no tower is here TowerPtr GetTower(const Vec2f& position) const; // returns null if no tower is here
const std::unordered_map<ChunkCoord, ChunkPtr>& GetChunks() const { return m_Chunks; } const std::unordered_map<ChunkCoord, ChunkPtr>& GetChunks() const { return m_Chunks; }
const Color& GetSpawnColor(TeamColor color) const { return m_SpawnColorPalette[static_cast<std::size_t>(color)]; } const Color& GetSpawnColor(TeamColor color) const { return m_SpawnColorPalette[static_cast<std::size_t>(color)]; }
const SpawnColorPalette& GetSpawnColors() const { return m_SpawnColorPalette; } const SpawnColorPalette& GetSpawnColors() const { return m_SpawnColorPalette; }
const MobList& GetMobList() const { return m_Mobs; } const MobList& GetMobList() const { return m_Mobs; }
MobList& GetMobList() { return m_Mobs; } MobList& GetMobList() { return m_Mobs; }
const Color* GetTileColor(TilePtr tile) const; const Color* GetTileColor(TilePtr tile) const;
Team& GetRedTeam(); Team& GetRedTeam();
const Team& GetRedTeam() const; const Team& GetRedTeam() const;
Team& GetBlueTeam(); Team& GetBlueTeam();
const Team& GetBlueTeam() const; const Team& GetBlueTeam() const;
Team& GetTeam(TeamColor team); Team& GetTeam(TeamColor team);
const Team& GetTeam(TeamColor team) const; const Team& GetTeam(TeamColor team) const;
const TeamList& GetTeams() const; const TeamList& GetTeams() const;
const TowerList& GetTowers() const { return m_Towers; } const TowerList& GetTowers() const { return m_Towers; }
TowerPtr GetTowerById(TowerID tower); TowerPtr GetTowerById(TowerID tower);
const Player* GetPlayerById(PlayerID id) const; const Player* GetPlayerById(PlayerID id) const;
WorldNotifier& GetWorldNotifier() { return m_WorldNotifier; } WorldNotifier& GetWorldNotifier() { return m_WorldNotifier; }
MobNotifier& GetMobNotifier() { return m_MobNotifier; } MobNotifier& GetMobNotifier() { return m_MobNotifier; }
// WorldListener // WorldListener
virtual void OnArcherTowerShot(MobPtr target, ArcherTower* shooter) override; virtual void OnArcherTowerShot(MobPtr target, ArcherTower* shooter) override;
virtual void OnArrowShot(MobPtr target, bool fire, Tower* shooter) override; virtual void OnArrowShot(MobPtr target, bool fire, Tower* shooter) override;
virtual void OnExplosion(utils::shape::Circle explosion, float centerDamage, Tower* shooter) override; virtual void OnExplosion(utils::shape::Circle explosion, float centerDamage, Tower* shooter) override;
// MobListener // MobListener
virtual void OnMobDamage(Mob* target, float damage, Tower* source) override; virtual void OnMobDamage(Mob* target, float damage, Tower* source) override;
virtual void OnMobCastleDamage(Mob* damager, TeamCastle* enemyCastle, float damage) override; virtual void OnMobCastleDamage(Mob* damager, TeamCastle* enemyCastle, float damage) override;
private: private:
void TickMobs(std::uint64_t delta); void TickMobs(std::uint64_t delta);
void CleanDeadMobs(); void CleanDeadMobs();
}; };
} // namespace game } // namespace game

View File

@@ -17,38 +17,38 @@ namespace client {
class Client { class Client {
private: private:
render::Renderer* m_Renderer; render::Renderer* m_Renderer;
ClientConnexion m_Connexion; ClientConnexion m_Connexion;
std::unique_ptr<ClientGame> m_Game; std::unique_ptr<ClientGame> m_Game;
bool m_Connected; bool m_Connected;
public: public:
Client(render::Renderer* renderer) : m_Renderer(renderer), m_Game(std::make_unique<ClientGame>(this)), m_Connected(false) {} Client(render::Renderer* renderer) : m_Renderer(renderer), m_Game(std::make_unique<ClientGame>(this)), m_Connected(false) {}
const ClientGame& GetGame() const { return *m_Game; } const ClientGame& GetGame() const { return *m_Game; }
const ClientConnexion& GetConnexion() const { return m_Connexion; } const ClientConnexion& GetConnexion() const { return m_Connexion; }
render::Renderer* GetRenderer() const { return m_Renderer; } render::Renderer* GetRenderer() const { return m_Renderer; }
ClientGame& GetGame() { return *m_Game; } ClientGame& GetGame() { return *m_Game; }
ClientConnexion& GetConnexion() { return m_Connexion; } ClientConnexion& GetConnexion() { return m_Connexion; }
const game::Player* GetPlayer() { return m_Game->GetPlayer(); } const game::Player* GetPlayer() { return m_Game->GetPlayer(); }
void Tick(std::uint64_t delta); void Tick(std::uint64_t delta);
void Render(); void Render();
bool Connect(const network::IPAddresses& addresses, std::uint16_t port); bool Connect(const network::IPAddresses& addresses, std::uint16_t port);
void CloseConnection(); void CloseConnection();
bool IsConnected() const { return m_Connexion.GetSocketStatus() == network::Socket::Connected; } bool IsConnected() const { return m_Connexion.GetSocketStatus() == network::Socket::Connected; }
void SelectTeam(game::TeamColor team); void SelectTeam(game::TeamColor team);
void SendMobs(const std::vector<protocol::MobSend>& mobSends); void SendMobs(const std::vector<protocol::MobSend>& mobSends);
void PlaceTower(game::TowerType type, const glm::vec2& position); void PlaceTower(game::TowerType type, const Vec2f& position);
void UpgradeTower(game::TowerID tower, game::TowerLevel level); void UpgradeTower(game::TowerID tower, game::TowerLevel level);
void RemoveTower(game::TowerID tower); void RemoveTower(game::TowerID tower);
private: private:
void Reset(); void Reset();
}; };
} // namespace client } // namespace client

View File

@@ -9,28 +9,30 @@ namespace client {
class ClientConnexion : public protocol::Connexion { class ClientConnexion : public protocol::Connexion {
private: private:
std::uint8_t m_ConnectionID; std::uint8_t m_ConnectionID;
std::string m_DisconnectReason; std::string m_DisconnectReason;
float m_ServerTPS; float m_ServerTPS;
int m_Ping = 0; float m_ServerMSPT;
int m_Ping = 0;
public: public:
ClientConnexion(); ClientConnexion();
virtual bool UpdateSocket(); virtual bool UpdateSocket();
virtual void HandlePacket(const protocol::KeepAlivePacket* packet) override; virtual void HandlePacket(const protocol::KeepAlivePacket* packet) override;
virtual void HandlePacket(const protocol::ConnexionInfoPacket* packet) override; virtual void HandlePacket(const protocol::ConnexionInfoPacket* packet) override;
virtual void HandlePacket(const protocol::DisconnectPacket* packet) override; virtual void HandlePacket(const protocol::DisconnectPacket* packet) override;
virtual void HandlePacket(const protocol::ServerTpsPacket* packet) override; virtual void HandlePacket(const protocol::ServerTpsPacket* packet) override;
const std::string& GetDisconnectReason() const { return m_DisconnectReason; } const std::string& GetDisconnectReason() const { return m_DisconnectReason; }
float GetServerTPS() const { return m_ServerTPS; } float GetServerTPS() const { return m_ServerTPS; }
int GetServerPing() const { return m_Ping; } float GetServerMSPT() const { return m_ServerMSPT; }
int GetServerPing() const { return m_Ping; }
REMOVE_COPY(ClientConnexion); REMOVE_COPY(ClientConnexion);
private: private:
void RegisterHandlers(); void RegisterHandlers();
void Login(); void Login();
}; };
} // namespace client } // namespace client

View File

@@ -16,40 +16,40 @@ class Client;
class ClientGame : public protocol::PacketHandler, public game::Game { class ClientGame : public protocol::PacketHandler, public game::Game {
private: private:
Client* m_Client; Client* m_Client;
std::uint8_t m_ConnexionID; std::uint8_t m_ConnexionID;
std::uint32_t m_LobbyTime = 0; std::uint32_t m_LobbyTime = 0;
game::Player* m_Player = nullptr; game::Player* m_Player = nullptr;
render::Renderer* m_Renderer; render::Renderer* m_Renderer;
client::WorldClient m_WorldClient; client::WorldClient m_WorldClient;
render::WorldRenderer m_WorldRenderer; render::WorldRenderer m_WorldRenderer;
public: public:
ClientGame(Client* client); ClientGame(Client* client);
virtual ~ClientGame(); virtual ~ClientGame();
virtual void Tick(std::uint64_t delta); virtual void Tick(std::uint64_t delta);
void RenderWorld(); void RenderWorld();
std::uint32_t GetLobbyTime() const { return m_LobbyTime; } std::uint32_t GetLobbyTime() const { return m_LobbyTime; }
const game::Player* GetPlayer() const { return m_Player; } const game::Player* GetPlayer() const { return m_Player; }
const WorldClient& GetWorld() const { return m_WorldClient; } const WorldClient& GetWorld() const { return m_WorldClient; }
Client* GetClient() const { return m_Client; } Client* GetClient() const { return m_Client; }
render::Renderer* GetRenderer() const { return m_Renderer; } render::Renderer* GetRenderer() const { return m_Renderer; }
WorldClient& GetWorldClient() { return m_WorldClient; } WorldClient& GetWorldClient() { return m_WorldClient; }
virtual void HandlePacket(const protocol::ConnexionInfoPacket* packet) override; virtual void HandlePacket(const protocol::ConnexionInfoPacket* packet) override;
virtual void HandlePacket(const protocol::PlayerJoinPacket* packet) override; virtual void HandlePacket(const protocol::PlayerJoinPacket* packet) override;
virtual void HandlePacket(const protocol::PlayerLeavePacket* packet) override; virtual void HandlePacket(const protocol::PlayerLeavePacket* packet) override;
virtual void HandlePacket(const protocol::PlayerListPacket* packet) override; virtual void HandlePacket(const protocol::PlayerListPacket* packet) override;
virtual void HandlePacket(const protocol::UpdatePlayerTeamPacket* packet) override; virtual void HandlePacket(const protocol::UpdatePlayerTeamPacket* packet) override;
virtual void HandlePacket(const protocol::UpdateGameStatePacket* packet) override; virtual void HandlePacket(const protocol::UpdateGameStatePacket* packet) override;
virtual void HandlePacket(const protocol::UpdateLobbyTimePacket* packet) override; virtual void HandlePacket(const protocol::UpdateLobbyTimePacket* packet) override;
virtual void HandlePacket(const protocol::UpdateMoneyPacket* packet) override; virtual void HandlePacket(const protocol::UpdateMoneyPacket* packet) override;
virtual void HandlePacket(const protocol::UpdateExpPacket* packet) override; virtual void HandlePacket(const protocol::UpdateExpPacket* packet) override;
virtual void HandlePacket(const protocol::DisconnectPacket* packet) override; virtual void HandlePacket(const protocol::DisconnectPacket* packet) override;
virtual void HandlePacket(const protocol::WorldDataPacket* packet) override; virtual void HandlePacket(const protocol::WorldDataPacket* packet) override;
}; };

View File

@@ -10,18 +10,18 @@ class ClientGame;
class WorldClient : public game::World, public protocol::PacketHandler { class WorldClient : public game::World, public protocol::PacketHandler {
private: private:
ClientGame* m_Game; ClientGame* m_Game;
public: public:
WorldClient(ClientGame* game); WorldClient(ClientGame* game);
virtual void HandlePacket(const protocol::WorldBeginDataPacket* packet) override; virtual void HandlePacket(const protocol::WorldBeginDataPacket* packet) override;
virtual void HandlePacket(const protocol::WorldDataPacket* packet) override; virtual void HandlePacket(const protocol::WorldDataPacket* packet) override;
virtual void HandlePacket(const protocol::SpawnMobPacket* packet) override; virtual void HandlePacket(const protocol::SpawnMobPacket* packet) override;
virtual void HandlePacket(const protocol::UpgradeTowerPacket* packet) override; virtual void HandlePacket(const protocol::UpgradeTowerPacket* packet) override;
virtual void HandlePacket(const protocol::WorldAddTowerPacket* packet) override; virtual void HandlePacket(const protocol::WorldAddTowerPacket* packet) override;
virtual void HandlePacket(const protocol::RemoveTowerPacket* packet) override; virtual void HandlePacket(const protocol::RemoveTowerPacket* packet) override;
virtual void HandlePacket(const protocol::UpdateMobStatesPacket* packet) override; virtual void HandlePacket(const protocol::UpdateMobStatesPacket* packet) override;
virtual void HandlePacket(const protocol::UpdateCastleLifePacket* packet) override; virtual void HandlePacket(const protocol::UpdateCastleLifePacket* packet) override;
}; };

View File

@@ -11,23 +11,23 @@ class Server;
class Lobby { class Lobby {
private: private:
Server* m_Server; Server* m_Server;
bool m_GameStarted = false; bool m_GameStarted = false;
std::uint64_t m_StartTimerTime = 0; std::uint64_t m_StartTimerTime = 0;
std::vector<std::uint8_t> m_Players; std::vector<std::uint8_t> m_Players;
utils::AutoTimer m_Timer; utils::AutoTimer m_Timer;
public: public:
Lobby(Server* server); Lobby(Server* server);
void OnPlayerJoin(std::uint8_t playerID); void OnPlayerJoin(std::uint8_t playerID);
void OnPlayerLeave(std::uint8_t playerID); void OnPlayerLeave(std::uint8_t playerID);
void SendTimeRemaining(); void SendTimeRemaining();
void Tick(); void Tick();
//static constexpr int LobbyWaitingTime = 2 * 60 * 1000; // in millis //static constexpr int LobbyWaitingTime = 2 * 60 * 1000; // in millis
static constexpr int LobbyWaitingTime = 5 * 1000; // in millis static constexpr int LobbyWaitingTime = 5 * 1000; // in millis
}; };
} // namespace server } // namespace server

View File

@@ -21,80 +21,84 @@ typedef std::map<std::uint8_t, ServerConnexion> ConnexionMap;
class TickCounter { class TickCounter {
private: private:
float m_TPS; float m_TPS;
std::uint64_t m_LastTPSTime; float m_MSPT;
std::uint8_t m_TickCount; std::uint64_t m_LastTPSTime;
std::uint8_t m_TickCount;
public: public:
TickCounter() {} TickCounter() {}
void Reset() { void Reset() {
m_TPS = SERVER_TPS; m_TPS = SERVER_TPS;
m_LastTPSTime = utils::GetTime(); m_LastTPSTime = utils::GetTime();
m_TickCount = 0; m_TickCount = 0;
} }
bool Update() { // return true when tps is updated bool Update() { // return true when tps is updated
m_TickCount++; m_TickCount++;
if (m_TickCount >= SERVER_TPS) { if (m_TickCount >= SERVER_TPS) {
std::uint64_t timeElapsedSinceLast20Ticks = td::utils::GetTime() - m_LastTPSTime; std::uint64_t timeElapsedSinceLast20Ticks = td::utils::GetTime() - m_LastTPSTime;
m_TPS = static_cast<float>(SERVER_TPS) / static_cast<float>(timeElapsedSinceLast20Ticks / 1000.0f); m_TPS = static_cast<float>(SERVER_TPS) / static_cast<float>(timeElapsedSinceLast20Ticks / 1000.0f);
m_TickCount = 0; m_TickCount = 0;
m_LastTPSTime = td::utils::GetTime(); m_LastTPSTime = td::utils::GetTime();
return true; return true;
} }
return false; return false;
} }
float GetTPS() const { return m_TPS; } float GetTPS() const { return m_TPS; }
float GetMSPT() const { return m_MSPT; }
void SetMSPT(float mspt) { m_MSPT = mspt; }
}; };
class Server { class Server {
private: private:
network::TCPListener m_Listener; network::TCPListener m_Listener;
ConnexionMap m_Connections; ConnexionMap m_Connections;
ServerGame m_Game{ this }; ServerGame m_Game{ this };
Lobby m_Lobby{ this }; Lobby m_Lobby{ this };
TickCounter m_TickCounter; TickCounter m_TickCounter;
std::thread m_Thread; std::thread m_Thread;
bool m_ServerRunning; bool m_ServerRunning;
public: public:
Server(const std::string& worldFilePath); Server(const std::string& worldFilePath);
virtual ~Server(); virtual ~Server();
bool Start(std::uint16_t port); bool Start(std::uint16_t port);
void Stop(); // force the server to stop void Stop(); // force the server to stop
void Close(); // at the end of a game void Close(); // at the end of a game
void RemoveConnexion(std::uint8_t connexionID); void RemoveConnexion(std::uint8_t connexionID);
void BroadcastPacket(const protocol::Packet* packet); void BroadcastPacket(const protocol::Packet* packet);
float GetTPS() const { return m_TickCounter.GetTPS(); } float GetTPS() const { return m_TickCounter.GetTPS(); }
bool IsRunning() { return m_ServerRunning; } bool IsRunning() { return m_ServerRunning; }
const ServerGame& GetGame() const { return m_Game; } const ServerGame& GetGame() const { return m_Game; }
ServerGame& GetGame() { return m_Game; } ServerGame& GetGame() { return m_Game; }
const Lobby& GetLobby() const { return m_Lobby; } const Lobby& GetLobby() const { return m_Lobby; }
const ConnexionMap& GetConnexions() const { return m_Connections; } const ConnexionMap& GetConnexions() const { return m_Connections; }
ConnexionMap& GetConnexions() { return m_Connections; } ConnexionMap& GetConnexions() { return m_Connections; }
const game::PlayerList& GetPlayers() const { return m_Game.GetPlayers(); } const game::PlayerList& GetPlayers() const { return m_Game.GetPlayers(); }
game::PlayerList& GetPlayers() { return m_Game.GetPlayers(); } game::PlayerList& GetPlayers() { return m_Game.GetPlayers(); }
private: private:
void Accept(); void Accept();
void UpdateSockets(); void UpdateSockets();
void Clean(); void Clean();
void StartThread(); void StartThread();
void StopThread(); void StopThread();
void Tick(std::uint64_t delta); void Tick(std::uint64_t delta);
void OnPlayerJoin(std::uint8_t id); void OnPlayerJoin(std::uint8_t id);
void OnPlayerLeave(std::uint8_t id); void OnPlayerLeave(std::uint8_t id);
}; };
} // namespace server } // namespace server

View File

@@ -11,49 +11,48 @@ namespace server {
class Server; class Server;
struct KeepAlive struct KeepAlive {
{ std::uint64_t keepAliveID = 0;
std::uint64_t keepAliveID = 0; std::uint64_t sendTime;
std::uint64_t sendTime; bool recievedResponse = false;
bool recievedResponse = false;
}; };
class ServerConnexion : public protocol::Connexion { class ServerConnexion : public protocol::Connexion {
private: private:
Server* m_Server = nullptr; Server* m_Server = nullptr;
std::uint8_t m_ID; std::uint8_t m_ID;
KeepAlive m_KeepAlive; KeepAlive m_KeepAlive;
game::Player* m_Player; game::Player* m_Player;
public: public:
ServerConnexion(); ServerConnexion();
ServerConnexion(network::TCPSocket& socket, std::uint8_t id); ServerConnexion(network::TCPSocket& socket, std::uint8_t id);
ServerConnexion(ServerConnexion&& move); ServerConnexion(ServerConnexion&& move);
virtual ~ServerConnexion(); virtual ~ServerConnexion();
void SetServer(Server* server); void SetServer(Server* server);
virtual void HandlePacket(const protocol::PlayerLoginPacket* packet) override; virtual void HandlePacket(const protocol::PlayerLoginPacket* packet) override;
virtual void HandlePacket(const protocol::KeepAlivePacket* packet) override; virtual void HandlePacket(const protocol::KeepAlivePacket* packet) override;
virtual void HandlePacket(const protocol::SelectTeamPacket* packet) override; virtual void HandlePacket(const protocol::SelectTeamPacket* packet) override;
virtual void HandlePacket(const protocol::DisconnectPacket* packet) override; virtual void HandlePacket(const protocol::DisconnectPacket* packet) override;
virtual void HandlePacket(const protocol::PlaceTowerPacket* packet) override; virtual void HandlePacket(const protocol::PlaceTowerPacket* packet) override;
virtual void HandlePacket(const protocol::SendMobsPacket* packet) override; virtual void HandlePacket(const protocol::SendMobsPacket* packet) override;
virtual void HandlePacket(const protocol::UpgradeTowerPacket* packet) override; virtual void HandlePacket(const protocol::UpgradeTowerPacket* packet) override;
virtual void HandlePacket(const protocol::RemoveTowerPacket* packet) override; virtual void HandlePacket(const protocol::RemoveTowerPacket* packet) override;
std::uint8_t GetID() const { return m_ID; } std::uint8_t GetID() const { return m_ID; }
const game::Player* GetPlayer() const { return m_Player; } const game::Player* GetPlayer() const { return m_Player; }
game::Player* GetPlayer() { return m_Player; } game::Player* GetPlayer() { return m_Player; }
virtual bool UpdateSocket(); virtual bool UpdateSocket();
REMOVE_COPY(ServerConnexion); REMOVE_COPY(ServerConnexion);
private: private:
void RegisterHandlers(); void RegisterHandlers();
void CheckKeepAlive(); void CheckKeepAlive();
void SendKeepAlive(); void SendKeepAlive();
void InitConnection(); void InitConnection();
}; };
} // namespace server } // namespace server

View File

@@ -11,32 +11,32 @@ class Server;
class ServerGame : public game::Game, public game::GameListener { class ServerGame : public game::Game, public game::GameListener {
private: private:
Server* m_Server; Server* m_Server;
ServerWorld m_ServerWorld; ServerWorld m_ServerWorld;
utils::AutoTimer m_GoldMineTimer; utils::AutoTimer m_GoldMineTimer;
utils::AutoTimer m_MobStatesTimer; utils::AutoTimer m_MobStatesTimer;
utils::CooldownTimer m_EndGameCooldown; utils::CooldownTimer m_EndGameCooldown;
public: public:
ServerGame(Server* server); ServerGame(Server* server);
~ServerGame() {} ~ServerGame() {}
ServerWorld* GetServerWorld() { return &m_ServerWorld; } ServerWorld* GetServerWorld() { return &m_ServerWorld; }
virtual void Tick(std::uint64_t delta); virtual void Tick(std::uint64_t delta);
void StartGame(); void StartGame();
// GameListener // GameListener
virtual void OnGameStateUpdate(game::GameState newState) override; virtual void OnGameStateUpdate(game::GameState newState) override;
virtual void OnGameBegin() override; virtual void OnGameBegin() override;
virtual void OnGameEnd() override; virtual void OnGameEnd() override;
virtual void OnGameClose() override; virtual void OnGameClose() override;
private: private:
void BalanceTeams(); void BalanceTeams();
void InitPlayerStats(); void InitPlayerStats();
void UpdateMobStates(); void UpdateMobStates();
void UpdateGoldMines(); void UpdateGoldMines();
void UpdatePlayerStats(); void UpdatePlayerStats();
}; };
} // namespace game } // namespace game

View File

@@ -10,19 +10,19 @@ class ServerGame;
class ServerWorld : public game::World { class ServerWorld : public game::World {
private: private:
game::MobID m_CurrentMobID; game::MobID m_CurrentMobID;
game::TowerID m_CurrentTowerID; game::TowerID m_CurrentTowerID;
Server* m_Server; Server* m_Server;
public: public:
static constexpr float MobSpawnBorder = 0.01f; static constexpr float MobSpawnBorder = 0.01f;
ServerWorld(Server* server, ServerGame* game); ServerWorld(Server* server, ServerGame* game);
void SpawnMobs(game::MobType type, std::uint8_t level, game::PlayerID sender, std::uint8_t count); void SpawnMobs(game::MobType type, std::uint8_t level, game::PlayerID sender, std::uint8_t count);
game::TowerPtr PlaceTowerAt(game::TowerType type, std::int32_t x, std::int32_t y, game::PlayerID builder); game::TowerPtr PlaceTowerAt(game::TowerType type, std::int32_t x, std::int32_t y, game::PlayerID builder);
virtual void OnMobDie(game::Mob* mob) override; virtual void OnMobDie(game::Mob* mob) override;
virtual void OnMobCastleDamage(game::Mob* damager, game::TeamCastle* enemyCastle, float damage) override; virtual void OnMobCastleDamage(game::Mob* damager, game::TeamCastle* enemyCastle, float damage) override;
}; };

View File

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

View File

@@ -6,15 +6,15 @@
namespace td { namespace td {
namespace utils { namespace utils {
template <typename... Args> template <typename... Args>
std::string format(const std::string& format, Args... args){ std::string format(const std::string& format, Args... args) {
int size = snprintf(nullptr, 0, format.c_str(), args...) + 1; // Extra space for '\0' int size = snprintf(nullptr, 0, format.c_str(), args...) + 1; // Extra space for '\0'
if (size <= 0){ if (size <= 0) {
throw std::runtime_error("Error during formatting."); throw std::runtime_error("Error during formatting.");
} }
std::unique_ptr<char[]> buf(new char[size]); std::unique_ptr<char[]> buf(new char[size]);
snprintf(buf.get(), size, format.c_str(), args...); snprintf(buf.get(), static_cast<std::size_t>(size), format.c_str(), args...);
return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside
} }

177
include/misc/Maths.h Normal file
View File

@@ -0,0 +1,177 @@
#pragma once
#include "Defines.h"
#include <cmath>
namespace td {
//////////////////////////////////////////////////////////////////
// Operators //
//////////////////////////////////////////////////////////////////
template<typename T>
Vec2<T> operator+(const Vec2<T>& vect, const Vec2<T>& other) {
return {vect.x + other.x, vect.y + other.y};
}
template<typename T>
Vec2<T> operator- (const Vec2<T>& vect) {
return { -vect.x, -vect.y };
}
template<typename T>
Vec2<T> operator- (const Vec2<T>& vect, const Vec2<T>& other) {
return vect + (-other);
}
template<typename T>
Vec3<T> operator- (const Vec3<T>& vect) {
return { -vect.x, -vect.y, -vect.z };
}
template<typename T>
Vec3<T> operator+ (const Vec3<T>& vect, const Vec3<T>& other) {
return { vect.x + other.x, vect.y + other.y, vect.z + other.y };
}
template<typename T>
Vec3<T> operator- (const Vec3<T>& vect, const Vec3<T>& other) {
return vect + (-other);
}
template<typename T>
Vec4<T> operator- (const Vec4<T>& vect) {
return { -vect.x, -vect.y, -vect.z, -vect.w };
}
template<typename T>
Vec4<T> operator+ (const Vec4<T>& vect, const Vec4<T>& other) {
return { vect.x + other.x, vect.y + other.y, vect.z + other.y, vect.w + other.w };
}
template<typename T>
Vec4<T> operator- (const Vec4<T>& vect, const Vec4<T>& other) {
return vect + (-other);
}
//////////////////////////////////////////////////////////////////
// Vectors //
//////////////////////////////////////////////////////////////////
namespace maths {
template<typename T>
T Length(const Vec3<T>& vect) {
return std::sqrt(vect.x * vect.x + vect.y * vect.y + vect.z * vect.z);
}
template<typename T>
Vec3<T> Normalize(const Vec3<T>& vect) {
T length = Length(vect);
return { vect.x / length, vect.y / length, vect.z / length };
}
template<typename T>
Vec4<T> Normalize(const Vec4<T>& vect) {
T length = std::sqrt(vect.x * vect.x + vect.y * vect.y + vect.z * vect.z + vect.w * vect.w);
return { vect.x / length, vect.y / length, vect.z / length, vect.w / length };
}
template<typename T>
T Dot(const Vec3<T>& vect, const Vec3<T>& other) {
return vect.x * other.x + vect.y * other.y + vect.z * other.z;
}
template<typename T>
Vec3<T> Cross(const Vec3<T>& vect, const Vec3<T>& other) {
return {
vect.y * other.z - vect.z * other.y,
vect.z * other.x - vect.x * other.z,
vect.x * other.y - vect.y * other.x,
};
}
template<typename T>
T Dot(const Vec4<T>& vect, const Vec4<T>& other) {
return vect.x * other.x + vect.y * other.y + vect.z * other.z + vect.w * other.w;
}
template<typename T>
T Distance(const Vec3<T>& vect, const Vec3<T>& other) {
return Length(vect - other);
}
//////////////////////////////////////////////////////////////////
// Matricies //
//////////////////////////////////////////////////////////////////
template<typename T>
Vec4<T> Dot(const Mat4<T>& mat, const Vec4<T>& vect) {
return {
mat.x0 * vect.x + mat.x1 * vect.y + mat.x2 * vect.z + mat.x3 * vect.w,
mat.y0 * vect.x + mat.y1 * vect.y + mat.y2 * vect.z + mat.y3 * vect.w,
mat.z0 * vect.x + mat.z1 * vect.y + mat.z2 * vect.z + mat.z3 * vect.w,
mat.w0 * vect.x + mat.w1 * vect.y + mat.w2 * vect.z + mat.w3 * vect.w
};
}
template<typename T>
Mat4<T> Dot(const Mat4<T>& mat, const Mat4<T>& other) {
Mat4<T> result {};
for (std::size_t i = 0; i < Mat4<T>::MATRIX_SIZE; i++) {
for (std::size_t j = 0; j < Mat4<T>::MATRIX_SIZE; j++) {
for (std::size_t k = 0; k < Mat4<T>::MATRIX_SIZE; k++) {
result.at(i, j) += mat.at(i, k) * other.at(k, j);
}
}
}
return result;
}
template<typename T>
Mat4<T> Identity() {
Mat4<T> result{};
result.x0 = static_cast<T>(1);
result.y1 = static_cast<T>(1);
result.z2 = static_cast<T>(1);
result.w3 = static_cast<T>(1);
return result;
}
template<typename T>
Mat4<T> Transpose(const Mat4<T>& mat) {
Mat4<T> result;
result.x1 = mat.y0;
result.x2 = mat.z0;
result.x3 = mat.w0;
result.y0 = mat.x1;
result.y2 = mat.z1;
result.y3 = mat.w1;
result.z0 = mat.x2;
result.z1 = mat.y2;
result.z3 = mat.w2;
result.w0 = mat.x3;
result.w1 = mat.y3;
result.w2 = mat.z3;
result.x0 = mat.x0;
result.y1 = mat.y1;
result.z2 = mat.z2;
result.w3 = mat.w3;
return result;
}
Mat4f Perspective(float fovY, float aspectRatio, float zNear, float zFar);
Mat4f Look(const Vec3f& eye, const Vec3f& center, const Vec3f& up);
Mat4f Inverse(const Mat4f& mat);
} // namespace maths
} // namespace td

View File

@@ -10,26 +10,26 @@ namespace utils {
template <typename Listener> template <typename Listener>
class ObjectNotifier { class ObjectNotifier {
protected: protected:
std::vector<Listener*> m_Listeners; std::vector<Listener*> m_Listeners;
public: public:
void BindListener(Listener* listener) { void BindListener(Listener* listener) {
m_Listeners.push_back(listener); m_Listeners.push_back(listener);
} }
void UnbindListener(Listener* listener) { void UnbindListener(Listener* listener) {
auto iter = std::find(m_Listeners.begin(), m_Listeners.end(), listener); auto iter = std::find(m_Listeners.begin(), m_Listeners.end(), listener);
if (iter == m_Listeners.end()) return; if (iter == m_Listeners.end()) return;
m_Listeners.erase(iter); m_Listeners.erase(iter);
} }
template <typename Func, typename... Args> template <typename Func, typename... Args>
void NotifyListeners(Func function, Args... args) { void NotifyListeners(Func function, Args... args) {
for (Listener* listener : m_Listeners) for (Listener* listener : m_Listeners)
std::bind(function, listener, args...)(); std::bind(function, listener, args...)();
} }
}; };
} // namespace utils } // namespace utils

View File

@@ -4,49 +4,49 @@ namespace td {
namespace utils { namespace utils {
enum class Os { enum class Os {
Windows = 0, Windows = 0,
Linux, Linux,
Android, Android,
Unknown, Unknown,
}; };
enum class Architecture { enum class Architecture {
x86_64 = 0, x86_64 = 0,
x86, x86,
Arm64, Arm64,
Armhf, Armhf,
Unknown, Unknown,
}; };
inline Os GetSystemOs() { inline Os GetSystemOs() {
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
return Os::Windows; return Os::Windows;
#elif defined(__ANDROID__) #elif defined(__ANDROID__)
return Os::Android; return Os::Android;
#elif defined(__unix__) #elif defined(__unix__)
return Os::Linux; return Os::Linux;
#else #else
#pragma message ("Target OS unknown or unsupported !") #pragma message ("Target OS unknown or unsupported !")
return Os::Unknown; return Os::Unknown;
#endif #endif
} }
inline Architecture GetSystemArchitecture() { inline Architecture GetSystemArchitecture() {
#if defined(_WIN64) #if defined(_WIN64)
return Architecture::x86_64; return Architecture::x86_64;
#elif defined(_WIN32) #elif defined(_WIN32)
return Architecture::x86; return Architecture::x86;
#elif defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) #elif defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
return Architecture::x86_64; return Architecture::x86_64;
#elif defined(_M_IX86) || defined(_X86_) || defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) #elif defined(_M_IX86) || defined(_X86_) || defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__)
return Architecture::x86; return Architecture::x86;
#elif defined(__aarch64__) #elif defined(__aarch64__)
return Architecture::Arm64; return Architecture::Arm64;
#elif defined(__arm__) || defined(_M_ARM) #elif defined(__arm__) || defined(_M_ARM)
return Architecture::Armhf; return Architecture::Armhf;
#else #else
#pragma message ("Target CPU architecture unknown or unsupported !") #pragma message ("Target CPU architecture unknown or unsupported !")
return Architecture::Unknown; return Architecture::Unknown;
#endif #endif
} }

View File

@@ -7,18 +7,18 @@ namespace utils {
template<typename NumberType> template<typename NumberType>
NumberType GetRandomInt(NumberType min, NumberType max) { NumberType GetRandomInt(NumberType min, NumberType max) {
std::random_device randomDevice; std::random_device randomDevice;
std::mt19937 generator(randomDevice()); std::mt19937 generator(randomDevice());
std::uniform_int_distribution<NumberType> distrib(min, max); std::uniform_int_distribution<NumberType> distrib(min, max);
return distrib(generator); return distrib(generator);
} }
template<typename NumberType> template<typename NumberType>
NumberType GetRandomReal(NumberType min, NumberType max) { NumberType GetRandomReal(NumberType min, NumberType max) {
std::random_device randomDevice; std::random_device randomDevice;
std::mt19937 generator(randomDevice()); std::mt19937 generator(randomDevice());
std::uniform_real_distribution<NumberType> distrib(min, max); std::uniform_real_distribution<NumberType> distrib(min, max);
return distrib(generator); return distrib(generator);
} }
} // namespace utils } // namespace utils

View File

@@ -8,87 +8,87 @@ namespace shape {
class Point { class Point {
private: private:
float m_X, m_Y; float m_X, m_Y;
public: public:
Point() : m_X(0), m_Y(0) {} Point() : m_X(0), m_Y(0) {}
Point(float x, float y) : m_X(x), m_Y(y) {} Point(float x, float y) : m_X(x), m_Y(y) {}
float GetX() const { return m_X; } float GetX() const { return m_X; }
float GetY() const { return m_Y; } float GetY() const { return m_Y; }
void SetX(float x) { m_X = x; } void SetX(float x) { m_X = x; }
void SetY(float y) { m_Y = y; } void SetY(float y) { m_Y = y; }
float Distance(const Point& point) const; float Distance(const Point& point) const;
float DistanceSquared(const Point& point) const; float DistanceSquared(const Point& point) const;
}; };
class Circle; class Circle;
class Rectangle { class Rectangle {
private: private:
Point m_Center; Point m_Center;
float m_Width, m_Height; float m_Width, m_Height;
public: public:
Rectangle() {} Rectangle() {}
const Point& GetCenter() const { return m_Center; } const Point& GetCenter() const { return m_Center; }
float GetCenterX() const { return m_Center.GetX(); } float GetCenterX() const { return m_Center.GetX(); }
float GetCenterY() const { return m_Center.GetY(); } float GetCenterY() const { return m_Center.GetY(); }
float GetWidth() const { return m_Width; } float GetWidth() const { return m_Width; }
float GetHeight() const { return m_Height; } float GetHeight() const { return m_Height; }
Point GetTopLeft() const { return { m_Center.GetX() - (m_Width / 2.0f), m_Center.GetY() - (m_Height / 2.0f) }; } Point GetTopLeft() const { return { m_Center.GetX() - (m_Width / 2.0f), m_Center.GetY() - (m_Height / 2.0f) }; }
Point GetBottomRight() const { return { m_Center.GetX() + (m_Width / 2.0f), m_Center.GetY() + (m_Height / 2.0f) }; } Point GetBottomRight() const { return { m_Center.GetX() + (m_Width / 2.0f), m_Center.GetY() + (m_Height / 2.0f) }; }
void SetCenter(const Point& center) { m_Center = center; } void SetCenter(const Point& center) { m_Center = center; }
void SetCenterX(float x) { m_Center.SetX(x); } void SetCenterX(float x) { m_Center.SetX(x); }
void SetCenterY(float y) { m_Center.SetY(y); } void SetCenterY(float y) { m_Center.SetY(y); }
void SetSize(float width, float height) { SetWidth(width); SetHeight(height); } void SetSize(float width, float height) { SetWidth(width); SetHeight(height); }
void SetSize(Point size) { SetSize(size.GetX(), size.GetY()); } void SetSize(Point size) { SetSize(size.GetX(), size.GetY()); }
Point GetSize() { return { m_Width, m_Height }; } Point GetSize() { return { m_Width, m_Height }; }
void SetWidth(float width) { m_Width = width; } void SetWidth(float width) { m_Width = width; }
void SetHeight(float height) { m_Height = height; } void SetHeight(float height) { m_Height = height; }
bool CollidesWith(const Point& point) const; bool CollidesWith(const Point& point) const;
bool CollidesWith(const Rectangle& rect) const; bool CollidesWith(const Rectangle& rect) const;
bool CollidesWith(const Circle& circle) const; bool CollidesWith(const Circle& circle) const;
// distance from the closest side of the rectangle // distance from the closest side of the rectangle
float Distance(const Circle& circle) const; float Distance(const Circle& circle) const;
float DistanceSquared(const Circle& circle) const; float DistanceSquared(const Circle& circle) const;
}; };
class Circle { class Circle {
private: private:
Point m_Center; Point m_Center;
float m_Radius; float m_Radius;
public: public:
Circle(float x, float y, float radius) : m_Center(x, y), m_Radius(radius) {} Circle(float x, float y, float radius) : m_Center(x, y), m_Radius(radius) {}
Circle() : m_Radius(0) {} Circle() : m_Radius(0) {}
const Point& GetCenter() const { return m_Center; } const Point& GetCenter() const { return m_Center; }
float GetCenterX() const { return m_Center.GetX(); } float GetCenterX() const { return m_Center.GetX(); }
float GetCenterY() const { return m_Center.GetY(); } float GetCenterY() const { return m_Center.GetY(); }
float GetRadius() const { return m_Radius; } float GetRadius() const { return m_Radius; }
void SetCenter(const Point& center) { m_Center = center; } void SetCenter(const Point& center) { m_Center = center; }
void SetCenterX(float x) { m_Center.SetX(x); } void SetCenterX(float x) { m_Center.SetX(x); }
void SetCenterY(float y) { m_Center.SetY(y); } void SetCenterY(float y) { m_Center.SetY(y); }
void SetRadius(float radius) { m_Radius = radius; } void SetRadius(float radius) { m_Radius = radius; }
bool CollidesWith(const Point& point) const; bool CollidesWith(const Point& point) const;
bool CollidesWith(const Rectangle& rect) const; bool CollidesWith(const Rectangle& rect) const;
bool CollidesWith(const Circle& circle) const; bool CollidesWith(const Circle& circle) const;
// distance from the closest side of the rectangle // distance from the closest side of the rectangle
float Distance(const Rectangle& rect) const; float Distance(const Rectangle& rect) const;
float DistanceSquared(const Rectangle& rect) const; float DistanceSquared(const Rectangle& rect) const;
}; };
} // namespace shape } // namespace shape

View File

@@ -14,62 +14,62 @@ typedef std::function<void()> TimerExecFunction;
// utililty class to call function at regular period of time // utililty class to call function at regular period of time
class AutoTimer { class AutoTimer {
private: private:
std::uint64_t m_Interval; std::uint64_t m_Interval;
TimerExecFunction m_Function; TimerExecFunction m_Function;
std::uint64_t m_LastTime = GetTime(); std::uint64_t m_LastTime = GetTime();
std::uint64_t m_InternalTime = 0; std::uint64_t m_InternalTime = 0;
public: public:
AutoTimer() : m_Interval(0), m_Function(nullptr) {} AutoTimer() : m_Interval(0), m_Function(nullptr) {}
AutoTimer(std::uint64_t interval) : m_Interval(interval), m_Function(nullptr) {} AutoTimer(std::uint64_t interval) : m_Interval(interval), m_Function(nullptr) {}
AutoTimer(std::uint64_t interval, TimerExecFunction callback) : m_Interval(interval), m_Function(callback) {} AutoTimer(std::uint64_t interval, TimerExecFunction callback) : m_Interval(interval), m_Function(callback) {}
void Update(); void Update();
void Update(std::uint64_t delta); void Update(std::uint64_t delta);
void Reset(); void Reset();
void SetInterval(std::uint64_t newInterval) { m_Interval = newInterval; } void SetInterval(std::uint64_t newInterval) { m_Interval = newInterval; }
std::uint64_t GetInterval() const { return m_Interval; } std::uint64_t GetInterval() const { return m_Interval; }
void SetCallbackFunction(TimerExecFunction newCallback) { m_Function = newCallback; } void SetCallbackFunction(TimerExecFunction newCallback) { m_Function = newCallback; }
TimerExecFunction GetCallbackFunction() const { return m_Function; } TimerExecFunction GetCallbackFunction() const { return m_Function; }
}; };
// utililty class to call function at regular period of time // utililty class to call function at regular period of time
class Timer { class Timer {
private: private:
std::uint64_t m_Interval; // in millis std::uint64_t m_Interval; // in millis
std::uint64_t m_InternalTime = 0; std::uint64_t m_InternalTime = 0;
public: public:
Timer() : m_Interval(0) {} Timer() : m_Interval(0) {}
Timer(std::uint64_t interval) : m_Interval(interval) {} Timer(std::uint64_t interval) : m_Interval(interval) {}
bool Update(std::uint64_t delta); bool Update(std::uint64_t delta);
void Reset(); void Reset();
void SetInterval(std::uint64_t newInterval) { m_Interval = newInterval; } void SetInterval(std::uint64_t newInterval) { m_Interval = newInterval; }
std::uint64_t GetInterval() const { return m_Interval; } std::uint64_t GetInterval() const { return m_Interval; }
}; };
// utililty class to call function at regular period of time with a cooldown (used for towers and mobs ) // utililty class to call function at regular period of time with a cooldown (used for towers and mobs )
class CooldownTimer { class CooldownTimer {
private: private:
std::uint64_t m_Cooldown; // in millis std::uint64_t m_Cooldown; // in millis
std::uint64_t m_CooldownTime; std::uint64_t m_CooldownTime;
public: public:
CooldownTimer() : m_Cooldown(0), m_CooldownTime(0) {} CooldownTimer() : m_Cooldown(0), m_CooldownTime(0) {}
CooldownTimer(std::uint64_t cooldown) : m_Cooldown(0), m_CooldownTime(cooldown) {} CooldownTimer(std::uint64_t cooldown) : m_Cooldown(0), m_CooldownTime(cooldown) {}
bool Update(std::uint64_t delta); bool Update(std::uint64_t delta);
void ApplyCooldown(); void ApplyCooldown();
void Reset(); void Reset();
void SetCooldown(std::uint64_t newCooldown) { m_CooldownTime = newCooldown; } void SetCooldown(std::uint64_t newCooldown) { m_CooldownTime = newCooldown; }
std::uint64_t GetCooldown() const { return m_CooldownTime; } std::uint64_t GetCooldown() const { return m_CooldownTime; }
}; };
} // namespace utils } // namespace utils

View File

@@ -11,38 +11,38 @@ namespace network {
/* IPv4 address */ /* IPv4 address */
class IPAddress { class IPAddress {
private: private:
std::uint32_t m_Address; std::uint32_t m_Address;
bool m_Valid; bool m_Valid;
public: public:
/* Create an invalid address */ /* Create an invalid address */
IPAddress() noexcept; IPAddress() noexcept;
/* Initialize by string IP */ /* Initialize by string IP */
IPAddress(const std::string& str); IPAddress(const std::string& str);
/* Initialize by string IP */ /* Initialize by string IP */
IPAddress(const std::wstring& str); IPAddress(const std::wstring& str);
/* Initialize by octets */ /* Initialize by octets */
IPAddress(std::uint8_t octet1, std::uint8_t octet2, std::uint8_t octet3, std::uint8_t octet4) noexcept; IPAddress(std::uint8_t octet1, std::uint8_t octet2, std::uint8_t octet3, std::uint8_t octet4) noexcept;
/* Get the specific octet. 1-4 */ /* Get the specific octet. 1-4 */
std::uint8_t GetOctet(std::uint8_t num) const; std::uint8_t GetOctet(std::uint8_t num) const;
/* Set the specific octet. 1-4 */ /* Set the specific octet. 1-4 */
void SetOctet(std::uint8_t num, std::uint8_t value); 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. */ /* Make sure the IP is valid. It will be invalid if the host wasn't found. */
bool IsValid() const noexcept { return m_Valid; } bool IsValid() const noexcept { return m_Valid; }
std::string ToString() const; std::string ToString() const;
static IPAddress LocalAddress(); static IPAddress LocalAddress();
bool operator==(const IPAddress& right); bool operator==(const IPAddress& right);
bool operator!=(const IPAddress& right); bool operator!=(const IPAddress& right);
bool operator==(bool b); bool operator==(bool b);
}; };
typedef std::vector<IPAddress> IPAddresses; typedef std::vector<IPAddress> IPAddresses;

View File

@@ -22,7 +22,7 @@ namespace network {
class Dns { class Dns {
public: public:
static IPAddresses Resolve(const std::string& host); static IPAddresses Resolve(const std::string& host);
}; };
} // ns network } // ns network

View File

@@ -40,45 +40,45 @@ typedef int SocketHandle;
class Socket { class Socket {
public: public:
enum Status { Connected, Disconnected, Error }; enum Status { Connected, Disconnected, Error };
enum Type { TCP, UDP }; enum Type { TCP, UDP };
private: private:
bool m_Blocking; bool m_Blocking;
Type m_Type; Type m_Type;
Status m_Status; Status m_Status;
protected: protected:
SocketHandle m_Handle; SocketHandle m_Handle;
Socket(Type type); Socket(Type type);
void SetStatus(Status status); void SetStatus(Status status);
public: public:
virtual ~Socket(); virtual ~Socket();
Socket(Socket&& rhs) = default; Socket(Socket&& rhs) = default;
Socket& operator=(Socket&& rhs) = default; Socket& operator=(Socket&& rhs) = default;
bool SetBlocking(bool block); bool SetBlocking(bool block);
bool IsBlocking() const noexcept; bool IsBlocking() const noexcept;
Type GetType() const noexcept; Type GetType() const noexcept;
Status GetStatus() const noexcept; Status GetStatus() const noexcept;
SocketHandle GetHandle() const noexcept; SocketHandle GetHandle() const noexcept;
bool Connect(const std::string& ip, std::uint16_t port); bool Connect(const std::string& ip, std::uint16_t port);
virtual bool Connect(const IPAddress& address, std::uint16_t port) = 0; virtual bool Connect(const IPAddress& address, std::uint16_t port) = 0;
void Disconnect(); void Disconnect();
std::size_t Send(const std::string& data); std::size_t Send(const std::string& data);
std::size_t Send(DataBuffer& buffer); std::size_t Send(DataBuffer& buffer);
virtual std::size_t Send(const uint8_t* data, std::size_t size) = 0; virtual std::size_t Send(const uint8_t* data, std::size_t size) = 0;
virtual DataBuffer Receive(std::size_t amount) = 0; virtual DataBuffer Receive(std::size_t amount) = 0;
virtual std::size_t Receive(DataBuffer& buffer, std::size_t amount) = 0; virtual std::size_t Receive(DataBuffer& buffer, std::size_t amount) = 0;
}; };
typedef std::shared_ptr<Socket> SocketPtr; typedef std::shared_ptr<Socket> SocketPtr;

View File

@@ -5,30 +5,30 @@ namespace td {
namespace network { namespace network {
class TCPListener { class TCPListener {
int m_Handle; int m_Handle;
std::uint16_t m_Port; std::uint16_t m_Port;
int m_MaxConnections; int m_MaxConnections;
public: public:
TCPListener(); TCPListener();
~TCPListener(); ~TCPListener();
bool Listen(std::uint16_t port, int maxConnections); bool Listen(std::uint16_t port, int maxConnections);
bool Accept(TCPSocket& newSocket); bool Accept(TCPSocket& newSocket);
void Destroy(); void Destroy();
bool Close(); bool Close();
bool SetBlocking(bool blocking); bool SetBlocking(bool blocking);
std::uint16_t GetListeningPort() const { std::uint16_t GetListeningPort() const {
return m_Port; return m_Port;
} }
int GetMaximumConnections() const { int GetMaximumConnections() const {
return m_MaxConnections; return m_MaxConnections;
} }
REMOVE_COPY(TCPListener); REMOVE_COPY(TCPListener);
}; };
} // namespace network } // namespace network

View File

@@ -13,22 +13,22 @@ class TCPListener;
class TCPSocket : public Socket { class TCPSocket : public Socket {
private: private:
IPAddress m_RemoteIP; IPAddress m_RemoteIP;
uint16_t m_Port; uint16_t m_Port;
sockaddr m_RemoteAddr; sockaddr m_RemoteAddr;
public: public:
TCPSocket(); TCPSocket();
TCPSocket(TCPSocket&& other); TCPSocket(TCPSocket&& other);
virtual bool Connect(const IPAddress& address, std::uint16_t port); 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 std::size_t Send(const std::uint8_t* data, std::size_t size);
virtual DataBuffer Receive(std::size_t amount); virtual DataBuffer Receive(std::size_t amount);
virtual std::size_t Receive(DataBuffer& buffer, std::size_t amount); virtual std::size_t Receive(DataBuffer& buffer, std::size_t amount);
REMOVE_COPY(TCPSocket); REMOVE_COPY(TCPSocket);
friend class TCPListener; friend class TCPListener;
}; };
void SendPacket(const DataBuffer& data, network::TCPSocket& socket); void SendPacket(const DataBuffer& data, network::TCPSocket& socket);

View File

@@ -11,18 +11,18 @@ namespace network {
class UDPSocket : public Socket { class UDPSocket : public Socket {
private: private:
IPAddress m_RemoteIP; IPAddress m_RemoteIP;
uint16_t m_Port; uint16_t m_Port;
sockaddr_in m_RemoteAddr; sockaddr_in m_RemoteAddr;
public: public:
UDPSocket(); UDPSocket();
bool Connect(const IPAddress& address, std::uint16_t port); bool Connect(const IPAddress& address, std::uint16_t port);
std::size_t Send(const std::uint8_t* data, std::size_t size); std::size_t Send(const std::uint8_t* data, std::size_t size);
virtual DataBuffer Receive(std::size_t amount); virtual DataBuffer Receive(std::size_t amount);
virtual std::size_t Receive(DataBuffer& buffer, std::size_t amount); virtual std::size_t Receive(DataBuffer& buffer, std::size_t amount);
}; };
} // ns network } // ns network

View File

@@ -12,21 +12,21 @@ class PacketHandler;
class PacketDispatcher { class PacketDispatcher {
private: private:
std::map<PacketType, std::vector<PacketHandler*>> m_Handlers; std::map<PacketType, std::vector<PacketHandler*>> m_Handlers;
public: public:
PacketDispatcher() = default; PacketDispatcher() = default;
PacketDispatcher(const PacketDispatcher& rhs) = delete; PacketDispatcher(const PacketDispatcher& rhs) = delete;
PacketDispatcher& operator=(const PacketDispatcher& rhs) = delete; PacketDispatcher& operator=(const PacketDispatcher& rhs) = delete;
PacketDispatcher(PacketDispatcher&& rhs) = delete; PacketDispatcher(PacketDispatcher&& rhs) = delete;
PacketDispatcher& operator=(PacketDispatcher&& rhs) = delete; PacketDispatcher& operator=(PacketDispatcher&& rhs) = delete;
void Dispatch(const PacketPtr& packet); void Dispatch(const PacketPtr& packet);
void RegisterHandler(PacketType type, PacketHandler* handler); void RegisterHandler(PacketType type, PacketHandler* handler);
void UnregisterHandler(PacketType type, PacketHandler* handler); void UnregisterHandler(PacketType type, PacketHandler* handler);
void UnregisterHandler(PacketHandler* handler); void UnregisterHandler(PacketHandler* handler);
}; };
} // namespace protocol } // namespace protocol

View File

@@ -9,39 +9,39 @@ class PacketDispatcher;
class PacketHandler { class PacketHandler {
private: private:
PacketDispatcher* m_Dispatcher; PacketDispatcher* m_Dispatcher;
public: public:
PacketHandler(PacketDispatcher* dispatcher) : m_Dispatcher(dispatcher) {} PacketHandler(PacketDispatcher* dispatcher) : m_Dispatcher(dispatcher) {}
virtual ~PacketHandler() {} virtual ~PacketHandler() {}
PacketDispatcher* GetDispatcher() { return m_Dispatcher; } PacketDispatcher* GetDispatcher() { return m_Dispatcher; }
virtual void HandlePacket(const ConnexionInfoPacket* packet) {} virtual void HandlePacket(const ConnexionInfoPacket* packet) {}
virtual void HandlePacket(const DisconnectPacket* packet) {} virtual void HandlePacket(const DisconnectPacket* packet) {}
virtual void HandlePacket(const KeepAlivePacket* packet) {} virtual void HandlePacket(const KeepAlivePacket* packet) {}
virtual void HandlePacket(const PlaceTowerPacket* packet) {} virtual void HandlePacket(const PlaceTowerPacket* packet) {}
virtual void HandlePacket(const PlayerBuyItemPacket* packet) {} virtual void HandlePacket(const PlayerBuyItemPacket* packet) {}
virtual void HandlePacket(const PlayerBuyMobUpgradePacket* packet) {} virtual void HandlePacket(const PlayerBuyMobUpgradePacket* packet) {}
virtual void HandlePacket(const PlayerJoinPacket* packet) {} virtual void HandlePacket(const PlayerJoinPacket* packet) {}
virtual void HandlePacket(const PlayerLeavePacket* packet) {} virtual void HandlePacket(const PlayerLeavePacket* packet) {}
virtual void HandlePacket(const PlayerListPacket* packet) {} virtual void HandlePacket(const PlayerListPacket* packet) {}
virtual void HandlePacket(const PlayerLoginPacket* packet) {} virtual void HandlePacket(const PlayerLoginPacket* packet) {}
virtual void HandlePacket(const RemoveTowerPacket* packet) {} virtual void HandlePacket(const RemoveTowerPacket* packet) {}
virtual void HandlePacket(const SelectTeamPacket* packet) {} virtual void HandlePacket(const SelectTeamPacket* packet) {}
virtual void HandlePacket(const SendMobsPacket* packet) {} virtual void HandlePacket(const SendMobsPacket* packet) {}
virtual void HandlePacket(const ServerTpsPacket* packet) {} virtual void HandlePacket(const ServerTpsPacket* packet) {}
virtual void HandlePacket(const SpawnMobPacket* packet) {} virtual void HandlePacket(const SpawnMobPacket* packet) {}
virtual void HandlePacket(const UpdateCastleLifePacket* packet) {} virtual void HandlePacket(const UpdateCastleLifePacket* packet) {}
virtual void HandlePacket(const UpdateExpPacket* packet) {} virtual void HandlePacket(const UpdateExpPacket* packet) {}
virtual void HandlePacket(const UpdateGameStatePacket* packet) {} virtual void HandlePacket(const UpdateGameStatePacket* packet) {}
virtual void HandlePacket(const UpdateLobbyTimePacket* packet) {} virtual void HandlePacket(const UpdateLobbyTimePacket* packet) {}
virtual void HandlePacket(const UpdateMobStatesPacket* packet) {} virtual void HandlePacket(const UpdateMobStatesPacket* packet) {}
virtual void HandlePacket(const UpdateMoneyPacket* packet) {} virtual void HandlePacket(const UpdateMoneyPacket* packet) {}
virtual void HandlePacket(const UpdatePlayerTeamPacket* packet) {} virtual void HandlePacket(const UpdatePlayerTeamPacket* packet) {}
virtual void HandlePacket(const UpgradeTowerPacket* packet) {} virtual void HandlePacket(const UpgradeTowerPacket* packet) {}
virtual void HandlePacket(const WorldAddTowerPacket* packet) {} virtual void HandlePacket(const WorldAddTowerPacket* packet) {}
virtual void HandlePacket(const WorldBeginDataPacket* packet) {} virtual void HandlePacket(const WorldBeginDataPacket* packet) {}
virtual void HandlePacket(const WorldDataPacket* packet) {} virtual void HandlePacket(const WorldDataPacket* packet) {}
}; };
} // namespace protocol } // namespace protocol

View File

@@ -12,621 +12,627 @@ namespace protocol {
class PacketHandler; class PacketHandler;
enum class PacketType : std::uint8_t { enum class PacketType : std::uint8_t {
// client --> server // client --> server
PlayerLogin = 0, PlayerLogin = 0,
SelectTeam, SelectTeam,
SpawnMob, SpawnMob,
SendMobs, SendMobs,
PlaceTower, PlaceTower,
// client <-- server // client <-- server
PlayerJoin, PlayerJoin,
PlayerLeave, PlayerLeave,
WorldBeginData, WorldBeginData,
WorldData, WorldData,
UpdateMoney, UpdateMoney,
UpdateEXP, UpdateEXP,
UpdateLobbyTime, UpdateLobbyTime,
UpdateGameState, UpdateGameState,
PlayerList, PlayerList,
ConnectionInfo, ConnectionInfo,
UpdatePlayerTeam, UpdatePlayerTeam,
ServerTps, ServerTps,
WorldAddTower, WorldAddTower,
UpdateMobStates, UpdateMobStates,
UpdateCastleLife, UpdateCastleLife,
// client <--> server // client <--> server
KeepAlive, KeepAlive,
Disconnect, Disconnect,
UpgradeTower, UpgradeTower,
RemoveTower, RemoveTower,
PlayerBuyItem, PlayerBuyItem,
PlayerBuyMobUpgrade, PlayerBuyMobUpgrade,
PACKET_COUNT PACKET_COUNT
}; };
struct WorldHeader { struct WorldHeader {
game::TowerTileColorPalette m_TowerPlacePalette; game::TowerTileColorPalette m_TowerPlacePalette;
game::Color m_WalkablePalette; Color m_WalkablePalette;
std::vector<game::Color> m_DecorationPalette; std::vector<Color> m_DecorationPalette;
game::Color m_Background; Color m_Background;
game::SpawnColorPalette m_SpawnColorPalette; game::SpawnColorPalette m_SpawnColorPalette;
game::TilePalette m_TilePalette; game::TilePalette m_TilePalette;
game::Spawn m_RedSpawn, m_BlueSpawn; game::Spawn m_RedSpawn, m_BlueSpawn;
game::TeamCastle m_RedCastle, m_BlueCastle; game::TeamCastle m_RedCastle, m_BlueCastle;
const game::World* m_World; const game::World* m_World;
}; };
struct WorldData { struct WorldData {
std::unordered_map<game::ChunkCoord, game::ChunkPtr> m_Chunks; std::unordered_map<game::ChunkCoord, game::ChunkPtr> m_Chunks;
}; };
class Packet { class Packet {
public: public:
Packet() {} Packet() {}
virtual ~Packet() {} virtual ~Packet() {}
virtual DataBuffer Serialize(bool packetID = true) const = 0; virtual DataBuffer Serialize(bool packetID = true) const = 0;
virtual void Deserialize(DataBuffer& data) = 0; virtual void Deserialize(DataBuffer& data) = 0;
virtual void Dispatch(PacketHandler* handler) const = 0; virtual void Dispatch(PacketHandler* handler) const = 0;
void WritePacketID(DataBuffer& data, bool packetID) const; void WritePacketID(DataBuffer& data, bool packetID) const;
virtual PacketType GetType() const = 0; virtual PacketType GetType() const = 0;
std::uint8_t GetID() const { return static_cast<std::uint8_t>(GetType()); } std::uint8_t GetID() const { return static_cast<std::uint8_t>(GetType()); }
}; };
typedef std::unique_ptr<Packet> PacketPtr; typedef std::unique_ptr<Packet> PacketPtr;
class KeepAlivePacket : public Packet { class KeepAlivePacket : public Packet {
private: private:
std::uint64_t m_AliveID; std::uint64_t m_AliveID;
public: public:
KeepAlivePacket() {} KeepAlivePacket() {}
KeepAlivePacket(std::uint64_t aliveID) : m_AliveID(aliveID) {} KeepAlivePacket(std::uint64_t aliveID) : m_AliveID(aliveID) {}
virtual ~KeepAlivePacket() {} virtual ~KeepAlivePacket() {}
virtual DataBuffer Serialize(bool packetID = true) const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
std::uint64_t GetAliveID() const { return m_AliveID; } std::uint64_t GetAliveID() const { return m_AliveID; }
virtual PacketType GetType() const { return PacketType::KeepAlive; } virtual PacketType GetType() const { return PacketType::KeepAlive; }
}; };
class PlayerLoginPacket : public Packet { class PlayerLoginPacket : public Packet {
private: private:
std::string m_PlayerName; std::string m_PlayerName;
public: public:
PlayerLoginPacket() {} PlayerLoginPacket() {}
PlayerLoginPacket(std::string playerName) : m_PlayerName(playerName) {} PlayerLoginPacket(std::string playerName) : m_PlayerName(playerName) {}
virtual ~PlayerLoginPacket() {} virtual ~PlayerLoginPacket() {}
virtual DataBuffer Serialize(bool packetID = true) const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
virtual PacketType GetType() const { return PacketType::PlayerLogin; } virtual PacketType GetType() const { return PacketType::PlayerLogin; }
const std::string& GetPlayerName() const { return m_PlayerName; } const std::string& GetPlayerName() const { return m_PlayerName; }
}; };
class WorldBeginDataPacket : public Packet { class WorldBeginDataPacket : public Packet {
private: private:
WorldHeader m_Header; WorldHeader m_Header;
public: public:
WorldBeginDataPacket() {} WorldBeginDataPacket() {}
WorldBeginDataPacket(const game::World* world) { WorldBeginDataPacket(const game::World* world) {
m_Header.m_World = world; m_Header.m_World = world;
} }
virtual ~WorldBeginDataPacket() {} virtual ~WorldBeginDataPacket() {}
virtual DataBuffer Serialize(bool packetID = true) const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
virtual PacketType GetType() const { return PacketType::WorldBeginData; } virtual PacketType GetType() const { return PacketType::WorldBeginData; }
const game::TowerTileColorPalette& GetTowerTilePalette() const { return m_Header.m_TowerPlacePalette; } const game::TowerTileColorPalette& GetTowerTilePalette() const { return m_Header.m_TowerPlacePalette; }
const game::Color& GetWalkableTileColor() const { return m_Header.m_WalkablePalette; } const Color& GetWalkableTileColor() const { return m_Header.m_WalkablePalette; }
const std::vector<game::Color>& GetDecorationPalette() const { return m_Header.m_DecorationPalette; } const std::vector<Color>& GetDecorationPalette() const { return m_Header.m_DecorationPalette; }
const game::Color& GetBackgroundColor() const { return m_Header.m_Background; } const Color& GetBackgroundColor() const { return m_Header.m_Background; }
const game::Spawn& GetRedSpawn() const { return m_Header.m_RedSpawn; } const game::Spawn& GetRedSpawn() const { return m_Header.m_RedSpawn; }
const game::Spawn& GetBlueSpawn() const { return m_Header.m_BlueSpawn; } const game::Spawn& GetBlueSpawn() const { return m_Header.m_BlueSpawn; }
const game::SpawnColorPalette& GetSpawnPalette() const { return m_Header.m_SpawnColorPalette; } const game::SpawnColorPalette& GetSpawnPalette() const { return m_Header.m_SpawnColorPalette; }
const game::TeamCastle& GetRedCastle() const { return m_Header.m_RedCastle; } const game::TeamCastle& GetRedCastle() const { return m_Header.m_RedCastle; }
const game::TeamCastle& GetBlueCastle() const { return m_Header.m_BlueCastle; } const game::TeamCastle& GetBlueCastle() const { return m_Header.m_BlueCastle; }
const game::TilePalette GetTilePalette() const { return m_Header.m_TilePalette; } const game::TilePalette GetTilePalette() const { return m_Header.m_TilePalette; }
void setWorldHeader(const WorldHeader& header) { m_Header = header; } void setWorldHeader(const WorldHeader& header) { m_Header = header; }
}; };
class WorldDataPacket : public Packet { class WorldDataPacket : public Packet {
private: private:
WorldData m_WorldData; WorldData m_WorldData;
const game::World* m_World; const game::World* m_World;
public: public:
WorldDataPacket() {} WorldDataPacket() {}
WorldDataPacket(const game::World* world) : m_World(world) {} WorldDataPacket(const game::World* world) : m_World(world) {}
virtual ~WorldDataPacket() {} virtual ~WorldDataPacket() {}
virtual DataBuffer Serialize(bool packetID = true) const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
virtual PacketType GetType() const { return PacketType::WorldData; } virtual PacketType GetType() const { return PacketType::WorldData; }
const std::unordered_map<game::ChunkCoord, game::ChunkPtr>& GetChunks() const { return m_WorldData.m_Chunks; } const std::unordered_map<game::ChunkCoord, game::ChunkPtr>& GetChunks() const { return m_WorldData.m_Chunks; }
DataBuffer SerializeCustom() const; // allow serialisation with invalid World member DataBuffer SerializeCustom() const; // allow serialisation with invalid World member
void SetWorldData(const WorldData& worldData) { m_WorldData = worldData; } void SetWorldData(const WorldData& worldData) { m_WorldData = worldData; }
}; };
class UpdateMoneyPacket : public Packet { class UpdateMoneyPacket : public Packet {
private: private:
std::uint32_t m_NewAmount; std::uint32_t m_NewAmount;
public: public:
UpdateMoneyPacket() {} UpdateMoneyPacket() {}
UpdateMoneyPacket(std::uint32_t newAmount) : m_NewAmount(newAmount) {} UpdateMoneyPacket(std::uint32_t newAmount) : m_NewAmount(newAmount) {}
virtual ~UpdateMoneyPacket() {} virtual ~UpdateMoneyPacket() {}
std::uint32_t GetGold() const { return m_NewAmount; } std::uint32_t GetGold() const { return m_NewAmount; }
virtual DataBuffer Serialize(bool packetID = true) const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
virtual PacketType GetType() const { return PacketType::UpdateMoney; } virtual PacketType GetType() const { return PacketType::UpdateMoney; }
}; };
class UpdateExpPacket : public Packet { class UpdateExpPacket : public Packet {
private: private:
std::uint32_t m_NewAmount; std::uint32_t m_NewAmount;
public: public:
UpdateExpPacket() {} UpdateExpPacket() {}
UpdateExpPacket(std::uint32_t newAmount) : m_NewAmount(newAmount) {} UpdateExpPacket(std::uint32_t newAmount) : m_NewAmount(newAmount) {}
virtual ~UpdateExpPacket() {} virtual ~UpdateExpPacket() {}
std::uint32_t GetExp() const { return m_NewAmount; } std::uint32_t GetExp() const { return m_NewAmount; }
virtual DataBuffer Serialize(bool packetID = true) const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
virtual PacketType GetType() const { return PacketType::UpdateEXP; } virtual PacketType GetType() const { return PacketType::UpdateEXP; }
}; };
class UpdateLobbyTimePacket : public Packet { class UpdateLobbyTimePacket : public Packet {
private: private:
std::uint32_t m_RemainingTime; std::uint32_t m_RemainingTime;
public: public:
UpdateLobbyTimePacket() {} UpdateLobbyTimePacket() {}
UpdateLobbyTimePacket(std::uint32_t remainingTime) : m_RemainingTime(remainingTime) {} UpdateLobbyTimePacket(std::uint32_t remainingTime) : m_RemainingTime(remainingTime) {}
virtual ~UpdateLobbyTimePacket() {} virtual ~UpdateLobbyTimePacket() {}
virtual DataBuffer Serialize(bool packetID = true) const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
std::uint32_t GetRemainingTime() const { return m_RemainingTime; } std::uint32_t GetRemainingTime() const { return m_RemainingTime; }
virtual PacketType GetType() const { return PacketType::UpdateLobbyTime; } virtual PacketType GetType() const { return PacketType::UpdateLobbyTime; }
}; };
class UpdateGameStatePacket : public Packet { class UpdateGameStatePacket : public Packet {
private: private:
game::GameState m_GameState; game::GameState m_GameState;
public: public:
UpdateGameStatePacket() {} UpdateGameStatePacket() {}
UpdateGameStatePacket(game::GameState gameState) : m_GameState(gameState) {} UpdateGameStatePacket(game::GameState gameState) : m_GameState(gameState) {}
virtual ~UpdateGameStatePacket() {} virtual ~UpdateGameStatePacket() {}
virtual DataBuffer Serialize(bool packetID = true) const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
game::GameState GetGameState() const { return m_GameState; } game::GameState GetGameState() const { return m_GameState; }
virtual PacketType GetType() const { return PacketType::UpdateGameState; } virtual PacketType GetType() const { return PacketType::UpdateGameState; }
}; };
struct PlayerInfo { struct PlayerInfo {
std::string name; std::string name;
game::TeamColor team; game::TeamColor team;
}; };
class PlayerListPacket : public Packet { class PlayerListPacket : public Packet {
private: private:
std::map<std::uint8_t, PlayerInfo> m_Players; std::map<std::uint8_t, PlayerInfo> m_Players;
public: public:
PlayerListPacket() {} PlayerListPacket() {}
PlayerListPacket(std::map<std::uint8_t, PlayerInfo> players) : m_Players(players) {} PlayerListPacket(std::map<std::uint8_t, PlayerInfo> players) : m_Players(players) {}
virtual ~PlayerListPacket() {} virtual ~PlayerListPacket() {}
virtual DataBuffer Serialize(bool packetID = true) const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
const std::map<std::uint8_t, PlayerInfo>& GetPlayers() const { return m_Players; } const std::map<std::uint8_t, PlayerInfo>& GetPlayers() const { return m_Players; }
virtual PacketType GetType() const { return PacketType::PlayerList; } virtual PacketType GetType() const { return PacketType::PlayerList; }
}; };
class PlayerJoinPacket : public Packet { class PlayerJoinPacket : public Packet {
private: private:
std::uint8_t m_PlayerID; std::uint8_t m_PlayerID;
std::string m_PlayerName; std::string m_PlayerName;
public: public:
PlayerJoinPacket() {} PlayerJoinPacket() {}
PlayerJoinPacket(std::uint8_t playerID, const std::string& playerName) : m_PlayerID(playerID), m_PlayerName(playerName) {} PlayerJoinPacket(std::uint8_t playerID, const std::string& playerName) : m_PlayerID(playerID), m_PlayerName(playerName) {}
virtual ~PlayerJoinPacket() {} virtual ~PlayerJoinPacket() {}
virtual DataBuffer Serialize(bool packetID = true) const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
std::uint8_t GetPlayerID() const { return m_PlayerID; } std::uint8_t GetPlayerID() const { return m_PlayerID; }
const std::string& GetPlayerName() const { return m_PlayerName; } const std::string& GetPlayerName() const { return m_PlayerName; }
virtual PacketType GetType() const { return PacketType::PlayerJoin; } virtual PacketType GetType() const { return PacketType::PlayerJoin; }
}; };
class PlayerLeavePacket : public Packet { class PlayerLeavePacket : public Packet {
private: private:
std::uint8_t m_PlayerID; std::uint8_t m_PlayerID;
public: public:
PlayerLeavePacket() {} PlayerLeavePacket() {}
PlayerLeavePacket(std::uint8_t playerID) : m_PlayerID(playerID) {} PlayerLeavePacket(std::uint8_t playerID) : m_PlayerID(playerID) {}
virtual ~PlayerLeavePacket() {} virtual ~PlayerLeavePacket() {}
virtual DataBuffer Serialize(bool packetID = true) const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
std::uint8_t GetPlayerID() const { return m_PlayerID; } std::uint8_t GetPlayerID() const { return m_PlayerID; }
virtual PacketType GetType() const { return PacketType::PlayerLeave; } virtual PacketType GetType() const { return PacketType::PlayerLeave; }
}; };
class ConnexionInfoPacket : public Packet { class ConnexionInfoPacket : public Packet {
private: private:
std::uint8_t m_ConnectionID; std::uint8_t m_ConnectionID;
public: public:
ConnexionInfoPacket() {} ConnexionInfoPacket() {}
ConnexionInfoPacket(std::uint8_t connectionID) : m_ConnectionID(connectionID) {} ConnexionInfoPacket(std::uint8_t connectionID) : m_ConnectionID(connectionID) {}
virtual ~ConnexionInfoPacket() {} virtual ~ConnexionInfoPacket() {}
virtual DataBuffer Serialize(bool packetID = true) const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
std::uint8_t GetConnectionID() const { return m_ConnectionID; } std::uint8_t GetConnectionID() const { return m_ConnectionID; }
virtual PacketType GetType() const { return PacketType::ConnectionInfo; } virtual PacketType GetType() const { return PacketType::ConnectionInfo; }
}; };
class SelectTeamPacket : public Packet { class SelectTeamPacket : public Packet {
private: private:
game::TeamColor m_SelectedTeam; game::TeamColor m_SelectedTeam;
public: public:
SelectTeamPacket() {} SelectTeamPacket() {}
SelectTeamPacket(game::TeamColor selectedTeam) : m_SelectedTeam(selectedTeam) {} SelectTeamPacket(game::TeamColor selectedTeam) : m_SelectedTeam(selectedTeam) {}
virtual ~SelectTeamPacket() {} virtual ~SelectTeamPacket() {}
virtual DataBuffer Serialize(bool packetID = true) const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
game::TeamColor GetSelectedTeam() const { return m_SelectedTeam; } game::TeamColor GetSelectedTeam() const { return m_SelectedTeam; }
virtual PacketType GetType() const { return PacketType::SelectTeam; } virtual PacketType GetType() const { return PacketType::SelectTeam; }
}; };
class UpdatePlayerTeamPacket : public Packet { class UpdatePlayerTeamPacket : public Packet {
private: private:
std::uint8_t m_PlayerID; std::uint8_t m_PlayerID;
game::TeamColor m_SelectedTeam; game::TeamColor m_SelectedTeam;
public: public:
UpdatePlayerTeamPacket() {} UpdatePlayerTeamPacket() {}
UpdatePlayerTeamPacket(std::uint8_t playerID, game::TeamColor selectedTeam) : m_PlayerID(playerID), m_SelectedTeam(selectedTeam) {} UpdatePlayerTeamPacket(std::uint8_t playerID, game::TeamColor selectedTeam) : m_PlayerID(playerID), m_SelectedTeam(selectedTeam) {}
virtual ~UpdatePlayerTeamPacket() {} virtual ~UpdatePlayerTeamPacket() {}
virtual DataBuffer Serialize(bool packetID = true) const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
game::TeamColor GetSelectedTeam() const { return m_SelectedTeam; } game::TeamColor GetSelectedTeam() const { return m_SelectedTeam; }
std::uint8_t GetPlayerID() const { return m_PlayerID; } std::uint8_t GetPlayerID() const { return m_PlayerID; }
virtual PacketType GetType() const { return PacketType::UpdatePlayerTeam; } virtual PacketType GetType() const { return PacketType::UpdatePlayerTeam; }
}; };
class DisconnectPacket : public Packet { class DisconnectPacket : public Packet {
private: private:
std::string m_Reason; // only when sent from server std::string m_Reason; // only when sent from server
public: public:
DisconnectPacket() {} DisconnectPacket() {}
DisconnectPacket(std::string reason) : m_Reason(reason) {} DisconnectPacket(std::string reason) : m_Reason(reason) {}
virtual ~DisconnectPacket() {} virtual ~DisconnectPacket() {}
virtual DataBuffer Serialize(bool packetID = true) const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
const std::string& GetReason() const { return m_Reason; } const std::string& GetReason() const { return m_Reason; }
virtual PacketType GetType() const { return PacketType::Disconnect; } virtual PacketType GetType() const { return PacketType::Disconnect; }
}; };
class ServerTpsPacket : public Packet { class ServerTpsPacket : public Packet {
private: private:
float m_TPS; float m_TPS;
std::uint64_t m_PacketSendTime; // used to calculate ping float m_MSPT;
std::uint64_t m_PacketSendTime; // used to calculate ping
public: public:
ServerTpsPacket() {} ServerTpsPacket() {}
ServerTpsPacket(float tps, std::uint64_t sendTime) : m_TPS(tps), m_PacketSendTime(sendTime) {} ServerTpsPacket(float tps, float mspt, std::uint64_t sendTime) : m_TPS(tps), m_MSPT(mspt), m_PacketSendTime(sendTime) {}
virtual ~ServerTpsPacket() {} virtual ~ServerTpsPacket() {}
virtual DataBuffer Serialize(bool packetID = true) const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
float GetTPS() const { return m_TPS; } float GetTPS() const { return m_TPS; }
std::uint64_t GetPacketSendTime() const { return m_PacketSendTime; } float GetMSPT() const { return m_MSPT; }
std::uint64_t GetPacketSendTime() const { return m_PacketSendTime; }
virtual PacketType GetType() const { return PacketType::ServerTps; } virtual PacketType GetType() const { return PacketType::ServerTps; }
}; };
struct MobSend { // represents a mob send struct MobSend { // represents a mob send
game::MobType mobType : 4; game::MobType mobType : 4;
game::MobLevel mobLevel : 4; game::MobLevel mobLevel : 4;
std::uint8_t mobCount; // the max is 12 std::uint8_t mobCount; // the max is 12
}; };
class SendMobsPacket : public Packet { class SendMobsPacket : public Packet {
private: private:
std::vector<MobSend> m_MobSends; std::vector<MobSend> m_MobSends;
public: public:
SendMobsPacket() {} SendMobsPacket() {}
SendMobsPacket(const std::vector<MobSend>& mobSends) : m_MobSends(mobSends) {} SendMobsPacket(const std::vector<MobSend>& mobSends) : m_MobSends(mobSends) {}
virtual ~SendMobsPacket() {} virtual ~SendMobsPacket() {}
virtual DataBuffer Serialize(bool packetID = true) const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
const std::vector<MobSend>& GetMobSends() const { return m_MobSends; } const std::vector<MobSend>& GetMobSends() const { return m_MobSends; }
virtual PacketType GetType() const { return PacketType::SendMobs; } virtual PacketType GetType() const { return PacketType::SendMobs; }
}; };
class SpawnMobPacket : public Packet { class SpawnMobPacket : public Packet {
private: private:
game::MobID m_MobID; game::MobID m_MobID;
game::MobType m_MobType; game::MobType m_MobType;
game::MobLevel m_MobLevel; game::MobLevel m_MobLevel;
game::Direction m_MobDirection; game::Direction m_MobDirection;
game::PlayerID m_Sender; game::PlayerID m_Sender;
float m_MobX, m_MobY; float m_MobX, m_MobY;
public: public:
SpawnMobPacket() {} SpawnMobPacket() {}
SpawnMobPacket(game::MobID id, game::MobType type, std::uint8_t level, game::PlayerID sender, 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), 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) {} m_MobDirection(dir), m_Sender(sender), m_MobX(x), m_MobY(y) {
virtual ~SpawnMobPacket() {} }
virtual ~SpawnMobPacket() {}
virtual DataBuffer Serialize(bool packetID = true) const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
game::MobID GetMobID() const { return m_MobID; } game::MobID GetMobID() const { return m_MobID; }
game::MobType GetMobType() const { return m_MobType; } game::MobType GetMobType() const { return m_MobType; }
game::MobLevel GetMobLevel() const { return m_MobLevel; } game::MobLevel GetMobLevel() const { return m_MobLevel; }
game::Direction GetMobDirection() const { return m_MobDirection; } game::Direction GetMobDirection() const { return m_MobDirection; }
game::PlayerID GetSender() const { return m_Sender; } game::PlayerID GetSender() const { return m_Sender; }
float GetMobX() const { return m_MobX; } float GetMobX() const { return m_MobX; }
float GetMobY() const { return m_MobY; } float GetMobY() const { return m_MobY; }
virtual PacketType GetType() const { return PacketType::SpawnMob; } virtual PacketType GetType() const { return PacketType::SpawnMob; }
}; };
class PlaceTowerPacket : public Packet { class PlaceTowerPacket : public Packet {
private: private:
std::int32_t m_TowerX, m_TowerY; std::int32_t m_TowerX, m_TowerY;
game::TowerType m_TowerType; game::TowerType m_TowerType;
public: public:
PlaceTowerPacket() {} PlaceTowerPacket() {}
PlaceTowerPacket(std::int32_t x, std::int32_t y, game::TowerType type) : PlaceTowerPacket(std::int32_t x, std::int32_t y, game::TowerType type) :
m_TowerX(x), m_TowerY(y), m_TowerType(type) {} m_TowerX(x), m_TowerY(y), m_TowerType(type) {
virtual ~PlaceTowerPacket() {} }
virtual ~PlaceTowerPacket() {}
virtual DataBuffer Serialize(bool packetID = true) const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
std::int32_t GetTowerX() const { return m_TowerX; } std::int32_t GetTowerX() const { return m_TowerX; }
std::int32_t GetTowerY() const { return m_TowerY; } std::int32_t GetTowerY() const { return m_TowerY; }
game::TowerType GetTowerType() const { return m_TowerType; } game::TowerType GetTowerType() const { return m_TowerType; }
virtual PacketType GetType() const { return PacketType::PlaceTower; } virtual PacketType GetType() const { return PacketType::PlaceTower; }
}; };
class WorldAddTowerPacket : public Packet { class WorldAddTowerPacket : public Packet {
private: private:
game::TowerID m_TowerID; game::TowerID m_TowerID;
std::int32_t m_TowerX, m_TowerY; std::int32_t m_TowerX, m_TowerY;
game::TowerType m_TowerType; game::TowerType m_TowerType;
game::PlayerID m_Builder; game::PlayerID m_Builder;
public: public:
WorldAddTowerPacket() {} WorldAddTowerPacket() {}
WorldAddTowerPacket(game::TowerID id, std::int32_t x, std::int32_t y, game::TowerType type, game::PlayerID player) : WorldAddTowerPacket(game::TowerID id, std::int32_t x, std::int32_t y, game::TowerType type, game::PlayerID player) :
m_TowerID(id), m_TowerX(x), m_TowerY(y), m_TowerType(type), m_Builder(player) {} m_TowerID(id), m_TowerX(x), m_TowerY(y), m_TowerType(type), m_Builder(player) {
virtual ~WorldAddTowerPacket() {} }
virtual ~WorldAddTowerPacket() {}
virtual DataBuffer Serialize(bool packetID = true) const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
game::TowerID GetTowerID() const { return m_TowerID; } game::TowerID GetTowerID() const { return m_TowerID; }
std::int32_t GetTowerX() const { return m_TowerX; } std::int32_t GetTowerX() const { return m_TowerX; }
std::int32_t GetTowerY() const { return m_TowerY; } std::int32_t GetTowerY() const { return m_TowerY; }
game::TowerType GetTowerType() const { return m_TowerType; } game::TowerType GetTowerType() const { return m_TowerType; }
game::PlayerID GetBuilder() const { return m_Builder; } game::PlayerID GetBuilder() const { return m_Builder; }
virtual PacketType GetType() const { return PacketType::WorldAddTower; } virtual PacketType GetType() const { return PacketType::WorldAddTower; }
}; };
class RemoveTowerPacket : public Packet { class RemoveTowerPacket : public Packet {
private: private:
game::TowerID m_TowerID; game::TowerID m_TowerID;
public: public:
RemoveTowerPacket() {} RemoveTowerPacket() {}
RemoveTowerPacket(game::TowerID id) : m_TowerID(id) {} RemoveTowerPacket(game::TowerID id) : m_TowerID(id) {}
virtual ~RemoveTowerPacket() {} virtual ~RemoveTowerPacket() {}
virtual DataBuffer Serialize(bool packetID = true) const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
game::TowerID GetTowerID() const { return m_TowerID; } game::TowerID GetTowerID() const { return m_TowerID; }
virtual PacketType GetType() const { return PacketType::RemoveTower; } virtual PacketType GetType() const { return PacketType::RemoveTower; }
}; };
class UpgradeTowerPacket : public Packet { class UpgradeTowerPacket : public Packet {
private: private:
game::TowerID m_TowerID; game::TowerID m_TowerID;
game::TowerLevel m_TowerLevel; game::TowerLevel m_TowerLevel;
public: public:
UpgradeTowerPacket() {} UpgradeTowerPacket() {}
UpgradeTowerPacket(game::TowerID tower, game::TowerLevel level) : m_TowerID(tower), m_TowerLevel(level) {} UpgradeTowerPacket(game::TowerID tower, game::TowerLevel level) : m_TowerID(tower), m_TowerLevel(level) {}
virtual ~UpgradeTowerPacket() {} virtual ~UpgradeTowerPacket() {}
virtual DataBuffer Serialize(bool packetID = true) const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
game::TowerID GetTowerID() const { return m_TowerID; } game::TowerID GetTowerID() const { return m_TowerID; }
game::TowerLevel GetTowerLevel() const { return m_TowerLevel; } game::TowerLevel GetTowerLevel() const { return m_TowerLevel; }
virtual PacketType GetType() const { return PacketType::UpgradeTower; } virtual PacketType GetType() const { return PacketType::UpgradeTower; }
}; };
class MobState { class MobState {
using Point = utils::shape::Point; using Point = utils::shape::Point;
private: private:
game::MobID m_MobID; game::MobID m_MobID;
Point m_MobPosition; Point m_MobPosition;
float m_MobLife; float m_MobLife;
game::Direction m_MobDirection; game::Direction m_MobDirection;
public: public:
MobState() {} MobState() {}
MobState(game::MobID id, const Point& position, float life, game::Direction direction) : MobState(game::MobID id, const Point& position, float life, game::Direction direction) :
m_MobID(id), m_MobPosition(position), m_MobLife(life), m_MobDirection(direction) {} m_MobID(id), m_MobPosition(position), m_MobLife(life), m_MobDirection(direction) {
}
game::MobID GetMobId() const { return m_MobID; } game::MobID GetMobId() const { return m_MobID; }
Point GetMobPosition() const { return m_MobPosition; } Point GetMobPosition() const { return m_MobPosition; }
float GetMobLife() const { return m_MobLife; } float GetMobLife() const { return m_MobLife; }
game::Direction GetMobDirection() const { return m_MobDirection; } game::Direction GetMobDirection() const { return m_MobDirection; }
}; };
class UpdateMobStatesPacket : public Packet { class UpdateMobStatesPacket : public Packet {
private: private:
std::vector<MobState> m_MobStates; std::vector<MobState> m_MobStates;
public: public:
UpdateMobStatesPacket() {} UpdateMobStatesPacket() {}
virtual ~UpdateMobStatesPacket() {} virtual ~UpdateMobStatesPacket() {}
virtual DataBuffer Serialize(bool packetID = true) const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
void addMobState(MobState mobState) { m_MobStates.push_back(mobState); } void addMobState(MobState mobState) { m_MobStates.push_back(mobState); }
const std::vector<MobState>& GetMobStates() const { return m_MobStates; } const std::vector<MobState>& GetMobStates() const { return m_MobStates; }
virtual PacketType GetType() const { return PacketType::UpdateMobStates; } virtual PacketType GetType() const { return PacketType::UpdateMobStates; }
}; };
class UpdateCastleLifePacket : public Packet { class UpdateCastleLifePacket : public Packet {
private: private:
std::uint16_t m_CastleLife; std::uint16_t m_CastleLife;
game::TeamColor m_Team; game::TeamColor m_Team;
public: public:
UpdateCastleLifePacket() {} UpdateCastleLifePacket() {}
UpdateCastleLifePacket(std::uint16_t life, game::TeamColor team) : m_CastleLife(life), m_Team(team) {} UpdateCastleLifePacket(std::uint16_t life, game::TeamColor team) : m_CastleLife(life), m_Team(team) {}
virtual ~UpdateCastleLifePacket() {} virtual ~UpdateCastleLifePacket() {}
virtual DataBuffer Serialize(bool packetID = true) const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
std::uint16_t GetCastleLife() const { return m_CastleLife; } std::uint16_t GetCastleLife() const { return m_CastleLife; }
game::TeamColor GetTeamColor() const { return m_Team; } game::TeamColor GetTeamColor() const { return m_Team; }
virtual PacketType GetType() const { return PacketType::UpdateCastleLife; } virtual PacketType GetType() const { return PacketType::UpdateCastleLife; }
}; };
enum class ItemType : std::uint8_t { enum class ItemType : std::uint8_t {
// Upgrades // Upgrades
ClickerUpgrade, ClickerUpgrade,
GoldPerSecUpgrade, GoldPerSecUpgrade,
// Items // Items
}; };
/** Packet used by the client to buy items or upgrades /** Packet used by the client to buy items or upgrades
Packet used by the server to confirm transaction */ Packet used by the server to confirm transaction */
class PlayerBuyItemPacket : public Packet { class PlayerBuyItemPacket : public Packet {
private: private:
ItemType m_ItemType; ItemType m_ItemType;
std::uint8_t m_Count; std::uint8_t m_Count;
public: public:
PlayerBuyItemPacket() {} PlayerBuyItemPacket() {}
PlayerBuyItemPacket(ItemType itemType, std::uint8_t count) : m_ItemType(itemType), m_Count(count) {} PlayerBuyItemPacket(ItemType itemType, std::uint8_t count) : m_ItemType(itemType), m_Count(count) {}
virtual ~PlayerBuyItemPacket() {} virtual ~PlayerBuyItemPacket() {}
virtual DataBuffer Serialize(bool packetID = true) const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
ItemType GetItemType() const { return m_ItemType; } ItemType GetItemType() const { return m_ItemType; }
std::uint8_t GetCount() const { return m_Count; } std::uint8_t GetCount() const { return m_Count; }
virtual PacketType GetType() const { return PacketType::PlayerBuyItem; } virtual PacketType GetType() const { return PacketType::PlayerBuyItem; }
}; };
/** Packet used by the client to buy mob upgrades /** Packet used by the client to buy mob upgrades
Packet used by the server to confirm transaction */ Packet used by the server to confirm transaction */
class PlayerBuyMobUpgradePacket : public Packet { class PlayerBuyMobUpgradePacket : public Packet {
private: private:
game::MobType m_MobType; game::MobType m_MobType;
std::uint8_t m_MobLevel; std::uint8_t m_MobLevel;
public: public:
PlayerBuyMobUpgradePacket() {} PlayerBuyMobUpgradePacket() {}
PlayerBuyMobUpgradePacket(game::MobType mobType, std::uint8_t level) : m_MobType(mobType), m_MobLevel(level) {} PlayerBuyMobUpgradePacket(game::MobType mobType, std::uint8_t level) : m_MobType(mobType), m_MobLevel(level) {}
virtual ~PlayerBuyMobUpgradePacket() {} virtual ~PlayerBuyMobUpgradePacket() {}
virtual DataBuffer Serialize(bool packetID = true) const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
game::MobType GetMobType() const { return m_MobType; } game::MobType GetMobType() const { return m_MobType; }
std::uint8_t GetLevel() const { return m_MobLevel; } std::uint8_t GetLevel() const { return m_MobLevel; }
virtual PacketType GetType() const { return PacketType::PlayerBuyMobUpgrade; } virtual PacketType GetType() const { return PacketType::PlayerBuyMobUpgrade; }
}; };
} // namespace protocol } // namespace protocol

View File

@@ -13,17 +13,17 @@
#if defined(__has_include) #if defined(__has_include)
#if __has_include(<GL/glew.h>) #if __has_include(<GL/glew.h>)
#define TD_IMPL_OPENGL_LOADER_GLEW #define TD_IMPL_OPENGL_LOADER_GLEW
#elif __has_include(<glad/glad.h>) #elif __has_include(<glad/glad.h>)
#define TD_IMPL_OPENGL_LOADER_GLAD #define TD_IMPL_OPENGL_LOADER_GLAD
#elif __has_include(<GL/gl3w.h>) #elif __has_include(<GL/gl3w.h>)
#define TD_IMPL_OPENGL_LOADER_GL3W #define TD_IMPL_OPENGL_LOADER_GL3W
#elif __has_include(<glbinding/glbinding.h>) #elif __has_include(<glbinding/glbinding.h>)
#define TD_IMPL_OPENGL_LOADER_GLBINDING3 #define TD_IMPL_OPENGL_LOADER_GLBINDING3
#elif __has_include(<glbinding/Binding.h>) #elif __has_include(<glbinding/Binding.h>)
#define TD_IMPL_OPENGL_LOADER_GLBINDING2 #define TD_IMPL_OPENGL_LOADER_GLBINDING2
#else #else
#error "Cannot detect OpenGL loader!" #error "Cannot detect OpenGL loader!"
#endif #endif
#else #else

View File

@@ -1,6 +1,6 @@
#pragma once #pragma once
#include <glm/glm.hpp> #include "Defines.h"
#include <memory> #include <memory>
#include "loader/GLLoader.h" #include "loader/GLLoader.h"
#include "render/shaders/WorldShader.h" #include "render/shaders/WorldShader.h"
@@ -9,47 +9,62 @@
namespace td { namespace td {
namespace render { namespace render {
struct Camera {
Mat4f viewMatrix;
Mat4f projectionMatrix;
Mat4f InvViewMatrix;
Mat4f InvProjectionMatrix;
float CamDistance = 25.0f;
Vec3f CamPos {0, CamDistance, 0};
Vec2f CamLook {};
float m_Yaw = -PI / 2.0f;
float m_Pitch = -PI / 2.0f + 0.0000001f;
};
class Renderer { class Renderer {
public: public:
static constexpr float m_AnimationSpeed = 2.0f; static constexpr float m_AnimationSpeed = 2.0f;
static constexpr float m_MouseSensitivity = 200.0f;
struct Model { struct Model {
GL::VertexArray* vao; GL::VertexArray* vao;
glm::vec2 positon; Vec3f positon;
}; Vec3f color = { 1, 1, 1 };
};
private: private:
std::unique_ptr<shader::WorldShader> m_WorldShader; std::unique_ptr<shader::WorldShader> m_WorldShader;
std::unique_ptr<shader::EntityShader> m_EntityShader; std::unique_ptr<shader::EntityShader> m_EntityShader;
glm::vec3 m_BackgroundColor; Vec2i m_WindowSize;
bool m_IsometricView = true; Vec3f m_BackgroundColor;
float m_IsometricShade = m_IsometricView;
glm::vec2 m_CamPos{}; Camera m_Camera {};
public: public:
Renderer(); Renderer();
~Renderer(); ~Renderer();
bool Init(); bool Init();
void Prepare(); void Prepare();
void Resize(const int width, const int height); void Resize(const int width, const int height);
void RenderVAO(const GL::VertexArray& vao); void RenderVAO(const GL::VertexArray& vao);
void RenderModel(const Model& model); void RenderModel(const Model& model);
void SetZoom(float zoom); void AddZoom(float zoom);
void SetCamMovement(const glm::vec2& mov); void SetCamAngularMovement(const Vec2f& mov);
void SetCamPos(const glm::vec2& newPos); void SetCamMovement(const Vec2f& lastCursorPos, const Vec2f& currentCursorPos);
void SetIsometricView(bool isometric); // false = 2D true = Isometric void SetCamLook(const Vec2f& worldPos);
void SetBackgroundColor(const glm::vec3& color) { m_BackgroundColor = color; } void SetBackgroundColor(const Vec3f& color) { m_BackgroundColor = color; }
glm::vec2 GetCursorWorldPos(const glm::vec2& cursorPos, float aspectRatio, float zoom, float windowWidth, float windowHeight); Vec2f GetCursorWorldPos(const Vec2f& cursorPos, float windowWidth, float windowHeight);
private: private:
void UpdateIsometricView(); void InitShaders();
void UpdateIsometricFade(); void SetCamPos(const Vec3f& newPos);
void InitShaders();
}; };
} // namespace render } // namespace render

View File

@@ -11,27 +11,27 @@ namespace render {
class VertexCache { class VertexCache {
typedef std::vector<float> Vector; typedef std::vector<float> Vector;
struct DataIndex { struct DataIndex {
Vector position; Vector position;
Vector color; Vector color;
}; };
private: private:
std::size_t m_VertexCount; std::size_t m_VertexCount;
std::unordered_map<std::uint64_t, DataIndex> m_Indexes; std::unordered_map<std::uint64_t, DataIndex> m_Indexes;
std::unique_ptr<GL::VertexArray> m_VertexArray; std::unique_ptr<GL::VertexArray> m_VertexArray;
public: public:
VertexCache() : m_VertexCount(0) {} VertexCache() : m_VertexCount(0) {}
void AddData(std::uint64_t index, std::vector<float> positions, std::vector<float> colors); void AddData(std::uint64_t index, std::vector<float> positions, std::vector<float> colors);
void RemoveData(std::uint64_t index); void RemoveData(std::uint64_t index);
void Clear(); void Clear();
void UpdateVertexArray(); void UpdateVertexArray();
const GL::VertexArray& GetVertexArray() const { return *m_VertexArray; } const GL::VertexArray& GetVertexArray() const { return *m_VertexArray; }
bool IsEmpty() const { return m_VertexArray == nullptr; } bool IsEmpty() const { return m_VertexArray == nullptr; }
}; };
} // namespace render } // namespace render

View File

@@ -6,13 +6,12 @@
#include "render/VertexCache.h" #include "render/VertexCache.h"
#include "render/gui/TowerPlacePopup.h" #include "render/gui/TowerPlacePopup.h"
#include "render/gui/TowerUpgradePopup.h"
#include "render/gui/MobTooltip.h" #include "render/gui/MobTooltip.h"
#include "render/gui/CastleTooltip.h" #include "render/gui/CastleTooltip.h"
#include "render/gui/imgui/imgui.h" #include "render/gui/imgui/imgui.h"
#include <glm/glm.hpp>
namespace td { namespace td {
namespace client { namespace client {
@@ -26,61 +25,61 @@ namespace render {
class WorldRenderer : public game::WorldListener { class WorldRenderer : public game::WorldListener {
private: private:
client::ClientGame* m_Client; client::ClientGame* m_Client;
Renderer* m_Renderer; Renderer* m_Renderer;
game::World* m_World; game::World* m_World;
std::unique_ptr<GL::VertexArray> m_WorldVao, m_MobVao, m_SelectTileVao; std::unique_ptr<GL::VertexArray> m_WorldVao, m_MobVao, m_SelectTileVao;
glm::vec2 m_CamPos; Vec2f m_CamPos;
glm::vec2 m_CursorPos; Vec2f m_CursorPos;
glm::vec2 m_HoldCursorPos; Vec2f m_HoldCursorPos;
glm::vec2 m_LastClicked; Vec2f m_LastClicked;
float m_Zoom; float m_Zoom;
float m_CamSensibility = 1; float m_CamSensibility = 1;
bool m_PopupOpened = false; bool m_PopupOpened = false;
VertexCache m_TowersCache; VertexCache m_TowersCache;
std::unique_ptr<gui::TowerPlacePopup> m_TowerPlacePopup; std::unique_ptr<gui::TowerPlacePopup> m_TowerPlacePopup;
std::unique_ptr<gui::MobTooltip> m_MobTooltip; std::unique_ptr<gui::TowerUpgradePopup> m_TowerUpgradePopup;
std::unique_ptr<gui::CastleTooltip> m_CastleTooltip; std::unique_ptr<gui::MobTooltip> m_MobTooltip;
std::unique_ptr<gui::CastleTooltip> m_CastleTooltip;
public: public:
WorldRenderer(game::World* world, client::ClientGame* client); WorldRenderer(game::World* world, client::ClientGame* client);
~WorldRenderer(); ~WorldRenderer();
void LoadModels(); void LoadModels();
static ImVec4 GetImGuiTeamColor(game::TeamColor color); static ImVec4 GetImGuiTeamColor(game::TeamColor color);
void Update(); void Update();
void Render(); void Render();
void SetCamPos(float camX, float camY); void SetCamPos(float camX, float camY);
void MoveCam(float relativeX, float relativeY, float aspectRatio); void MoveCam(float relativeX, float relativeY);
void ChangeZoom(float zoom); void ChangeZoom(float zoom);
// WorldListener // WorldListener
virtual void OnTowerAdd(game::TowerPtr tower); virtual void OnTowerAdd(game::TowerPtr tower);
virtual void OnTowerRemove(game::TowerPtr tower); virtual void OnTowerRemove(game::TowerPtr tower);
private: private:
void Click(); void Click();
void RenderWorld() const; void RenderWorld() const;
void RenderTowers() const; void RenderTowers() const;
void RenderMobs() const; void RenderMobs() const;
void RenderTileSelect() const; void RenderTileSelect() const;
void RenderPopups(); void RenderPopups();
void RenderTowerUpgradePopup(); void RenderMobTooltip() const;
void RenderMobTooltip() const; void RenderCastleTooltip() const;
void RenderCastleTooltip() const; void DetectClick();
void DetectClick(); void DetectMobHovering() const;
void DetectMobHovering() const; void DetectCastleHovering() const;
void DetectCastleHovering() const; void RenderTooltips() const;
void RenderTooltips() const; void RemoveTower();
void RemoveTower(); Vec2f GetCursorWorldPos() const;
glm::vec2 GetCursorWorldPos() const; Vec2f GetClickWorldPos() const;
glm::vec2 GetClickWorldPos() const;
void UpdateCursorPos(); void UpdateCursorPos();
}; };
} // namespace render } // namespace render

View File

@@ -14,14 +14,14 @@ namespace gui {
class CastleTooltip : public GuiWidget { class CastleTooltip : public GuiWidget {
private: private:
const game::TeamCastle* m_Castle; const game::TeamCastle* m_Castle;
public: public:
CastleTooltip(client::Client* client); CastleTooltip(client::Client* client);
virtual void Render(); virtual void Render();
void SetCastle(const game::TeamCastle* castle) { m_Castle = castle; } void SetCastle(const game::TeamCastle* castle) { m_Castle = castle; }
bool IsShown() { return m_Castle != nullptr; } bool IsShown() { return m_Castle != nullptr; }
}; };
} // namespace gui } // namespace gui

View File

@@ -7,13 +7,13 @@ namespace gui {
class FrameMenu : public GuiWidget { class FrameMenu : public GuiWidget {
private: private:
bool m_VSync; bool m_VSync;
bool m_IsometricView; bool m_IsometricView;
bool m_ShowDemoWindow; bool m_ShowDemoWindow;
public: public:
FrameMenu(client::Client* client); FrameMenu(client::Client* client);
virtual void Render(); virtual void Render();
}; };
} // namespace gui } // namespace gui

View File

@@ -7,17 +7,17 @@ namespace gui {
class GameMenu : public GuiWidget { class GameMenu : public GuiWidget {
private: private:
std::unique_ptr<SummonMenu> m_SummonMenu; std::unique_ptr<SummonMenu> m_SummonMenu;
public: public:
GameMenu(client::Client* client); GameMenu(client::Client* client);
virtual void Render(); virtual void Render();
private: private:
void ShowTPS(); void ShowTPS();
void ShowStats(); void ShowStats();
void ShowPlayers(); void ShowPlayers();
void ShowLobbyProgress(); void ShowLobbyProgress();
void ShowTeamSelection(); void ShowTeamSelection();
}; };
} // namespace gui } // namespace gui

View File

@@ -10,19 +10,19 @@ namespace gui {
class GuiManager { class GuiManager {
private: private:
std::vector<std::unique_ptr<GuiWidget>> m_Widgets; std::vector<std::unique_ptr<GuiWidget>> m_Widgets;
public: public:
GuiManager() {} GuiManager() {}
void RenderWidgets() { void RenderWidgets() {
for (auto& widget : m_Widgets) { for (auto& widget : m_Widgets) {
widget->Render(); widget->Render();
} }
} }
void AddWidget(std::unique_ptr<GuiWidget>&& widget) { void AddWidget(std::unique_ptr<GuiWidget>&& widget) {
m_Widgets.push_back(std::move(widget)); m_Widgets.push_back(std::move(widget));
} }
}; };
} // namespace gui } // namespace gui

View File

@@ -10,13 +10,13 @@ namespace gui {
class GuiWidget { class GuiWidget {
protected: protected:
client::Client* m_Client; client::Client* m_Client;
public: public:
GuiWidget(client::Client* client) : m_Client(client) {} GuiWidget(client::Client* client) : m_Client(client) {}
client::Client* GetClient() { return m_Client; } client::Client* GetClient() { return m_Client; }
virtual void Render() = 0; virtual void Render() = 0;
}; };
} // namespace gui } // namespace gui

View File

@@ -0,0 +1,9 @@
#pragma once
namespace td {
namespace gui {
extern void RenderLifeProgress(float progress);
} // namespace gui
} // namespace td

View File

@@ -13,24 +13,24 @@ namespace gui {
class MainMenu : public GuiWidget { class MainMenu : public GuiWidget {
private: private:
bool m_TriedToConnect = false; bool m_TriedToConnect = false;
bool m_TriedToCreate = false; bool m_TriedToCreate = false;
std::string m_ConnectAddress; std::string m_ConnectAddress;
int m_ConnectPort; int m_ConnectPort;
int m_ServerPort = 25565; int m_ServerPort = 25565;
std::string m_WorldFilePath; std::string m_WorldFilePath;
imgui_addons::ImGuiFileBrowser m_FileDialog; imgui_addons::ImGuiFileBrowser m_FileDialog;
std::unique_ptr<server::Server> m_Server; std::unique_ptr<server::Server> m_Server;
public: public:
MainMenu(client::Client* client); MainMenu(client::Client* client);
~MainMenu(); ~MainMenu();
virtual void Render(); virtual void Render();
const server::Server* GetServer() const { return m_Server.get(); } const server::Server* GetServer() const { return m_Server.get(); }
private: private:
bool StartServer(); bool StartServer();
}; };
} // namespace gui } // namespace gui

View File

@@ -14,14 +14,14 @@ namespace gui {
class MobTooltip : public GuiWidget { class MobTooltip : public GuiWidget {
private: private:
const game::Mob* m_Mob; const game::Mob* m_Mob;
public: public:
MobTooltip(client::Client* client); MobTooltip(client::Client* client);
virtual void Render(); virtual void Render();
void SetMob(const game::Mob* mob) { m_Mob = mob; } void SetMob(const game::Mob* mob) { m_Mob = mob; }
bool IsShown() { return m_Mob != nullptr; } bool IsShown() { return m_Mob != nullptr; }
}; };
} // namespace gui } // namespace gui

View File

@@ -10,16 +10,20 @@ namespace gui {
class SummonMenu : public GuiWidget { class SummonMenu : public GuiWidget {
private: private:
bool m_MenuOpened; bool m_MenuOpened;
int m_ImageWidth = 100; int m_ImageWidth = 100;
static constexpr int m_MobTypeCount = static_cast<std::size_t>(td::game::MobType::MOB_COUNT); float m_Cooldown;
std::array<int, static_cast<std::size_t>(m_MobTypeCount)> m_Values; float m_LastCooldown;
static constexpr int m_MobTypeCount = static_cast<std::size_t>(td::game::MobType::MOB_COUNT);
std::array<int, static_cast<std::size_t>(m_MobTypeCount)> m_Values;
public: public:
SummonMenu(client::Client* client); SummonMenu(client::Client* client);
virtual void Render(); void SetCooldown(float cooldown);
virtual void Render();
private: private:
void SetSummonMax(int valueIndex); void SetSummonMax(int valueIndex);
}; };
} // namespace gui } // namespace gui

View File

@@ -28,21 +28,21 @@ class Renderer;
class TowerGui { class TowerGui {
private: private:
SDL_Window* m_Window; SDL_Window* m_Window;
SDL_GLContext m_GlContext; SDL_GLContext m_GlContext;
td::render::Renderer* m_Renderer; td::render::Renderer* m_Renderer;
td::gui::GuiManager m_GuiManager; td::gui::GuiManager m_GuiManager;
std::unique_ptr<td::client::Client> m_Client; std::unique_ptr<td::client::Client> m_Client;
public: public:
TowerGui(SDL_Window* wndow, SDL_GLContext glContext, td::render::Renderer* renderer); TowerGui(SDL_Window* wndow, SDL_GLContext glContext, td::render::Renderer* renderer);
~TowerGui(); ~TowerGui();
void Render(); void Render();
private: private:
void InitWidgets(); void InitWidgets();
void Tick(); void Tick();
void BeginFrame(); void BeginFrame();
void EndFrame(); void EndFrame();
}; };
} // namespace render } // namespace render

View File

@@ -2,26 +2,26 @@
#include "GuiWidget.h" #include "GuiWidget.h"
#include <glm/glm.hpp> #include "Defines.h"
namespace td { namespace td {
namespace gui { namespace gui {
class TowerPlacePopup : public GuiWidget { class TowerPlacePopup : public GuiWidget {
private: private:
glm::vec2 m_ClickWorldPos; Vec2f m_ClickWorldPos;
public: public:
TowerPlacePopup(client::Client* client); TowerPlacePopup(client::Client* client);
virtual void Render(); virtual void Render();
void SetClickPos(const glm::vec2& worldPos); void SetClickPos(const Vec2f& worldPos);
private: private:
static constexpr float m_TowerPopupTileWidth = 200.0f; static constexpr float m_TowerPopupTileWidth = 200.0f;
static constexpr float m_TowerPopupTileHeight = 200.0f; static constexpr float m_TowerPopupTileHeight = 200.0f;
static constexpr float m_PlaceTowerButtonWidth = 150.0f; static constexpr float m_PlaceTowerButtonWidth = 150.0f;
static constexpr float m_PlaceTowerButtonHeight = 35.0f; static constexpr float m_PlaceTowerButtonHeight = 35.0f;
}; };
} // namespace gui } // namespace gui

View File

@@ -0,0 +1,32 @@
#pragma once
#include "GuiWidget.h"
#include "Defines.h"
namespace td {
namespace gui {
class TowerUpgradePopup : public GuiWidget {
private:
Vec2f m_ClickWorldPos;
bool m_ShouldBeClosed;
bool m_Opened;
public:
TowerUpgradePopup(client::Client* client);
virtual void Render();
void SetClickPos(const Vec2f& worldPos);
bool IsPopupOpened();
private:
static constexpr float m_TowerPopupTileWidth = 200.0f;
static constexpr float m_TowerPopupTileHeight = 200.0f;
static constexpr float m_PlaceTowerButtonWidth = 150.0f;
static constexpr float m_PlaceTowerButtonHeight = 35.0f;
};
} // namespace gui
} // namespace td

View File

@@ -2,27 +2,34 @@
#include "GuiWidget.h" #include "GuiWidget.h"
#include "updater/Updater.h"
#include <future> #include <future>
#include <memory>
namespace td { namespace td {
namespace utils {
class Updater;
} // namespace utils
namespace gui { namespace gui {
class UpdateMenu : public GuiWidget { class UpdateMenu : public GuiWidget {
private: private:
bool m_Opened; bool m_Opened;
std::string m_Error; std::string m_Error;
utils::Updater m_Updater; std::unique_ptr<utils::Updater> m_Updater;
std::shared_future<bool> m_UpdateAvailable; std::shared_future<bool> m_UpdateAvailable;
public: public:
UpdateMenu(client::Client* client); UpdateMenu(client::Client* client);
virtual ~UpdateMenu();
virtual void Render(); virtual void Render();
private: private:
void CheckUpdates(); void CheckUpdates();
bool IsUpdateChecked(); bool IsUpdateChecked();
void RenderErrorPopup(); void RenderErrorPopup();
}; };
} // namespace gui } // namespace gui

View File

@@ -9,8 +9,8 @@ namespace render {
namespace WorldLoader { namespace WorldLoader {
struct RenderData { struct RenderData {
std::vector<float> positions; std::vector<float> positions;
std::vector<float> colors; std::vector<float> colors;
}; };
GL::VertexArray LoadMobModel(); GL::VertexArray LoadMobModel();

View File

@@ -6,24 +6,22 @@ namespace td {
namespace shader { namespace shader {
class EntityShader : public ShaderProgram { class EntityShader : public ShaderProgram {
private: private:
unsigned int m_LocationCam = 0; unsigned int m_LocationProjectionMatrix = 0;
unsigned int m_LocationZoom = 0; unsigned int m_LocationViewMatrix = 0;
unsigned int m_LocationAspectRatio = 0; unsigned int m_LocationPosition = 0;
unsigned int m_LocationTranslation = 0; unsigned int m_LocationColorEffect = 0;
unsigned int m_LocationViewtype = 0;
protected: protected:
virtual void GetAllUniformLocation(); virtual void GetAllUniformLocation();
public: public:
EntityShader(); EntityShader();
void LoadShader(); void LoadShader();
void SetCamPos(const glm::vec2& camPos);
void SetZoom(float zoom); void SetColorEffect(const Vec3f& color);
void SetAspectRatio(float aspectRatio); void SetProjectionMatrix(const Mat4f& proj) const;
void SetModelPos(const glm::vec2& modelPos); void SetViewMatrix(const Mat4f& view) const;
void SetIsometricView(float isometric); void SetModelPos(const Vec3f& pos) const;
}; };
} // namespace shader } // namespace shader

View File

@@ -1,7 +1,7 @@
#pragma once #pragma once
#include <string> #include <string>
#include <glm/glm.hpp> #include "Defines.h"
#include "render/GL.h" #include "render/GL.h"
namespace td { namespace td {
@@ -24,11 +24,10 @@ protected:
void LoadFloat(unsigned int location, float value) const; void LoadFloat(unsigned int location, float value) const;
void LoadInt(unsigned int location, int value) const; void LoadInt(unsigned int location, int value) const;
void LoadVector(unsigned int location, const glm::vec2& vector) const; void LoadVector(unsigned int location, const Vec2f& vector) const;
void LoadVector(unsigned int location, const glm::vec3& vector) const; void LoadVector(unsigned int location, const Vec3f& vector) const;
void LoadVector(unsigned int location, const glm::vec4& vector) const;
void LoadBoolean(unsigned int location, bool value) const; void LoadBoolean(unsigned int location, bool value) const;
void LoadMatrix(unsigned int location, const glm::mat4& matrix) const; void LoadMat4(unsigned int location, const Mat4f& mat) const;
void CleanUp() const; void CleanUp() const;
private: private:

View File

@@ -7,16 +7,15 @@ namespace shader {
class WorldShader : public ShaderProgram { class WorldShader : public ShaderProgram {
private: private:
unsigned int m_LocationCam = 0, m_LocationZoom = 0, m_LocationAspectRatio = 0, m_LocationViewtype = 0; unsigned int m_LocationProjection = 0, m_LocationView = 0;
protected: protected:
void GetAllUniformLocation(); void GetAllUniformLocation();
public: public:
WorldShader(); WorldShader();
void LoadShader(); void LoadShader();
void SetCamPos(const glm::vec2& camPos);
void SetZoom(float zoom); void SetProjectionMatrix(const Mat4f& proj) const;
void SetAspectRatio(float aspectRatio); void SetViewMatrix(const Mat4f& view) const;
void SetIsometricView(float isometric);
}; };
} // namespace shader } // namespace shader

View File

@@ -2,42 +2,42 @@
#include "misc/DataBuffer.h" #include "misc/DataBuffer.h"
#define TD_VERSION "alpha-0.2.0" #define TD_VERSION "alpha-0.3.0"
namespace td { namespace td {
namespace utils { namespace utils {
class Updater { class Updater {
private: private:
float m_Progress; float m_Progress;
bool m_DownloadComplete; bool m_DownloadComplete;
bool m_FileWrited; bool m_FileWrited;
bool m_CancelDownload; bool m_CancelDownload;
DataBuffer m_FileBuffer; DataBuffer m_FileBuffer;
std::string m_LastVersion; std::string m_LastVersion;
public: public:
Updater() : m_Progress(0), m_DownloadComplete(false), m_FileWrited(false), m_CancelDownload(false) {} Updater() : m_Progress(0), m_DownloadComplete(false), m_FileWrited(false), m_CancelDownload(false) {}
bool CheckUpdate(); bool CheckUpdate();
void DownloadUpdate(); void DownloadUpdate();
void CancelDownload() { m_CancelDownload = true; m_Progress = 0.0f; m_DownloadComplete = false; } void CancelDownload() { m_CancelDownload = true; m_Progress = 0.0f; m_DownloadComplete = false; }
bool WriteFile(); bool WriteFile();
void ClearCache() { m_FileBuffer.Clear(); } void ClearCache() { m_FileBuffer.Clear(); }
float GetDownloadProgress() { return m_Progress; } float GetDownloadProgress() { return m_Progress; }
bool IsDownloadComplete() { return m_DownloadComplete; } bool IsDownloadComplete() { return m_DownloadComplete; }
bool IsFileWrited() { return m_FileWrited; } bool IsFileWrited() { return m_FileWrited; }
static std::string GetLocalFilePath(); static std::string GetLocalFilePath();
static void RemoveOldFile(); static void RemoveOldFile();
static std::string GetCurrentVersion() { return TD_VERSION; } static std::string GetCurrentVersion() { return TD_VERSION; }
std::string GetLastVersion() { return m_LastVersion; } std::string GetLastVersion() { return m_LastVersion; }
bool CanUpdate(); bool CanUpdate();
private: private:
std::string GetDownloadFileURL(); std::string GetDownloadFileURL();
}; };
} // namespace utils } // namespace utils

View File

@@ -21,19 +21,19 @@ extern "C"
int main(int argc, const char* args[]) { int main(int argc, const char* args[]) {
#if !defined(NDEBUG) #if !defined(NDEBUG)
// setup signal handling // setup signal handling
backward::SignalHandling sh; backward::SignalHandling sh;
#endif #endif
// remove the outdated binary // remove the outdated binary
td::utils::Updater::RemoveOldFile(); td::utils::Updater::RemoveOldFile();
Display::Create(); Display::Create();
while (!Display::IsCloseRequested()) { while (!Display::IsCloseRequested()) {
Display::PollEvents(); Display::PollEvents();
Display::Render(); Display::Render();
Display::Update(); Display::Update();
} }
Display::Destroy(); Display::Destroy();
return 0; return 0;
} }

View File

@@ -12,25 +12,25 @@ Game::~Game() {
} }
void Game::Tick(std::uint64_t delta) { void Game::Tick(std::uint64_t delta) {
if (m_GameState == GameState::Game) { if (m_GameState == GameState::Game) {
m_World->Tick(delta); m_World->Tick(delta);
} }
} }
Player* Game::GetPlayerById(PlayerID id) { Player* Game::GetPlayerById(PlayerID id) {
auto it = m_Players.find(id); auto it = m_Players.find(id);
if (it == m_Players.end()) return nullptr; if (it == m_Players.end()) return nullptr;
return &it->second; return &it->second;
} }
const Player* Game::GetPlayerById(PlayerID id) const { const Player* Game::GetPlayerById(PlayerID id) const {
auto it = m_Players.find(id); auto it = m_Players.find(id);
if (it == m_Players.end()) return nullptr; if (it == m_Players.end()) return nullptr;
return &it->second; return &it->second;
} }
} // namespace game } // namespace game

View File

@@ -29,44 +29,44 @@ Connexion::Connexion(protocol::PacketDispatcher* dispatcher, network::TCPSocket&
} }
bool Connexion::UpdateSocket() { bool Connexion::UpdateSocket() {
if (m_Socket.GetStatus() != network::Socket::Connected) if (m_Socket.GetStatus() != network::Socket::Connected)
return false; return false;
while (true) { while (true) {
DataBuffer buffer; DataBuffer buffer;
m_Socket.Receive(buffer, sizeof(std::uint64_t)); m_Socket.Receive(buffer, sizeof(std::uint64_t));
if (buffer.GetSize() == 0) if (buffer.GetSize() == 0)
break; break;
std::uint64_t packetLenght; std::uint64_t packetLenght;
buffer >> packetLenght; buffer >> packetLenght;
m_Socket.Receive(buffer, packetLenght); m_Socket.Receive(buffer, packetLenght);
DataBuffer decompressed = utils::Decompress(buffer, packetLenght); DataBuffer decompressed = utils::Decompress(buffer, packetLenght);
protocol::PacketType packetType; protocol::PacketType packetType;
decompressed >> packetType; decompressed >> packetType;
PacketPtr packet = protocol::PacketFactory::CreatePacket(packetType, decompressed); PacketPtr packet = protocol::PacketFactory::CreatePacket(packetType, decompressed);
GetDispatcher()->Dispatch(packet); GetDispatcher()->Dispatch(packet);
} }
return true; return true;
} }
bool Connexion::Connect(const std::string& address, std::uint16_t port) { bool Connexion::Connect(const std::string& address, std::uint16_t port) {
if (!m_Socket.Connect(address, port)) { if (!m_Socket.Connect(address, port)) {
return false; return false;
} }
m_Socket.SetBlocking(false); m_Socket.SetBlocking(false);
return true; return true;
} }
void Connexion::SendPacket(const protocol::Packet* packet) { void Connexion::SendPacket(const protocol::Packet* packet) {
network::SendPacket(packet->Serialize(), m_Socket); network::SendPacket(packet->Serialize(), m_Socket);
} }
void Connexion::CloseConnection() { void Connexion::CloseConnection() {
m_Socket.Disconnect(); m_Socket.Disconnect();
} }
Connexion::~Connexion() { Connexion::~Connexion() {

View File

@@ -9,251 +9,252 @@ namespace td {
namespace game { namespace game {
bool Mob::IsImmuneTo(TowerType type) { bool Mob::IsImmuneTo(TowerType type) {
return std::find(GetTowerImmunities().begin(), GetTowerImmunities().end(), type) != GetTowerImmunities().end(); return std::find(GetTowerImmunities().begin(), GetTowerImmunities().end(), type) != GetTowerImmunities().end();
} }
bool Mob::IsImmuneTo(EffectType type) { bool Mob::IsImmuneTo(EffectType type) {
return std::find(GetEffectImmunities().begin(), GetEffectImmunities().end(), type) != GetEffectImmunities().end(); return std::find(GetEffectImmunities().begin(), GetEffectImmunities().end(), type) != GetEffectImmunities().end();
} }
EffectDuration& Mob::GetEffect(EffectType effectType) { EffectDuration& Mob::GetEffect(EffectType effectType) {
return *std::find_if(m_Effects.begin(), m_Effects.end(), [&effectType](EffectDuration effect) { return effect.type == effectType;}); return *std::find_if(m_Effects.begin(), m_Effects.end(), [&effectType](EffectDuration effect) { return effect.type == effectType;});
} }
void Mob::AddEffect(EffectType effectType, float durationSec, Tower* tower) { void Mob::AddEffect(EffectType effectType, float durationSec, Tower* tower) {
if (IsImmuneTo(effectType)) if (IsImmuneTo(effectType))
return; return;
if (HasEffect(effectType)) { if (HasEffect(effectType)) {
EffectDuration& effect = GetEffect(effectType); EffectDuration& effect = GetEffect(effectType);
if (effect.duration < durationSec) if (effect.duration < durationSec)
effect.duration = durationSec; // Setting new duration if it's greater then the actual effect.duration = durationSec; // Setting new duration if it's greater then the actual
} else { } else {
m_Effects.push_back({ effectType, durationSec, tower }); m_Effects.push_back({ effectType, durationSec, tower });
} }
} }
void Mob::AttackCastle(std::uint64_t delta, World* world) { void Mob::AttackCastle(std::uint64_t delta, World* world) {
if (!HasReachedEnemyCastle()) return; if (!HasReachedEnemyCastle()) return;
if (m_AttackTimer.Update(delta)) { if (m_AttackTimer.Update(delta)) {
world->GetMobNotifier().NotifyListeners(&MobListener::OnMobCastleDamage, this, m_CastleTarget, GetStats()->GetDamage()); world->GetMobNotifier().NotifyListeners(&MobListener::OnMobCastleDamage, this, m_CastleTarget, GetStats()->GetDamage());
m_AttackTimer.ApplyCooldown(); m_AttackTimer.ApplyCooldown();
} }
} }
void Mob::Walk(std::uint64_t delta, World* world) { void Mob::Walk(std::uint64_t delta, World* world) {
float mobWalkSpeed = GetStats()->GetMovementSpeed(); float mobWalkSpeed = GetStats()->GetMovementSpeed();
float walkAmount = mobWalkSpeed * (static_cast<float>(delta) / 1000.0f); float walkAmount = mobWalkSpeed * (static_cast<float>(delta) / 1000.0f);
if (HasEffect(EffectType::Slowness)) if (HasEffect(EffectType::Slowness))
walkAmount *= 0.70; // walk 30% slower walkAmount *= 0.70; // walk 30% slower
switch (GetDirection()) { switch (GetDirection()) {
case Direction::NegativeX: { case Direction::NegativeX: {
SetCenterX(GetCenterX() - walkAmount); SetCenterX(GetCenterX() - walkAmount);
break; break;
} }
case Direction::PositiveX: { case Direction::PositiveX: {
SetCenterX(GetCenterX() + walkAmount); SetCenterX(GetCenterX() + walkAmount);
break; break;
} }
case Direction::NegativeY: { case Direction::NegativeY: {
SetCenterY(GetCenterY() - walkAmount); SetCenterY(GetCenterY() - walkAmount);
break; break;
} }
case Direction::PositiveY: { case Direction::PositiveY: {
SetCenterY(GetCenterY() + walkAmount); SetCenterY(GetCenterY() + walkAmount);
break; break;
} }
default: default:
break; break;
} }
} }
void Mob::Move(std::uint64_t delta, World* world) { void Mob::Move(std::uint64_t delta, World* world) {
TilePtr tile = world->GetTile(GetCenter().GetX(), GetCenter().GetY()); TilePtr tile = world->GetTile(GetCenter().GetX(), GetCenter().GetY());
if (tile != nullptr && tile->GetType() == TileType::Walk) { if (tile != nullptr && tile->GetType() == TileType::Walk) {
WalkableTilePtr walkTile = std::static_pointer_cast<WalkableTile>(tile); WalkableTilePtr walkTile = std::static_pointer_cast<WalkableTile>(tile);
ChangeDirection(*walkTile, world); ChangeDirection(*walkTile, world);
} }
if (HasReachedEnemyCastle()) return; if (HasReachedEnemyCastle()) return;
Walk(delta, world); Walk(delta, world);
TeamColor mobTeam = world->GetPlayerById(GetSender())->GetTeamColor(); TeamColor mobTeam = world->GetPlayerById(GetSender())->GetTeamColor();
TeamCastle* enemyCastle = nullptr; TeamCastle* enemyCastle = nullptr;
if (mobTeam == TeamColor::Red) { if (mobTeam == TeamColor::Red) {
enemyCastle = &world->GetBlueTeam().GetCastle(); enemyCastle = &world->GetBlueTeam().GetCastle();
} else if (mobTeam == TeamColor::Blue) { } else if (mobTeam == TeamColor::Blue) {
enemyCastle = &world->GetRedTeam().GetCastle(); enemyCastle = &world->GetRedTeam().GetCastle();
} }
if (IsTouchingCastle(*enemyCastle)) { if (IsTouchingCastle(*enemyCastle)) {
MoveBack(*enemyCastle, world); MoveBack(*enemyCastle, world);
SetMobReachedCastle(enemyCastle); SetMobReachedCastle(enemyCastle);
world->GetMobNotifier().NotifyListeners(&MobListener::OnMobTouchCastle, this, enemyCastle); world->GetMobNotifier().NotifyListeners(&MobListener::OnMobTouchCastle, this, enemyCastle);
} }
} }
void Mob::MoveBack(const TeamCastle& enemyCastle, World* world) { void Mob::MoveBack(const TeamCastle& enemyCastle, World* world) {
switch (GetDirection()) { switch (GetDirection()) {
case Direction::NegativeX: { case Direction::NegativeX: {
SetCenterX(enemyCastle.GetBottomRight().GetX() + GetWidth() / 2.0f); SetCenterX(enemyCastle.GetBottomRight().GetX() + GetWidth() / 2.0f);
break; break;
} }
case Direction::PositiveX: { case Direction::PositiveX: {
SetCenterX(enemyCastle.GetTopLeft().GetX() - GetWidth() / 2.0f); SetCenterX(enemyCastle.GetTopLeft().GetX() - GetWidth() / 2.0f);
break; break;
} }
case Direction::NegativeY: { case Direction::NegativeY: {
SetCenterY(enemyCastle.GetBottomRight().GetY() + GetHeight() / 2.0f); SetCenterY(enemyCastle.GetBottomRight().GetY() + GetHeight() / 2.0f);
break; break;
} }
case Direction::PositiveY: { case Direction::PositiveY: {
SetCenterY(enemyCastle.GetTopLeft().GetY() - GetHeight() / 2.0f); SetCenterY(enemyCastle.GetTopLeft().GetY() - GetHeight() / 2.0f);
break; break;
} }
default: default:
break; break;
} }
} }
void Mob::ChangeDirection(const WalkableTile& tile, World* world) { void Mob::ChangeDirection(const WalkableTile& tile, World* world) {
if (GetDirection() == tile.direction) return; if (GetDirection() == tile.direction) return;
float tileX = static_cast<float>(static_cast<std::int32_t>(GetCenterX())); float tileX = static_cast<float>(static_cast<std::int32_t>(GetCenterX()));
float tileY = static_cast<float>(static_cast<std::int32_t>(GetCenterY())); float tileY = static_cast<float>(static_cast<std::int32_t>(GetCenterY()));
switch (GetDirection()) { switch (GetDirection()) {
case Direction::PositiveY: { case Direction::PositiveY: {
if (tile.direction == Direction::NegativeX) { if (tile.direction == Direction::NegativeX) {
if (GetTileY() > GetTileX()) { if (GetTileY() > GetTileX()) {
SetCenterY(tileY + GetTileX()); SetCenterY(tileY + GetTileX());
SetDirection(tile.direction); SetDirection(tile.direction);
} }
} else { // tile->direction = Direction::PositiveX } else { // tile->direction = Direction::PositiveX
if (GetTileY() > 1 - GetTileX()) { if (GetTileY() > 1 - GetTileX()) {
SetCenterY(tileY + (1 - GetTileX())); SetCenterY(tileY + (1 - GetTileX()));
SetDirection(tile.direction); SetDirection(tile.direction);
} }
} }
return; return;
} }
case Direction::NegativeY: { case Direction::NegativeY: {
if (tile.direction == Direction::PositiveX) { if (tile.direction == Direction::PositiveX) {
if (GetTileY() < GetTileX()) { if (GetTileY() < GetTileX()) {
SetCenterY(tileY + GetTileX()); SetCenterY(tileY + GetTileX());
SetDirection(tile.direction); SetDirection(tile.direction);
} }
} else { // tile.direction = Direction::NegativeX } else { // tile.direction = Direction::NegativeX
if (GetTileY() < 1 - GetTileX()) { if (GetTileY() < 1 - GetTileX()) {
SetCenterY(tileY + (1 - GetTileX())); SetCenterY(tileY + (1 - GetTileX()));
SetDirection(tile.direction); SetDirection(tile.direction);
} }
} }
return; return;
} }
case Direction::PositiveX: { case Direction::PositiveX: {
if (tile.direction == Direction::NegativeY) { if (tile.direction == Direction::NegativeY) {
if (GetTileX() > GetTileY()) { if (GetTileX() > GetTileY()) {
SetCenterX(tileX + GetTileY()); SetCenterX(tileX + GetTileY());
SetDirection(tile.direction); SetDirection(tile.direction);
} }
} else { // tile.direction = Direction::PositiveY } else { // tile.direction = Direction::PositiveY
if (GetTileX() > 1 - GetTileY()) { if (GetTileX() > 1 - GetTileY()) {
SetCenterX(tileX + (1 - GetTileY())); SetCenterX(tileX + (1 - GetTileY()));
SetDirection(tile.direction); SetDirection(tile.direction);
} }
} }
return; return;
} }
case Direction::NegativeX: { case Direction::NegativeX: {
if (tile.direction == Direction::PositiveY) { if (tile.direction == Direction::PositiveY) {
if (GetTileX() < GetTileY()) { if (GetTileX() < GetTileY()) {
SetCenterX(tileX + GetTileY()); SetCenterX(tileX + GetTileY());
SetDirection(tile.direction); SetDirection(tile.direction);
} }
} else { // tile.direction = Direction::NegativeY } else { // tile.direction = Direction::NegativeY
if (GetTileX() < 1 - GetTileY()) { if (GetTileX() < 1 - GetTileY()) {
SetCenterX(tileX + (1 - GetTileY())); SetCenterX(tileX + (1 - GetTileY()));
SetDirection(tile.direction); SetDirection(tile.direction);
} }
} }
return; return;
} }
default: default:
break; break;
} }
} }
bool Mob::IsTouchingCastle(const TeamCastle& enemyCastle) const { bool Mob::IsTouchingCastle(const TeamCastle& enemyCastle) const {
return enemyCastle.CollidesWith(*this); return enemyCastle.CollidesWith(*this);
} }
void Mob::Tick(std::uint64_t delta, World* world) { void Mob::Tick(std::uint64_t delta, World* world) {
UpdateEffects(delta, world); m_HitCooldown = std::max(0.0f, m_HitCooldown - static_cast<float>(delta / 1000.0f));
Move(delta, world); UpdateEffects(delta, world);
AttackCastle(delta, world); Move(delta, world);
AttackCastle(delta, world);
} }
void Mob::UpdateEffects(std::uint64_t delta, World* world) { void Mob::UpdateEffects(std::uint64_t delta, World* world) {
float deltaSec = static_cast<float>(delta / 1000.0f); float deltaSec = static_cast<float>(delta / 1000.0f);
for (std::size_t i = 0; i < m_Effects.size(); i++) { for (std::size_t i = 0; i < m_Effects.size(); i++) {
EffectDuration& effect = m_Effects[i]; EffectDuration& effect = m_Effects[i];
effect.duration -= deltaSec; effect.duration -= deltaSec;
if (effect.duration < 0) { // effect has gone if (effect.duration < 0) { // effect has gone
m_Effects.erase(m_Effects.begin() + static_cast<int>(i)); m_Effects.erase(m_Effects.begin() + static_cast<int>(i));
switch (effect.type) { switch (effect.type) {
case EffectType::Fire: { case EffectType::Fire: {
m_EffectFireTimer.Reset(); m_EffectFireTimer.Reset();
break; break;
} }
case EffectType::Poison: { case EffectType::Poison: {
m_EffectPoisonTimer.Reset(); m_EffectPoisonTimer.Reset();
break; break;
} }
case EffectType::Heal: { case EffectType::Heal: {
m_EffectHealTimer.Reset(); m_EffectHealTimer.Reset();
} }
default: default:
break; break;
} }
} }
} }
if (HasEffect(EffectType::Fire)) { if (HasEffect(EffectType::Fire)) {
if (m_EffectFireTimer.Update(delta)) { if (m_EffectFireTimer.Update(delta)) {
world->GetMobNotifier().NotifyListeners(&MobListener::OnMobDamage, this, 3.0f, GetEffect(EffectType::Fire).tower); world->GetMobNotifier().NotifyListeners(&MobListener::OnMobDamage, this, 3.0f, GetEffect(EffectType::Fire).tower);
} }
} }
if (HasEffect(EffectType::Poison)) { if (HasEffect(EffectType::Poison)) {
if (m_EffectPoisonTimer.Update(delta)) { if (m_EffectPoisonTimer.Update(delta)) {
world->GetMobNotifier().NotifyListeners(&MobListener::OnMobDamage, this, 1.0f, GetEffect(EffectType::Poison).tower); world->GetMobNotifier().NotifyListeners(&MobListener::OnMobDamage, this, 1.0f, GetEffect(EffectType::Poison).tower);
} }
} }
if (HasEffect(EffectType::Heal)) { if (HasEffect(EffectType::Heal)) {
if (m_EffectFireTimer.Update(delta)) { if (m_EffectFireTimer.Update(delta)) {
Heal(10); Heal(10);
} }
} }
} }
bool Mob::HasEffect(EffectType type) { bool Mob::HasEffect(EffectType type) {
return std::find_if(m_Effects.begin(), m_Effects.end(), [&type](EffectDuration effect) { return effect.type == type;}) != m_Effects.end(); return std::find_if(m_Effects.begin(), m_Effects.end(), [&type](EffectDuration effect) { return effect.type == type;}) != m_Effects.end();
} }
@@ -262,248 +263,248 @@ bool Mob::HasEffect(EffectType type) {
typedef std::pair<MobType, std::uint8_t> MobKey; typedef std::pair<MobType, std::uint8_t> MobKey;
static const std::map<MobKey, MobStats> MobConstants = { static const std::map<MobKey, MobStats> MobConstants = {
// damage speed size money_cost exp_cost exp_reward max_health // damage speed size money_cost exp_cost exp_reward max_health
{{MobType::Zombie, 1},{MobStats{1, 1.6, {1, 1}, 15, 0, 7, 40}}}, {{MobType::Zombie, 1},{MobStats{1, 1.6, {1, 1}, 15, 0, 7, 40}}},
{{MobType::Zombie, 2},{MobStats{1, 1.6, {1, 1}, 18, 88, 9, 56}}}, {{MobType::Zombie, 2},{MobStats{1, 1.6, {1, 1}, 18, 88, 9, 56}}},
{{MobType::Zombie, 3},{MobStats{1, 1.6, {1, 1}, 22, 153, 10, 78}}}, {{MobType::Zombie, 3},{MobStats{1, 1.6, {1, 1}, 22, 153, 10, 78}}},
{{MobType::Zombie, 4},{MobStats{1.5, 1.6, {1, 1}, 26, 268, 13, 110}}}, {{MobType::Zombie, 4},{MobStats{1.5, 1.6, {1, 1}, 26, 268, 13, 110}}},
{{MobType::Zombie, 5},{MobStats{2, 1.6, {1, 1}, 31, 469, 15, 154}}}, {{MobType::Zombie, 5},{MobStats{2, 1.6, {1, 1}, 31, 469, 15, 154}}},
{{MobType::Spider, 1},{MobStats{1, 1.6, {1, 1}, 25, 100, 15, 80}}}, {{MobType::Spider, 1},{MobStats{1, 1.6, {1, 1}, 25, 100, 15, 80}}},
{{MobType::Spider, 2},{MobStats{1, 2, {1, 1}, 30, 175, 16, 112}}}, {{MobType::Spider, 2},{MobStats{1, 2, {1, 1}, 30, 175, 16, 112}}},
{{MobType::Spider, 3},{MobStats{1.5, 2, {1, 1}, 36, 306, 18, 157}}}, {{MobType::Spider, 3},{MobStats{1.5, 2, {1, 1}, 36, 306, 18, 157}}},
{{MobType::Spider, 4},{MobStats{2.5, 2, {1, 1}, 43, 536, 19, 222}}}, {{MobType::Spider, 4},{MobStats{2.5, 2, {1, 1}, 43, 536, 19, 222}}},
{{MobType::Spider, 5},{MobStats{1.5, 2.5, {1, 1}, 52, 938, 22, 307}}}, {{MobType::Spider, 5},{MobStats{1.5, 2.5, {1, 1}, 52, 938, 22, 307}}},
{{MobType::Skeleton, 1},{MobStats{1, 1.6, {1, 1}, 120, 200, 30, 350}}}, {{MobType::Skeleton, 1},{MobStats{1, 1.6, {1, 1}, 120, 200, 30, 350}}},
{{MobType::Skeleton, 2},{MobStats{1, 1.6, {1, 1}, 144, 350, 33, 490}}}, {{MobType::Skeleton, 2},{MobStats{1, 1.6, {1, 1}, 144, 350, 33, 490}}},
{{MobType::Skeleton, 3},{MobStats{1, 1.6, {1, 1}, 173, 613, 36, 686}}}, {{MobType::Skeleton, 3},{MobStats{1, 1.6, {1, 1}, 173, 613, 36, 686}}},
{{MobType::Skeleton, 4},{MobStats{1.5, 1.6, {1, 1}, 225, 1072, 40, 960}}}, {{MobType::Skeleton, 4},{MobStats{1.5, 1.6, {1, 1}, 225, 1072, 40, 960}}},
{{MobType::Skeleton, 5},{MobStats{2, 1.6, {1, 1}, 255, 1876, 43, 1345}}}, {{MobType::Skeleton, 5},{MobStats{2, 1.6, {1, 1}, 255, 1876, 43, 1345}}},
{{MobType::Pigman, 1},{MobStats{1, 2, {1, 1}, 100, 150, 22, 150}}}, {{MobType::Pigman, 1},{MobStats{1, 2, {1, 1}, 100, 150, 22, 150}}},
{{MobType::Pigman, 2},{MobStats{1, 2, {1, 1}, 120, 263, 24, 210}}}, {{MobType::Pigman, 2},{MobStats{1, 2, {1, 1}, 120, 263, 24, 210}}},
{{MobType::Pigman, 3},{MobStats{1, 2, {1, 1}, 144, 459, 25, 297}}}, {{MobType::Pigman, 3},{MobStats{1, 2, {1, 1}, 144, 459, 25, 297}}},
{{MobType::Pigman, 4},{MobStats{1, 2, {1, 1}, 173, 804, 25, 412}}}, {{MobType::Pigman, 4},{MobStats{1, 2, {1, 1}, 173, 804, 25, 412}}},
{{MobType::Pigman, 5},{MobStats{1.5, 2, {1, 1}, 207, 1407, 27, 576}}}, {{MobType::Pigman, 5},{MobStats{1.5, 2, {1, 1}, 207, 1407, 27, 576}}},
{{MobType::Creeper, 1},{MobStats{1, 2, {1, 1}, 250, 325, 46, 350}}}, {{MobType::Creeper, 1},{MobStats{1, 2, {1, 1}, 250, 325, 46, 350}}},
{{MobType::Creeper, 2},{MobStats{1, 2, {1, 1}, 290, 550, 49, 460}}}, {{MobType::Creeper, 2},{MobStats{1, 2, {1, 1}, 290, 550, 49, 460}}},
{{MobType::Creeper, 3},{MobStats{2, 2, {1, 1}, 350, 800, 55, 630}}}, {{MobType::Creeper, 3},{MobStats{2, 2, {1, 1}, 350, 800, 55, 630}}},
{{MobType::Creeper, 4},{MobStats{3, 2, {1, 1}, 420, 1300, 61, 900}}}, {{MobType::Creeper, 4},{MobStats{3, 2, {1, 1}, 420, 1300, 61, 900}}},
{{MobType::Creeper, 5},{MobStats{4, 2, {1, 1}, 510, 1850, 67, 1250}}}, {{MobType::Creeper, 5},{MobStats{4, 2, {1, 1}, 510, 1850, 67, 1250}}},
{{MobType::Silverfish, 1},{MobStats{1, 1.6, {1, 1}, 38, 125, 18, 120}}}, {{MobType::Silverfish, 1},{MobStats{1, 1.6, {1, 1}, 38, 125, 18, 120}}},
{{MobType::Silverfish, 2},{MobStats{1, 1.6, {1, 1}, 50, 230, 19, 170}}}, {{MobType::Silverfish, 2},{MobStats{1, 1.6, {1, 1}, 50, 230, 19, 170}}},
{{MobType::Silverfish, 3},{MobStats{1, 1.6, {1, 1}, 75, 340, 25, 225}}}, {{MobType::Silverfish, 3},{MobStats{1, 1.6, {1, 1}, 75, 340, 25, 225}}},
{{MobType::Silverfish, 4},{MobStats{1.5, 1.6, {1, 1}, 170, 700, 33, 310}}}, {{MobType::Silverfish, 4},{MobStats{1.5, 1.6, {1, 1}, 170, 700, 33, 310}}},
{{MobType::Silverfish, 5},{MobStats{1.5, 1.6, {1, 1}, 200, 1800, 36, 390}}}, {{MobType::Silverfish, 5},{MobStats{1.5, 1.6, {1, 1}, 200, 1800, 36, 390}}},
{{MobType::Blaze, 1},{MobStats{1, 1.6, {1, 1}, 500, 500, 105, 410}}}, {{MobType::Blaze, 1},{MobStats{1, 1.6, {1, 1}, 500, 500, 105, 410}}},
{{MobType::Blaze, 2},{MobStats{1, 1.6, {1, 1}, 600, 875, 111, 574}}}, {{MobType::Blaze, 2},{MobStats{1, 1.6, {1, 1}, 600, 875, 111, 574}}},
{{MobType::Blaze, 3},{MobStats{1, 1.6, {1, 1}, 720, 1531, 115, 804}}}, {{MobType::Blaze, 3},{MobStats{1, 1.6, {1, 1}, 720, 1531, 115, 804}}},
{{MobType::Blaze, 4},{MobStats{1.5, 1.6, {1, 1}, 864, 2680, 121, 1125}}}, {{MobType::Blaze, 4},{MobStats{1.5, 1.6, {1, 1}, 864, 2680, 121, 1125}}},
{{MobType::Blaze, 5},{MobStats{2, 1.6, {1, 1}, 1037, 4689, 127, 1575}}}, {{MobType::Blaze, 5},{MobStats{2, 1.6, {1, 1}, 1037, 4689, 127, 1575}}},
{{MobType::Witch, 1},{MobStats{1, 1.6, {1, 1}, 150, 300, 37, 300}}}, {{MobType::Witch, 1},{MobStats{1, 1.6, {1, 1}, 150, 300, 37, 300}}},
{{MobType::Witch, 2},{MobStats{1, 1.6, {1, 1}, 165, 525, 39, 405}}}, {{MobType::Witch, 2},{MobStats{1, 1.6, {1, 1}, 165, 525, 39, 405}}},
{{MobType::Witch, 3},{MobStats{1, 1.6, {1, 1}, 182, 918, 42, 547}}}, {{MobType::Witch, 3},{MobStats{1, 1.6, {1, 1}, 182, 918, 42, 547}}},
{{MobType::Witch, 4},{MobStats{1.5, 1.6, {1, 1}, 200, 1606, 43, 738}}}, {{MobType::Witch, 4},{MobStats{1.5, 1.6, {1, 1}, 200, 1606, 43, 738}}},
{{MobType::Witch, 5},{MobStats{2, 1.6, {1, 1}, 220, 2810, 45, 996}}}, {{MobType::Witch, 5},{MobStats{2, 1.6, {1, 1}, 220, 2810, 45, 996}}},
{{MobType::Slime, 1},{MobStats{1, 0.8, {1, 1}, 1500, 1000, 300, 800}}}, {{MobType::Slime, 1},{MobStats{1, 0.8, {1, 1}, 1500, 1000, 300, 800}}},
{{MobType::Slime, 2},{MobStats{1.5, 0.8, {1, 1}, 1800, 1750, 314, 880}}}, {{MobType::Slime, 2},{MobStats{1.5, 0.8, {1, 1}, 1800, 1750, 314, 880}}},
{{MobType::Slime, 3},{MobStats{2, 0.8, {1, 1}, 2160, 3063, 330, 968}}}, {{MobType::Slime, 3},{MobStats{2, 0.8, {1, 1}, 2160, 3063, 330, 968}}},
{{MobType::Slime, 4},{MobStats{2.5, 0.8, {1, 1}, 2592, 5359, 348, 1065}}}, {{MobType::Slime, 4},{MobStats{2.5, 0.8, {1, 1}, 2592, 5359, 348, 1065}}},
{{MobType::Slime, 5},{MobStats{3, 0.8, {1, 1}, 3110, 9379, 366, 1171}}}, {{MobType::Slime, 5},{MobStats{3, 0.8, {1, 1}, 3110, 9379, 366, 1171}}},
{{MobType::Giant, 1},{MobStats{10, 0.8, {1, 1}, 4000, 2250, 600, 6250}}}, {{MobType::Giant, 1},{MobStats{10, 0.8, {1, 1}, 4000, 2250, 600, 6250}}},
{{MobType::Giant, 2},{MobStats{20, 0.8, {1, 1}, 4500, 4000, 612, 9375}}}, {{MobType::Giant, 2},{MobStats{20, 0.8, {1, 1}, 4500, 4000, 612, 9375}}},
{{MobType::Giant, 3},{MobStats{30, 0.8, {1, 1}, 5062, 7250, 624, 14062}}}, {{MobType::Giant, 3},{MobStats{30, 0.8, {1, 1}, 5062, 7250, 624, 14062}}},
{{MobType::Giant, 4},{MobStats{40, 0.8, {1, 1}, 5695, 12500, 636, 21093}}}, {{MobType::Giant, 4},{MobStats{40, 0.8, {1, 1}, 5695, 12500, 636, 21093}}},
{{MobType::Giant, 5},{MobStats{50, 0.8, {1, 1}, 6407, 22000, 648, 31640}}}, {{MobType::Giant, 5},{MobStats{50, 0.8, {1, 1}, 6407, 22000, 648, 31640}}},
}; };
const MobStats* GetMobStats(MobType type, std::uint8_t level) { const MobStats* GetMobStats(MobType type, std::uint8_t level) {
return &MobConstants.at(MobKey{ type, level }); return &MobConstants.at(MobKey{ type, level });
} }
static const std::map<MobKey, TowerImmunities> MobsTowerImmunities = { static const std::map<MobKey, TowerImmunities> MobsTowerImmunities = {
{{MobType::Zombie, 1},{}}, {{MobType::Zombie, 1},{}},
{{MobType::Zombie, 2},{}}, {{MobType::Zombie, 2},{}},
{{MobType::Zombie, 3},{}}, {{MobType::Zombie, 3},{}},
{{MobType::Zombie, 4},{}}, {{MobType::Zombie, 4},{}},
{{MobType::Zombie, 5},{}}, {{MobType::Zombie, 5},{}},
{{MobType::Spider, 1},{}}, {{MobType::Spider, 1},{}},
{{MobType::Spider, 2},{}}, {{MobType::Spider, 2},{}},
{{MobType::Spider, 3},{}}, {{MobType::Spider, 3},{}},
{{MobType::Spider, 4},{TowerType::Archer, TowerType::Artillery, TowerType::Leach, TowerType::Necromancer, TowerType::Poison, TowerType::Quake, TowerType::Sorcerer, TowerType::Turret, TowerType::Zeus}}, {{MobType::Spider, 4},{TowerType::Archer, TowerType::Artillery, TowerType::Leach, TowerType::Necromancer, TowerType::Poison, TowerType::Quake, TowerType::Sorcerer, TowerType::Turret, TowerType::Zeus}},
{{MobType::Spider, 5},{TowerType::Archer, TowerType::Artillery, TowerType::Leach, TowerType::Necromancer, TowerType::Poison, TowerType::Quake, TowerType::Sorcerer, TowerType::Turret, TowerType::Zeus}}, {{MobType::Spider, 5},{TowerType::Archer, TowerType::Artillery, TowerType::Leach, TowerType::Necromancer, TowerType::Poison, TowerType::Quake, TowerType::Sorcerer, TowerType::Turret, TowerType::Zeus}},
{{MobType::Skeleton, 1},{}}, {{MobType::Skeleton, 1},{}},
{{MobType::Skeleton, 2},{}}, {{MobType::Skeleton, 2},{}},
{{MobType::Skeleton, 3},{}}, {{MobType::Skeleton, 3},{}},
{{MobType::Skeleton, 4},{}}, {{MobType::Skeleton, 4},{}},
{{MobType::Skeleton, 5},{}}, {{MobType::Skeleton, 5},{}},
{{MobType::Pigman, 1},{TowerType::Zeus}}, {{MobType::Pigman, 1},{TowerType::Zeus}},
{{MobType::Pigman, 2},{TowerType::Zeus}}, {{MobType::Pigman, 2},{TowerType::Zeus}},
{{MobType::Pigman, 3},{TowerType::Zeus}}, {{MobType::Pigman, 3},{TowerType::Zeus}},
{{MobType::Pigman, 4},{TowerType::Zeus}}, {{MobType::Pigman, 4},{TowerType::Zeus}},
{{MobType::Pigman, 5},{TowerType::Zeus}}, {{MobType::Pigman, 5},{TowerType::Zeus}},
{{MobType::Creeper, 1},{}}, {{MobType::Creeper, 1},{}},
{{MobType::Creeper, 2},{}}, {{MobType::Creeper, 2},{}},
{{MobType::Creeper, 3},{}}, {{MobType::Creeper, 3},{}},
{{MobType::Creeper, 4},{}}, {{MobType::Creeper, 4},{}},
{{MobType::Creeper, 5},{}}, {{MobType::Creeper, 5},{}},
{{MobType::Silverfish, 1},{}}, {{MobType::Silverfish, 1},{}},
{{MobType::Silverfish, 2},{}}, {{MobType::Silverfish, 2},{}},
{{MobType::Silverfish, 3},{}}, {{MobType::Silverfish, 3},{}},
{{MobType::Silverfish, 4},{}}, {{MobType::Silverfish, 4},{}},
{{MobType::Silverfish, 5},{}}, {{MobType::Silverfish, 5},{}},
{{MobType::Blaze, 1},{}}, {{MobType::Blaze, 1},{}},
{{MobType::Blaze, 2},{}}, {{MobType::Blaze, 2},{}},
{{MobType::Blaze, 3},{}}, {{MobType::Blaze, 3},{}},
{{MobType::Blaze, 4},{}}, {{MobType::Blaze, 4},{}},
{{MobType::Blaze, 5},{}}, {{MobType::Blaze, 5},{}},
{{MobType::Witch, 1},{TowerType::Zeus, TowerType::Mage, TowerType::Poison}}, {{MobType::Witch, 1},{TowerType::Zeus, TowerType::Mage, TowerType::Poison}},
{{MobType::Witch, 2},{TowerType::Zeus, TowerType::Mage, TowerType::Poison}}, {{MobType::Witch, 2},{TowerType::Zeus, TowerType::Mage, TowerType::Poison}},
{{MobType::Witch, 3},{TowerType::Zeus, TowerType::Mage, TowerType::Poison}}, {{MobType::Witch, 3},{TowerType::Zeus, TowerType::Mage, TowerType::Poison}},
{{MobType::Witch, 4},{TowerType::Zeus, TowerType::Mage, TowerType::Poison}}, {{MobType::Witch, 4},{TowerType::Zeus, TowerType::Mage, TowerType::Poison}},
{{MobType::Witch, 5},{TowerType::Zeus, TowerType::Mage, TowerType::Poison}}, {{MobType::Witch, 5},{TowerType::Zeus, TowerType::Mage, TowerType::Poison}},
{{MobType::Slime, 1},{}}, {{MobType::Slime, 1},{}},
{{MobType::Slime, 2},{}}, {{MobType::Slime, 2},{}},
{{MobType::Slime, 3},{}}, {{MobType::Slime, 3},{}},
{{MobType::Slime, 4},{}}, {{MobType::Slime, 4},{}},
{{MobType::Slime, 5},{}}, {{MobType::Slime, 5},{}},
{{MobType::Giant, 1},{}}, {{MobType::Giant, 1},{}},
{{MobType::Giant, 2},{}}, {{MobType::Giant, 2},{}},
{{MobType::Giant, 3},{}}, {{MobType::Giant, 3},{}},
{{MobType::Giant, 4},{}}, {{MobType::Giant, 4},{}},
{{MobType::Giant, 5},{}}, {{MobType::Giant, 5},{}},
}; };
const TowerImmunities& GetMobTowerImmunities(MobType type, std::uint8_t level) { const TowerImmunities& GetMobTowerImmunities(MobType type, std::uint8_t level) {
return MobsTowerImmunities.at({ type, level }); return MobsTowerImmunities.at({ type, level });
} }
static const std::map<MobKey, EffectImmunities> MobsEffectImmunities = { static const std::map<MobKey, EffectImmunities> MobsEffectImmunities = {
{{MobType::Zombie, 1},{}}, {{MobType::Zombie, 1},{}},
{{MobType::Zombie, 2},{}}, {{MobType::Zombie, 2},{}},
{{MobType::Zombie, 3},{}}, {{MobType::Zombie, 3},{}},
{{MobType::Zombie, 4},{}}, {{MobType::Zombie, 4},{}},
{{MobType::Zombie, 5},{}}, {{MobType::Zombie, 5},{}},
{{MobType::Spider, 1},{}}, {{MobType::Spider, 1},{}},
{{MobType::Spider, 2},{}}, {{MobType::Spider, 2},{}},
{{MobType::Spider, 3},{}}, {{MobType::Spider, 3},{}},
{{MobType::Spider, 4},{}}, {{MobType::Spider, 4},{}},
{{MobType::Spider, 5},{}}, {{MobType::Spider, 5},{}},
{{MobType::Skeleton, 1},{}}, {{MobType::Skeleton, 1},{}},
{{MobType::Skeleton, 2},{}}, {{MobType::Skeleton, 2},{}},
{{MobType::Skeleton, 3},{}}, {{MobType::Skeleton, 3},{}},
{{MobType::Skeleton, 4},{EffectType::Fire}}, {{MobType::Skeleton, 4},{EffectType::Fire}},
{{MobType::Skeleton, 5},{EffectType::Fire}}, {{MobType::Skeleton, 5},{EffectType::Fire}},
{{MobType::Pigman, 1},{EffectType::Fire}}, {{MobType::Pigman, 1},{EffectType::Fire}},
{{MobType::Pigman, 2},{EffectType::Fire}}, {{MobType::Pigman, 2},{EffectType::Fire}},
{{MobType::Pigman, 3},{EffectType::Fire}}, {{MobType::Pigman, 3},{EffectType::Fire}},
{{MobType::Pigman, 4},{EffectType::Fire}}, {{MobType::Pigman, 4},{EffectType::Fire}},
{{MobType::Pigman, 5},{EffectType::Fire}}, {{MobType::Pigman, 5},{EffectType::Fire}},
{{MobType::Creeper, 1},{}}, {{MobType::Creeper, 1},{}},
{{MobType::Creeper, 2},{}}, {{MobType::Creeper, 2},{}},
{{MobType::Creeper, 3},{}}, {{MobType::Creeper, 3},{}},
{{MobType::Creeper, 4},{}}, {{MobType::Creeper, 4},{}},
{{MobType::Creeper, 5},{}}, {{MobType::Creeper, 5},{}},
{{MobType::Silverfish, 1},{}}, {{MobType::Silverfish, 1},{}},
{{MobType::Silverfish, 2},{}}, {{MobType::Silverfish, 2},{}},
{{MobType::Silverfish, 3},{}}, {{MobType::Silverfish, 3},{}},
{{MobType::Silverfish, 4},{EffectType::Fire}}, {{MobType::Silverfish, 4},{EffectType::Fire}},
{{MobType::Silverfish, 5},{EffectType::Fire}}, {{MobType::Silverfish, 5},{EffectType::Fire}},
{{MobType::Blaze, 1},{EffectType::Fire}}, {{MobType::Blaze, 1},{EffectType::Fire}},
{{MobType::Blaze, 2},{EffectType::Fire}}, {{MobType::Blaze, 2},{EffectType::Fire}},
{{MobType::Blaze, 3},{EffectType::Fire}}, {{MobType::Blaze, 3},{EffectType::Fire}},
{{MobType::Blaze, 4},{EffectType::Fire}}, {{MobType::Blaze, 4},{EffectType::Fire}},
{{MobType::Blaze, 5},{EffectType::Fire}}, {{MobType::Blaze, 5},{EffectType::Fire}},
{{MobType::Witch, 1},{}}, {{MobType::Witch, 1},{}},
{{MobType::Witch, 2},{}}, {{MobType::Witch, 2},{}},
{{MobType::Witch, 3},{}}, {{MobType::Witch, 3},{}},
{{MobType::Witch, 4},{}}, {{MobType::Witch, 4},{}},
{{MobType::Witch, 5},{}}, {{MobType::Witch, 5},{}},
{{MobType::Slime, 1},{}}, {{MobType::Slime, 1},{}},
{{MobType::Slime, 2},{}}, {{MobType::Slime, 2},{}},
{{MobType::Slime, 3},{}}, {{MobType::Slime, 3},{}},
{{MobType::Slime, 4},{EffectType::Fire}}, {{MobType::Slime, 4},{EffectType::Fire}},
{{MobType::Slime, 5},{EffectType::Fire}}, {{MobType::Slime, 5},{EffectType::Fire}},
{{MobType::Giant, 1},{EffectType::Stun}}, {{MobType::Giant, 1},{EffectType::Stun}},
{{MobType::Giant, 2},{EffectType::Stun}}, {{MobType::Giant, 2},{EffectType::Stun}},
{{MobType::Giant, 3},{EffectType::Stun}}, {{MobType::Giant, 3},{EffectType::Stun}},
{{MobType::Giant, 4},{EffectType::Stun}}, {{MobType::Giant, 4},{EffectType::Stun}},
{{MobType::Giant, 5},{EffectType::Stun}}, {{MobType::Giant, 5},{EffectType::Stun}},
}; };
const EffectImmunities& GetMobEffectImmunities(MobType type, std::uint8_t level) { const EffectImmunities& GetMobEffectImmunities(MobType type, std::uint8_t level) {
return MobsEffectImmunities.at({ type, level }); return MobsEffectImmunities.at({ type, level });
} }
MobPtr MobFactory::CreateMob(MobID mobId, MobType mobType, std::uint8_t mobLevel, PlayerID mobSender) { MobPtr MobFactory::CreateMob(MobID mobId, MobType mobType, std::uint8_t mobLevel, PlayerID mobSender) {
using MobCreator = std::function<std::shared_ptr<Mob>(MobID, std::uint8_t, PlayerID)>; using MobCreator = std::function<std::shared_ptr<Mob>(MobID, std::uint8_t, PlayerID)>;
static const std::map<MobType, MobCreator> mobFactory = { static const std::map<MobType, MobCreator> mobFactory = {
{MobType::Zombie, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Zombie>(id, level, sender);} }, {MobType::Zombie, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Zombie>(id, level, sender);} },
{MobType::Spider, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Spider>(id, level, sender);} }, {MobType::Spider, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Spider>(id, level, sender);} },
{MobType::Skeleton, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Skeleton>(id, level, sender);} }, {MobType::Skeleton, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Skeleton>(id, level, sender);} },
{MobType::Pigman, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<PigMan>(id, level, sender);} }, {MobType::Pigman, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<PigMan>(id, level, sender);} },
{MobType::Creeper, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Creeper>(id, level, sender);} }, {MobType::Creeper, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Creeper>(id, level, sender);} },
{MobType::Silverfish, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Silverfish>(id, level, sender);} }, {MobType::Silverfish, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Silverfish>(id, level, sender);} },
{MobType::Blaze, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Blaze>(id, level, sender);} }, {MobType::Blaze, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Blaze>(id, level, sender);} },
{MobType::Witch, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Witch>(id, level, sender);} }, {MobType::Witch, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Witch>(id, level, sender);} },
{MobType::Slime, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Slime>(id, level, sender);} }, {MobType::Slime, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Slime>(id, level, sender);} },
{MobType::Giant, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Giant>(id, level, sender);} }, {MobType::Giant, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Giant>(id, level, sender);} },
}; };
return mobFactory.at(mobType)(mobId, mobLevel, mobSender); return mobFactory.at(mobType)(mobId, mobLevel, mobSender);
} }
std::string MobFactory::GetMobName(MobType type) { std::string MobFactory::GetMobName(MobType type) {
switch (type) { switch (type) {
case MobType::Zombie: case MobType::Zombie:
return "Zombie"; return "Zombie";
case MobType::Spider: case MobType::Spider:
return "Spider"; return "Spider";
case MobType::Skeleton: case MobType::Skeleton:
return "Skeleton"; return "Skeleton";
case MobType::Pigman: case MobType::Pigman:
return "Pigman"; return "Pigman";
case MobType::Creeper: case MobType::Creeper:
return "Creeper"; return "Creeper";
case MobType::Silverfish: case MobType::Silverfish:
return "Silverfish"; return "Silverfish";
case MobType::Blaze: case MobType::Blaze:
return "Blaze"; return "Blaze";
case MobType::Witch: case MobType::Witch:
return "Witch"; return "Witch";
case MobType::Slime: case MobType::Slime:
return "Slime"; return "Slime";
case MobType::Giant: case MobType::Giant:
return "Giant"; return "Giant";
default: default:
return "Unknow"; return "Unknow";
} }
} }
} // namespace game } // namespace game

View File

@@ -8,19 +8,19 @@ namespace game {
Team::Team(TeamColor color) : m_Color(color), m_TeamCastle(this) {} Team::Team(TeamColor color) : m_Color(color), m_TeamCastle(this) {}
void Team::AddPlayer(Player* newPlayer) { void Team::AddPlayer(Player* newPlayer) {
m_Players.push_back(newPlayer); m_Players.push_back(newPlayer);
} }
void Team::RemovePlayer(const Player* player) { void Team::RemovePlayer(const Player* player) {
m_Players.erase(std::find(m_Players.begin(), m_Players.end(), player)); m_Players.erase(std::find(m_Players.begin(), m_Players.end(), player));
} }
TeamColor Team::GetColor() const { TeamColor Team::GetColor() const {
return m_Color; return m_Color;
} }
std::uint8_t Team::GetPlayerCount() const { std::uint8_t Team::GetPlayerCount() const {
return m_Players.size(); return m_Players.size();
} }

View File

@@ -7,118 +7,118 @@ namespace td {
namespace game { namespace game {
bool Tower::IsMobInRange(MobPtr mob) { bool Tower::IsMobInRange(MobPtr mob) {
if (mob->IsDead()) if (mob->IsDead())
return false; return false;
return mob->CollidesWith(*this); return mob->CollidesWith(*this);
} }
const std::map<std::pair<TowerType, TowerLevel>, TowerStats> TowerConstants = { const std::map<std::pair<TowerType, TowerLevel>, TowerStats> TowerConstants = {
// // rate damage range // // rate damage range
{{TowerType::Archer, {1, TowerPath::Base}}, {2, 5, 10}}, {{TowerType::Archer, {1, TowerPath::Base}}, {2, 5, 10}},
{{TowerType::Archer, {2, TowerPath::Top}}, {1, 0, 12}}, {{TowerType::Archer, {2, TowerPath::Top}}, {1, 0, 12}},
{{TowerType::Archer, {3, TowerPath::Top}}, {1, 0, 13}}, {{TowerType::Archer, {3, TowerPath::Top}}, {1, 0, 13}},
{{TowerType::Archer, {4, TowerPath::Top}}, {0.8, 0, 15}}, {{TowerType::Archer, {4, TowerPath::Top}}, {0.8, 0, 15}},
{{TowerType::Archer, {2, TowerPath::Bottom}}, {2, 10, 12}}, {{TowerType::Archer, {2, TowerPath::Bottom}}, {2, 10, 12}},
{{TowerType::Archer, {3, TowerPath::Bottom}}, {2, 10, 13}}, {{TowerType::Archer, {3, TowerPath::Bottom}}, {2, 10, 13}},
{{TowerType::Archer, {4, TowerPath::Bottom}}, {2, 10, 15}}, {{TowerType::Archer, {4, TowerPath::Bottom}}, {2, 10, 15}},
//----------------------------------------------------------------- //-----------------------------------------------------------------
{{TowerType::Ice, {1, TowerPath::Base}}, {1, 0, 10}}, {{TowerType::Ice, {1, TowerPath::Base}}, {1, 0, 10}},
{{TowerType::Ice, {2, TowerPath::Base}}, {1, 0, 12}}, {{TowerType::Ice, {2, TowerPath::Base}}, {1, 0, 12}},
{{TowerType::Ice, {3, TowerPath::Base}}, {1, 0, 13}}, {{TowerType::Ice, {3, TowerPath::Base}}, {1, 0, 13}},
{{TowerType::Ice, {4, TowerPath::Base}}, {1, 1, 15}}, {{TowerType::Ice, {4, TowerPath::Base}}, {1, 1, 15}},
//----------------------------------------------------------------- //-----------------------------------------------------------------
{{TowerType::Sorcerer, {1, TowerPath::Base}}, {5, 0, 10}}, {{TowerType::Sorcerer, {1, TowerPath::Base}}, {5, 0, 10}},
{{TowerType::Sorcerer, {2, TowerPath::Base}}, {4, 0, 12}}, {{TowerType::Sorcerer, {2, TowerPath::Base}}, {4, 0, 12}},
{{TowerType::Sorcerer, {3, TowerPath::Top}}, {4, 0, 14}}, {{TowerType::Sorcerer, {3, TowerPath::Top}}, {4, 0, 14}},
{{TowerType::Sorcerer, {4, TowerPath::Top}}, {4, 0, 15}}, {{TowerType::Sorcerer, {4, TowerPath::Top}}, {4, 0, 15}},
{{TowerType::Sorcerer, {3, TowerPath::Bottom}}, {4, 0, 14}}, {{TowerType::Sorcerer, {3, TowerPath::Bottom}}, {4, 0, 14}},
{{TowerType::Sorcerer, {4, TowerPath::Bottom}}, {4, 0, 15}}, {{TowerType::Sorcerer, {4, TowerPath::Bottom}}, {4, 0, 15}},
//----------------------------------------------------------------- //-----------------------------------------------------------------
{{TowerType::Zeus, {1, TowerPath::Base}}, {5, 0, 10}}, {{TowerType::Zeus, {1, TowerPath::Base}}, {5, 0, 10}},
{{TowerType::Zeus, {2, TowerPath::Base}}, {4, 0, 12}}, {{TowerType::Zeus, {2, TowerPath::Base}}, {4, 0, 12}},
{{TowerType::Zeus, {3, TowerPath::Top}}, {0, 0, 0}}, {{TowerType::Zeus, {3, TowerPath::Top}}, {0, 0, 0}},
{{TowerType::Zeus, {4, TowerPath::Top}}, {0, 0, 0}}, {{TowerType::Zeus, {4, TowerPath::Top}}, {0, 0, 0}},
{{TowerType::Zeus, {3, TowerPath::Bottom}}, {1.2, 0, 14}}, {{TowerType::Zeus, {3, TowerPath::Bottom}}, {1.2, 0, 14}},
{{TowerType::Zeus, {4, TowerPath::Bottom}}, {0.8, 0, 15}}, {{TowerType::Zeus, {4, TowerPath::Bottom}}, {0.8, 0, 15}},
//----------------------------------------------------------------- //-----------------------------------------------------------------
{{TowerType::Mage, {1, TowerPath::Base}}, {5, 0, 10}}, {{TowerType::Mage, {1, TowerPath::Base}}, {5, 0, 10}},
{{TowerType::Mage, {2, TowerPath::Base}}, {4, 0, 12}}, {{TowerType::Mage, {2, TowerPath::Base}}, {4, 0, 12}},
{{TowerType::Mage, {3, TowerPath::Base}}, {3, 0, 13}}, {{TowerType::Mage, {3, TowerPath::Base}}, {3, 0, 13}},
{{TowerType::Mage, {4, TowerPath::Base}}, {1, 30, 15}}, {{TowerType::Mage, {4, TowerPath::Base}}, {1, 30, 15}},
//----------------------------------------------------------------- //-----------------------------------------------------------------
{{TowerType::Artillery, {1, TowerPath::Base}}, {7, 0, 10}}, {{TowerType::Artillery, {1, TowerPath::Base}}, {7, 0, 10}},
{{TowerType::Artillery, {2, TowerPath::Base}}, {7, 0, 12}}, {{TowerType::Artillery, {2, TowerPath::Base}}, {7, 0, 12}},
{{TowerType::Artillery, {3, TowerPath::Top}}, {7, 0, 13}}, {{TowerType::Artillery, {3, TowerPath::Top}}, {7, 0, 13}},
{{TowerType::Artillery, {4, TowerPath::Top}}, {7, 0, 15}}, {{TowerType::Artillery, {4, TowerPath::Top}}, {7, 0, 15}},
{{TowerType::Artillery, {3, TowerPath::Bottom}}, {5, 0, 13}}, {{TowerType::Artillery, {3, TowerPath::Bottom}}, {5, 0, 13}},
{{TowerType::Artillery, {4, TowerPath::Bottom}}, {4, 0, 15}}, {{TowerType::Artillery, {4, TowerPath::Bottom}}, {4, 0, 15}},
//----------------------------------------------------------------- //-----------------------------------------------------------------
{{TowerType::Quake, {1, TowerPath::Base}}, {5, 5, 10}}, {{TowerType::Quake, {1, TowerPath::Base}}, {5, 5, 10}},
{{TowerType::Quake, {2, TowerPath::Base}}, {4, 7, 12}}, {{TowerType::Quake, {2, TowerPath::Base}}, {4, 7, 12}},
{{TowerType::Quake, {3, TowerPath::Base}}, {3, 9, 13}}, {{TowerType::Quake, {3, TowerPath::Base}}, {3, 9, 13}},
{{TowerType::Quake, {4, TowerPath::Base}}, {2, 11, 15}}, {{TowerType::Quake, {4, TowerPath::Base}}, {2, 11, 15}},
//----------------------------------------------------------------- //-----------------------------------------------------------------
{{TowerType::Poison, {1, TowerPath::Base}}, {5, 0, 10}}, {{TowerType::Poison, {1, TowerPath::Base}}, {5, 0, 10}},
{{TowerType::Poison, {2, TowerPath::Base}}, {5, 0, 12}}, {{TowerType::Poison, {2, TowerPath::Base}}, {5, 0, 12}},
{{TowerType::Poison, {3, TowerPath::Top}}, {6, 0, 13}}, {{TowerType::Poison, {3, TowerPath::Top}}, {6, 0, 13}},
{{TowerType::Poison, {4, TowerPath::Top}}, {5, 0, 15}}, {{TowerType::Poison, {4, TowerPath::Top}}, {5, 0, 15}},
{{TowerType::Poison, {3, TowerPath::Bottom}}, {5, 10, 13}}, {{TowerType::Poison, {3, TowerPath::Bottom}}, {5, 10, 13}},
{{TowerType::Poison, {4, TowerPath::Bottom}}, {6, 20, 15}}, {{TowerType::Poison, {4, TowerPath::Bottom}}, {6, 20, 15}},
//----------------------------------------------------------------- //-----------------------------------------------------------------
{{TowerType::Leach, {1, TowerPath::Base}}, {0, 0, 0}}, {{TowerType::Leach, {1, TowerPath::Base}}, {0, 0, 0}},
{{TowerType::Leach, {2, TowerPath::Base}}, {0, 0, 0}}, {{TowerType::Leach, {2, TowerPath::Base}}, {0, 0, 0}},
{{TowerType::Leach, {3, TowerPath::Base}}, {0, 0, 0}}, {{TowerType::Leach, {3, TowerPath::Base}}, {0, 0, 0}},
//----------------------------------------------------------------- //-----------------------------------------------------------------
{{TowerType::Turret, {1, TowerPath::Base}}, {0.5, 0, 0}}, {{TowerType::Turret, {1, TowerPath::Base}}, {0.5, 0, 0}},
{{TowerType::Turret, {2, TowerPath::Top}}, {0, 0, 0}}, {{TowerType::Turret, {2, TowerPath::Top}}, {0, 0, 0}},
{{TowerType::Turret, {3, TowerPath::Top}}, {0, 0, 0}}, {{TowerType::Turret, {3, TowerPath::Top}}, {0, 0, 0}},
{{TowerType::Turret, {2, TowerPath::Bottom}}, {0, 0, 0}}, {{TowerType::Turret, {2, TowerPath::Bottom}}, {0, 0, 0}},
{{TowerType::Turret, {3, TowerPath::Bottom}}, {0, 0, 0}}, {{TowerType::Turret, {3, TowerPath::Bottom}}, {0, 0, 0}},
//----------------------------------------------------------------- //-----------------------------------------------------------------
{{TowerType::Necromancer, {1, TowerPath::Base}}, {2, 0, 11}}, {{TowerType::Necromancer, {1, TowerPath::Base}}, {2, 0, 11}},
{{TowerType::Necromancer, {2, TowerPath::Base}}, {1, 0, 14}}, {{TowerType::Necromancer, {2, TowerPath::Base}}, {1, 0, 14}},
{{TowerType::Necromancer, {3, TowerPath::Top}}, {1, 0, 15}}, {{TowerType::Necromancer, {3, TowerPath::Top}}, {1, 0, 15}},
{{TowerType::Necromancer, {3, TowerPath::Bottom}}, {0, 30, 0}}, {{TowerType::Necromancer, {3, TowerPath::Bottom}}, {0, 30, 0}},
}; };
const TowerStats* GetTowerStats(TowerType type, TowerLevel level) { const TowerStats* GetTowerStats(TowerType type, TowerLevel level) {
auto it = TowerConstants.find({ type, level }); auto it = TowerConstants.find({ type, level });
if (it == TowerConstants.end()) return nullptr; if (it == TowerConstants.end()) return nullptr;
return &it->second; return &it->second;
} }
@@ -126,21 +126,21 @@ const TowerStats* GetTowerStats(TowerType type, TowerLevel level) {
static const std::map<TowerType, TowerInfo> TowerInfoConstants = { static const std::map<TowerType, TowerInfo> TowerInfoConstants = {
{TowerType::Archer, {"Archer", "Shoot projectiles", false}}, {TowerType::Archer, {"Archer", "Shoot projectiles", false}},
{TowerType::Artillery, {"Artillery", "Explosion", false}}, {TowerType::Artillery, {"Artillery", "Explosion", false}},
{TowerType::Ice, {"Ice", "Slow down enemies", false}}, {TowerType::Ice, {"Ice", "Slow down enemies", false}},
{TowerType::Leach, {"Leach", "Shoot projectiles", true}}, {TowerType::Leach, {"Leach", "Shoot projectiles", true}},
{TowerType::Mage, {"Mage", "Set enemies on fire", false}}, {TowerType::Mage, {"Mage", "Set enemies on fire", false}},
{TowerType::Necromancer, {"Necromancer", "Summon troops", true}}, {TowerType::Necromancer, {"Necromancer", "Summon troops", true}},
{TowerType::Poison, {"Poison", "Poison enemies", false}}, {TowerType::Poison, {"Poison", "Poison enemies", false}},
{TowerType::Quake, {"Quake", "Shoot projectiles", false}}, {TowerType::Quake, {"Quake", "Shoot projectiles", false}},
{TowerType::Sorcerer, {"Sorcerer", "Summon friendly troops", false}}, {TowerType::Sorcerer, {"Sorcerer", "Summon friendly troops", false}},
{TowerType::Turret, {"Turret", "Shoot arrow very fast", true}}, {TowerType::Turret, {"Turret", "Shoot arrow very fast", true}},
{TowerType::Zeus, {"Zeus", "Strike lightning", false}}, {TowerType::Zeus, {"Zeus", "Strike lightning", false}},
}; };
const TowerInfo& GetTowerInfo(TowerType type) { const TowerInfo& GetTowerInfo(TowerType type) {
return TowerInfoConstants.at(type); return TowerInfoConstants.at(type);
} }
@@ -152,168 +152,54 @@ namespace TowerFactory {
using TowerCreator = std::function<std::shared_ptr<Tower>(TowerID, std::int32_t, std::int32_t, PlayerID)>; using TowerCreator = std::function<std::shared_ptr<Tower>(TowerID, std::int32_t, std::int32_t, PlayerID)>;
static const std::map<TowerType, TowerCreator> towerFactory = { static const std::map<TowerType, TowerCreator> towerFactory = {
{TowerType::Archer, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<ArcherTower>(id, x, y , builder);} }, {TowerType::Archer, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<ArcherTower>(id, x, y , builder);} },
{TowerType::Artillery, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<ArtilleryTower>(id, x, y , builder);} }, {TowerType::Artillery, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<ArtilleryTower>(id, x, y , builder);} },
{TowerType::Ice, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<IceTower>(id, x, y , builder);} }, {TowerType::Ice, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<IceTower>(id, x, y , builder);} },
{TowerType::Mage, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<MageTower>(id, x, y , builder);} }, {TowerType::Mage, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<MageTower>(id, x, y , builder);} },
{TowerType::Poison, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<PoisonTower>(id, x, y , builder);} }, {TowerType::Poison, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<PoisonTower>(id, x, y , builder);} },
{TowerType::Quake, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<QuakeTower>(id, x, y , builder);} }, {TowerType::Quake, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<QuakeTower>(id, x, y , builder);} },
{TowerType::Sorcerer, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<SorcererTower>(id, x, y , builder);} }, {TowerType::Sorcerer, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<SorcererTower>(id, x, y , builder);} },
{TowerType::Zeus, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<ZeusTower>(id, x, y , builder);} }, {TowerType::Zeus, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<ZeusTower>(id, x, y , builder);} },
{TowerType::Leach, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<LeachTower>(id, x, y , builder);} }, {TowerType::Leach, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<LeachTower>(id, x, y , builder);} },
{TowerType::Necromancer, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<NecromancerTower>(id, x, y , builder);} }, {TowerType::Necromancer, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<NecromancerTower>(id, x, y , builder);} },
{TowerType::Turret, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<TurretTower>(id, x, y , builder);} }, {TowerType::Turret, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<TurretTower>(id, x, y , builder);} },
}; };
TowerPtr CreateTower(TowerType type, TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) { TowerPtr CreateTower(TowerType type, TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) {
return towerFactory.at(type)(id, x, y, builder); return towerFactory.at(type)(id, x, y, builder);
} }
std::string GetTowerName(TowerType type) { std::string GetTowerName(TowerType type) {
switch (type) { switch (type) {
case TowerType::Archer: case TowerType::Archer:
return "Archer"; return "Archer";
case TowerType::Artillery: case TowerType::Artillery:
return "Artillery"; return "Artillery";
case TowerType::Ice: case TowerType::Ice:
return "Ice"; return "Ice";
case TowerType::Mage: case TowerType::Mage:
return "Mage"; return "Mage";
case TowerType::Poison: case TowerType::Poison:
return "Poison"; return "Poison";
case TowerType::Quake: case TowerType::Quake:
return "Quake"; return "Quake";
case TowerType::Sorcerer: case TowerType::Sorcerer:
return "Sorcerer"; return "Sorcerer";
case TowerType::Zeus: case TowerType::Zeus:
return "Zeus"; return "Zeus";
case TowerType::Leach: case TowerType::Leach:
return "Leach"; return "Leach";
case TowerType::Necromancer: case TowerType::Necromancer:
return "Necromancer"; return "Necromancer";
case TowerType::Turret: case TowerType::Turret:
return "Turret"; return "Turret";
default: default:
return "Unknow"; return "Unknow";
} }
} }
} // namespace TowerFactory } // namespace TowerFactory
void ArcherTower::Tick(std::uint64_t delta, World* world) {
if (m_Timer.Update(delta)) {
std::uint8_t arrowsShot = 0;
bool explosiveArrows = GetLevel().GetPath() == TowerPath::Bottom;
std::uint8_t arrows = explosiveArrows ? 2 : GetLevel().GetLevel();
for (MobPtr mob : world->GetMobList()) {
if (IsMobInRange(mob)) {
world->GetWorldNotifier().NotifyListeners(&WorldListener::OnArcherTowerShot, mob, this);
m_Timer.ApplyCooldown();
arrowsShot++;
if (arrowsShot >= arrows)
break;
}
}
}
}
void IceTower::Tick(std::uint64_t delta, World* world) {
if (m_Timer.Update(delta)) {
float damage = GetStats()->GetDamage();
for (MobPtr mob : world->GetMobList()) {
if (IsMobInRange(mob)) {
mob->AddEffect(EffectType::Slowness, 1, this); // slowness for 1s every second
if (damage > 0)
world->GetMobNotifier().NotifyListeners(&MobListener::OnMobDamage, mob.get(), damage, this);
m_Timer.ApplyCooldown();
}
}
}
}
void MageTower::Tick(std::uint64_t delta, World* world) {
if (m_Timer.Update(delta)) {
for (MobPtr mob : world->GetMobList()) {
if (IsMobInRange(mob)) {
mob->AddEffect(EffectType::Fire, GetLevel().GetLevel() * 3, this);
m_Timer.ApplyCooldown();
}
}
}
}
void PoisonTower::Tick(std::uint64_t delta, World* world) {
if (m_Timer.Update(delta)) {
for (MobPtr mob : world->GetMobList()) {
if (IsMobInRange(mob)) {
if (GetLevel().GetPath() == TowerPath::Bottom) {
world->GetMobNotifier().NotifyListeners(&MobListener::OnMobDamage, mob.get(), GetStats()->GetDamage(), this);
} else {
float durationSec;
switch (GetLevel().GetLevel()) {
case 1:
durationSec = 5;
break;
case 2:
durationSec = 15;
break;
case 3:
durationSec = 30;
break;
case 4:
durationSec = 1e10; // about 3 million hours. It should be enough
break;
default:
durationSec = 0; // how did we get there ?
break;
}
mob->AddEffect(EffectType::Poison, durationSec, this);
}
m_Timer.ApplyCooldown();
}
}
}
}
void QuakeTower::Tick(std::uint64_t delta, World* world) {
}
void ZeusTower::Tick(std::uint64_t delta, World* world) {
}
void ArtilleryTower::Tick(std::uint64_t delta, World* world) {
}
void SorcererTower::Tick(std::uint64_t delta, World* world) {
}
void LeachTower::Tick(std::uint64_t delta, World* world) {
}
void TurretTower::Tick(std::uint64_t delta, World* world) {
}
void NecromancerTower::Tick(std::uint64_t delta, World* world) {
}
} // namespace game } // namespace game
} // namespace td } // namespace td

View File

@@ -12,312 +12,312 @@ namespace td {
namespace game { namespace game {
World::World(Game* game) : m_Game(game) { World::World(Game* game) : m_Game(game) {
GetWorldNotifier().BindListener(this); GetWorldNotifier().BindListener(this);
GetMobNotifier().BindListener(this); GetMobNotifier().BindListener(this);
} }
TilePtr World::GetTile(std::int32_t x, std::int32_t y) const { TilePtr World::GetTile(std::int32_t x, std::int32_t y) const {
std::int16_t chunkX = x / Chunk::ChunkWidth; std::int16_t chunkX = x / Chunk::ChunkWidth;
std::int16_t chunkY = y / Chunk::ChunkHeight; std::int16_t chunkY = y / Chunk::ChunkHeight;
std::uint16_t subChunkX = std::abs(x % Chunk::ChunkWidth); std::uint16_t subChunkX = std::abs(x % Chunk::ChunkWidth);
std::uint16_t subChunkY = std::abs(y % Chunk::ChunkHeight); std::uint16_t subChunkY = std::abs(y % Chunk::ChunkHeight);
auto chunkIt = m_Chunks.find({ chunkX, chunkY }); auto chunkIt = m_Chunks.find({ chunkX, chunkY });
if (chunkIt == m_Chunks.end()) if (chunkIt == m_Chunks.end())
return nullptr; return nullptr;
ChunkPtr chunk = chunkIt->second; ChunkPtr chunk = chunkIt->second;
return GetTilePtr(chunk->GetTileIndex(subChunkY * Chunk::ChunkWidth + subChunkX)); return GetTilePtr(chunk->GetTileIndex(subChunkY * Chunk::ChunkWidth + subChunkX));
} }
bool World::LoadMap(const protocol::WorldBeginDataPacket* worldHeader) { bool World::LoadMap(const protocol::WorldBeginDataPacket* worldHeader) {
m_TowerPlacePalette = worldHeader->GetTowerTilePalette(); m_TowerPlacePalette = worldHeader->GetTowerTilePalette();
m_WalkablePalette = worldHeader->GetWalkableTileColor(); m_WalkablePalette = worldHeader->GetWalkableTileColor();
m_DecorationPalette = worldHeader->GetDecorationPalette(); m_DecorationPalette = worldHeader->GetDecorationPalette();
m_Background = worldHeader->GetBackgroundColor(); m_Background = worldHeader->GetBackgroundColor();
GetRedTeam().GetSpawn() = worldHeader->GetRedSpawn(); GetRedTeam().GetSpawn() = worldHeader->GetRedSpawn();
GetBlueTeam().GetSpawn() = worldHeader->GetBlueSpawn(); GetBlueTeam().GetSpawn() = worldHeader->GetBlueSpawn();
m_SpawnColorPalette = worldHeader->GetSpawnPalette(); m_SpawnColorPalette = worldHeader->GetSpawnPalette();
GetRedTeam().GetCastle() = worldHeader->GetRedCastle(); GetRedTeam().GetCastle() = worldHeader->GetRedCastle();
GetRedTeam().GetCastle().SetTeam(&GetRedTeam()); GetRedTeam().GetCastle().SetTeam(&GetRedTeam());
GetBlueTeam().GetCastle() = worldHeader->GetBlueCastle(); GetBlueTeam().GetCastle() = worldHeader->GetBlueCastle();
GetBlueTeam().GetCastle().SetTeam(&GetBlueTeam()); GetBlueTeam().GetCastle().SetTeam(&GetBlueTeam());
m_TilePalette = worldHeader->GetTilePalette(); m_TilePalette = worldHeader->GetTilePalette();
return true; return true;
} }
bool World::LoadMap(const protocol::WorldDataPacket* worldData) { bool World::LoadMap(const protocol::WorldDataPacket* worldData) {
m_Chunks = worldData->GetChunks(); m_Chunks = worldData->GetChunks();
return true; return true;
} }
bool World::LoadMapFromFile(const std::string& fileName) { bool World::LoadMapFromFile(const std::string& fileName) {
DataBuffer buffer; DataBuffer buffer;
if (!buffer.ReadFile(fileName)) { if (!buffer.ReadFile(fileName)) {
utils::LOGE(utils::format("Failed to load map from file %s", fileName.c_str())); utils::LOGE(utils::format("Failed to load map from file %s", fileName.c_str()));
return false; return false;
} }
utils::LOG(utils::format("Read file : %s (File size : %u)", fileName.c_str(), buffer.GetSize())); utils::LOG(utils::format("Read file : %s (File size : %u)", fileName.c_str(), buffer.GetSize()));
DataBuffer mapHeaderPacketBuffer = utils::Decompress(buffer); DataBuffer mapHeaderPacketBuffer = utils::Decompress(buffer);
DataBuffer mapDataPacketBuffer = utils::Decompress(buffer); DataBuffer mapDataPacketBuffer = utils::Decompress(buffer);
protocol::WorldBeginDataPacket headerPacket; protocol::WorldBeginDataPacket headerPacket;
headerPacket.Deserialize(mapHeaderPacketBuffer); headerPacket.Deserialize(mapHeaderPacketBuffer);
protocol::WorldDataPacket dataPacket; protocol::WorldDataPacket dataPacket;
dataPacket.Deserialize(mapDataPacketBuffer); dataPacket.Deserialize(mapDataPacketBuffer);
LoadMap(&headerPacket); LoadMap(&headerPacket);
LoadMap(&dataPacket); LoadMap(&dataPacket);
return true; return true;
} }
bool World::SaveMap(const std::string& fileName) const { bool World::SaveMap(const std::string& fileName) const {
protocol::WorldBeginDataPacket headerPacket(this); protocol::WorldBeginDataPacket headerPacket(this);
protocol::WorldDataPacket dataPacket(this); protocol::WorldDataPacket dataPacket(this);
DataBuffer mapHeaderCompressed = utils::Compress(headerPacket.Serialize(false)); DataBuffer mapHeaderCompressed = utils::Compress(headerPacket.Serialize(false));
DataBuffer mapDataCompressed = utils::Compress(dataPacket.Serialize(false)); DataBuffer mapDataCompressed = utils::Compress(dataPacket.Serialize(false));
utils::LOG(utils::format("Header Packet Size : %u", mapHeaderCompressed.GetSize())); utils::LOG(utils::format("Header Packet Size : %u", mapHeaderCompressed.GetSize()));
utils::LOG(utils::format("World Data Packet Size : %u", mapDataCompressed.GetSize())); utils::LOG(utils::format("World Data Packet Size : %u", mapDataCompressed.GetSize()));
DataBuffer buffer = mapHeaderCompressed << mapDataCompressed; DataBuffer buffer = mapHeaderCompressed << mapDataCompressed;
utils::LOG(utils::format("Total Size : %u", buffer.GetSize())); utils::LOG(utils::format("Total Size : %u", buffer.GetSize()));
return buffer.WriteFile(fileName); return buffer.WriteFile(fileName);
} }
void World::Tick(std::uint64_t delta) { void World::Tick(std::uint64_t delta) {
if (m_Game->GetGameState() != GameState::Game) return; if (m_Game->GetGameState() != GameState::Game) return;
TickMobs(delta); TickMobs(delta);
for (TowerPtr tower : m_Towers) { for (TowerPtr tower : m_Towers) {
tower->Tick(delta, this); tower->Tick(delta, this);
} }
CleanDeadMobs(); CleanDeadMobs();
} }
void World::SpawnMobAt(MobID id, MobType type, std::uint8_t level, PlayerID sender, float x, float y, Direction dir) { void World::SpawnMobAt(MobID id, MobType type, std::uint8_t level, PlayerID sender, float x, float y, Direction dir) {
MobPtr mob = MobFactory::CreateMob(id, type, level, sender); MobPtr mob = MobFactory::CreateMob(id, type, level, sender);
mob->SetCenter({ x, y }); mob->SetCenter({ x, y });
mob->SetDirection(dir); mob->SetDirection(dir);
m_Mobs.push_back(mob); m_Mobs.push_back(mob);
GetMobNotifier().NotifyListeners(&MobListener::OnMobSpawn, mob.get()); GetMobNotifier().NotifyListeners(&MobListener::OnMobSpawn, mob.get());
} }
TowerPtr World::PlaceTowerAt(TowerID id, TowerType type, std::int32_t x, std::int32_t y, PlayerID builder) { TowerPtr World::PlaceTowerAt(TowerID id, TowerType type, std::int32_t x, std::int32_t y, PlayerID builder) {
TowerPtr tower = TowerFactory::CreateTower(type, id, x, y, builder); TowerPtr tower = TowerFactory::CreateTower(type, id, x, y, builder);
m_Towers.push_back(tower); m_Towers.push_back(tower);
return tower; return tower;
} }
TowerPtr World::RemoveTower(TowerID towerId) { TowerPtr World::RemoveTower(TowerID towerId) {
auto it = std::find_if(m_Towers.begin(), m_Towers.end(), [towerId](TowerPtr tower) { return tower->GetID() == towerId;}); auto it = std::find_if(m_Towers.begin(), m_Towers.end(), [towerId](TowerPtr tower) { return tower->GetID() == towerId;});
if (it == m_Towers.end()) return nullptr; if (it == m_Towers.end()) return nullptr;
TowerPtr tower = *it; TowerPtr tower = *it;
m_Towers.erase(it); m_Towers.erase(it);
return tower; return tower;
} }
void World::TickMobs(std::uint64_t delta) { void World::TickMobs(std::uint64_t delta) {
for (MobPtr mob : m_Mobs) { for (MobPtr mob : m_Mobs) {
mob->Tick(delta, this); mob->Tick(delta, this);
} }
} }
const Color* World::GetTileColor(TilePtr tile) const { const Color* World::GetTileColor(TilePtr tile) const {
switch (tile->GetType()) { switch (tile->GetType()) {
case TileType::Tower: { case TileType::Tower: {
TowerTile* towerTile = dynamic_cast<TowerTile*>(tile.get()); TowerTile* towerTile = dynamic_cast<TowerTile*>(tile.get());
return &m_TowerPlacePalette[towerTile->color_palette_ref]; return &m_TowerPlacePalette[towerTile->color_palette_ref];
} }
case TileType::Walk: { case TileType::Walk: {
return &m_WalkablePalette; return &m_WalkablePalette;
} }
case TileType::Decoration: { case TileType::Decoration: {
DecorationTile* towerTile = dynamic_cast<DecorationTile*>(tile.get()); DecorationTile* towerTile = dynamic_cast<DecorationTile*>(tile.get());
return &m_DecorationPalette[towerTile->color_palette_ref]; return &m_DecorationPalette[towerTile->color_palette_ref];
break; break;
} }
default: { default: {
return nullptr; return nullptr;
} }
} }
return nullptr; return nullptr;
} }
bool World::CanPlaceLittleTower(const glm::vec2& worldPos, PlayerID playerID) const { bool World::CanPlaceLittleTower(const Vec2f& worldPos, PlayerID playerID) const {
TilePtr tile = GetTile(worldPos.x, worldPos.y); TilePtr tile = GetTile(worldPos.x, worldPos.y);
const Player& player = m_Game->GetPlayers()[playerID]; const Player& player = m_Game->GetPlayers()[playerID];
if (tile == nullptr) { if (tile == nullptr) {
return false; return false;
} }
if (tile->GetType() == game::TileType::Tower) { if (tile->GetType() == game::TileType::Tower) {
const TowerTile* towerTile = dynamic_cast<TowerTile*>(tile.get()); const TowerTile* towerTile = dynamic_cast<TowerTile*>(tile.get());
if (towerTile->team_owner != player.GetTeamColor()) if (towerTile->team_owner != player.GetTeamColor())
return false; return false;
for (int x = -1; x < 2; x++) { for (int x = -1; x < 2; x++) {
for (int y = -1; y < 2; y++) { for (int y = -1; y < 2; y++) {
game::TilePtr adjacentTile = GetTile(worldPos.x + x, worldPos.y + y); game::TilePtr adjacentTile = GetTile(worldPos.x + x, worldPos.y + y);
if (adjacentTile == nullptr || adjacentTile->GetType() != game::TileType::Tower || GetTower({ worldPos.x + x, worldPos.y + y }) != nullptr) { if (adjacentTile == nullptr || adjacentTile->GetType() != game::TileType::Tower || GetTower({ worldPos.x + x, worldPos.y + y }) != nullptr) {
return false; return false;
} }
} }
} }
return true; return true;
} }
return false; return false;
} }
bool World::CanPlaceBigTower(const glm::vec2& worldPos, PlayerID playerID) const { bool World::CanPlaceBigTower(const Vec2f& worldPos, PlayerID playerID) const {
if (!CanPlaceLittleTower(worldPos, playerID)) return false; if (!CanPlaceLittleTower(worldPos, playerID)) return false;
TilePtr tile = GetTile(worldPos.x, worldPos.y); TilePtr tile = GetTile(worldPos.x, worldPos.y);
const Player& player = m_Game->GetPlayers()[playerID]; const Player& player = m_Game->GetPlayers()[playerID];
if (tile == nullptr) { if (tile == nullptr) {
return false; return false;
} }
if (tile->GetType() == game::TileType::Tower) { if (tile->GetType() == game::TileType::Tower) {
const TowerTile* towerTile = dynamic_cast<const TowerTile*>(tile.get()); const TowerTile* towerTile = dynamic_cast<const TowerTile*>(tile.get());
if (towerTile->team_owner != player.GetTeamColor()) if (towerTile->team_owner != player.GetTeamColor())
return false; return false;
for (int x = -2; x < 3; x++) { for (int x = -2; x < 3; x++) {
for (int y = -2; y < 3; y++) { for (int y = -2; y < 3; y++) {
game::TilePtr adjacentTile = GetTile(worldPos.x + x, worldPos.y + y); game::TilePtr adjacentTile = GetTile(worldPos.x + x, worldPos.y + y);
if (adjacentTile == nullptr || adjacentTile->GetType() != game::TileType::Tower || GetTower({ worldPos.x + x, worldPos.y + y }) != nullptr) { if (adjacentTile == nullptr || adjacentTile->GetType() != game::TileType::Tower || GetTower({ worldPos.x + x, worldPos.y + y }) != nullptr) {
return false; return false;
} }
} }
} }
return true; return true;
} }
return false; return false;
} }
void World::CleanDeadMobs() { void World::CleanDeadMobs() {
// safely remove mobs when unused // safely remove mobs when unused
for (std::size_t i = 0; i < m_Mobs.size(); i++) { for (std::size_t i = 0; i < m_Mobs.size(); i++) {
MobPtr mob = m_Mobs[i]; MobPtr mob = m_Mobs[i];
if (mob->IsDead()) { if (mob->IsDead()) {
m_Mobs.erase(m_Mobs.begin() + static_cast<int>(i)); m_Mobs.erase(m_Mobs.begin() + static_cast<int>(i));
} }
} }
} }
TowerPtr World::GetTower(const glm::vec2& position) const { TowerPtr World::GetTower(const Vec2f& position) const {
for (TowerPtr tower : m_Towers) { for (TowerPtr tower : m_Towers) {
if (tower->GetSize() == TowerSize::Big) { if (tower->GetSize() == TowerSize::Big) {
if (tower->GetCenterX() - 2.5f < position.x && tower->GetCenterX() + 2.5f > position.x && if (tower->GetCenterX() - 2.5f < position.x && tower->GetCenterX() + 2.5f > position.x &&
tower->GetCenterY() - 2.5f < position.y && tower->GetCenterY() + 2.5f > position.y) { tower->GetCenterY() - 2.5f < position.y && tower->GetCenterY() + 2.5f > position.y) {
return tower; return tower;
} }
} else { // little tower } else { // little tower
if (tower->GetCenterX() - 1.5f < position.x && tower->GetCenterX() + 1.5f > position.x && if (tower->GetCenterX() - 1.5f < position.x && tower->GetCenterX() + 1.5f > position.x &&
tower->GetCenterY() - 1.5f < position.y && tower->GetCenterY() + 1.5f > position.y) { tower->GetCenterY() - 1.5f < position.y && tower->GetCenterY() + 1.5f > position.y) {
return tower; return tower;
} }
} }
} }
return nullptr; return nullptr;
} }
TowerPtr World::GetTowerById(TowerID towerID) { TowerPtr World::GetTowerById(TowerID towerID) {
auto it = std::find_if(m_Towers.begin(), m_Towers.end(), [towerID](TowerPtr tower) { return tower->GetID() == towerID;}); auto it = std::find_if(m_Towers.begin(), m_Towers.end(), [towerID](TowerPtr tower) { return tower->GetID() == towerID;});
if (it == m_Towers.end()) return nullptr; if (it == m_Towers.end()) return nullptr;
return *it; return *it;
} }
void World::OnArcherTowerShot(MobPtr tarGet, ArcherTower* shooter) { void World::OnArcherTowerShot(MobPtr tarGet, ArcherTower* shooter) {
bool fireArrows = shooter->GetLevel().GetPath() == TowerPath::Bottom; bool fireArrows = shooter->GetLevel().GetPath() == TowerPath::Bottom;
bool explosiveArrows = shooter->GetLevel().GetLevel() == 4 && fireArrows; bool explosiveArrows = shooter->GetLevel().GetLevel() == 4 && fireArrows;
GetWorldNotifier().NotifyListeners(&WorldListener::OnArrowShot, tarGet, fireArrows, shooter); GetWorldNotifier().NotifyListeners(&WorldListener::OnArrowShot, tarGet, fireArrows, shooter);
if (explosiveArrows) { if (explosiveArrows) {
GetWorldNotifier().NotifyListeners(&WorldListener::OnExplosion, utils::shape::Circle{ tarGet->GetCenterX(), tarGet->GetCenterY(), ArcherTower::ExplosionRadius }, shooter->GetStats()->GetDamage(), shooter); GetWorldNotifier().NotifyListeners(&WorldListener::OnExplosion, utils::shape::Circle{ tarGet->GetCenterX(), tarGet->GetCenterY(), ArcherTower::ExplosionRadius }, shooter->GetStats()->GetDamage(), shooter);
} }
} }
void World::OnArrowShot(MobPtr tarGet, bool fireArrow, Tower* shooter) { void World::OnArrowShot(MobPtr tarGet, bool fireArrow, Tower* shooter) {
GetMobNotifier().NotifyListeners(&MobListener::OnMobDamage, tarGet.get(), shooter->GetStats()->GetDamage(), shooter); GetMobNotifier().NotifyListeners(&MobListener::OnMobDamage, tarGet.get(), shooter->GetStats()->GetDamage(), shooter);
if (fireArrow) { if (fireArrow) {
tarGet->AddEffect(EffectType::Fire, ArcherTower::FireDurationSec, shooter); tarGet->AddEffect(EffectType::Fire, ArcherTower::FireDurationSec, shooter);
} }
} }
void World::OnExplosion(utils::shape::Circle explosion, float centerDamage, Tower* shooter) { void World::OnExplosion(utils::shape::Circle explosion, float centerDamage, Tower* shooter) {
for (MobPtr mob : m_Mobs) { for (MobPtr mob : m_Mobs) {
if (mob->IsAlive() && mob->CollidesWith(explosion)) { if (mob->IsAlive() && mob->CollidesWith(explosion)) {
// linear distance damage reduction // linear distance damage reduction
float explosionDamage = mob->Distance(explosion) / explosion.GetRadius() * centerDamage; float explosionDamage = mob->Distance(explosion) / explosion.GetRadius() * centerDamage;
GetMobNotifier().NotifyListeners(&MobListener::OnMobDamage, mob.get(), explosionDamage, shooter); GetMobNotifier().NotifyListeners(&MobListener::OnMobDamage, mob.get(), explosionDamage, shooter);
} }
} }
} }
void World::OnMobCastleDamage(Mob* damager, TeamCastle* enemyCastle, float damage) { void World::OnMobCastleDamage(Mob* damager, TeamCastle* enemyCastle, float damage) {
enemyCastle->Damage(damage); enemyCastle->Damage(damage);
if (enemyCastle->GetLife() <= 0) { if (enemyCastle->GetLife() <= 0) {
m_Game->NotifyListeners(&GameListener::OnGameEnd); m_Game->NotifyListeners(&GameListener::OnGameEnd);
} }
} }
void World::OnMobDamage(Mob* tarGet, float damage, Tower* source) { void World::OnMobDamage(Mob* tarGet, float damage, Tower* source) {
tarGet->Damage(damage, source); tarGet->Damage(damage, source);
if (tarGet->IsDead()) { if (tarGet->IsDead()) {
GetMobNotifier().NotifyListeners(&MobListener::OnMobDie, tarGet); GetMobNotifier().NotifyListeners(&MobListener::OnMobDie, tarGet);
} }
} }
Team& World::GetRedTeam() { Team& World::GetRedTeam() {
return m_Game->GetRedTeam(); return m_Game->GetRedTeam();
} }
const Team& World::GetRedTeam() const { const Team& World::GetRedTeam() const {
return m_Game->GetRedTeam(); return m_Game->GetRedTeam();
} }
Team& World::GetBlueTeam() { Team& World::GetBlueTeam() {
return m_Game->GetBlueTeam(); return m_Game->GetBlueTeam();
} }
const Team& World::GetBlueTeam() const { const Team& World::GetBlueTeam() const {
return m_Game->GetBlueTeam(); return m_Game->GetBlueTeam();
} }
Team& World::GetTeam(TeamColor team) { Team& World::GetTeam(TeamColor team) {
return m_Game->GetTeam(team); return m_Game->GetTeam(team);
} }
const Team& World::GetTeam(TeamColor team) const { const Team& World::GetTeam(TeamColor team) const {
return m_Game->GetTeam(team); return m_Game->GetTeam(team);
} }
const Player* World::GetPlayerById(PlayerID id) const { const Player* World::GetPlayerById(PlayerID id) const {
return m_Game->GetPlayerById(id); return m_Game->GetPlayerById(id);
} }
const TeamList& World::GetTeams() const { const TeamList& World::GetTeams() const {
return m_Game->GetTeams(); return m_Game->GetTeams();
} }
} // namespace game } // namespace game

View File

@@ -5,73 +5,73 @@ namespace td {
namespace client { namespace client {
bool Client::Connect(const network::IPAddresses& addresses, std::uint16_t port) { bool Client::Connect(const network::IPAddresses& addresses, std::uint16_t port) {
for (const network::IPAddress& address : addresses) { for (const network::IPAddress& address : addresses) {
if (address.IsValid() && m_Connexion.Connect(address.ToString(), port)) { if (address.IsValid() && m_Connexion.Connect(address.ToString(), port)) {
m_Connected = true; m_Connected = true;
return true; return true;
} }
} }
utils::LOGE("Failed to connect !"); utils::LOGE("Failed to connect !");
return false; return false;
} }
void Client::SelectTeam(game::TeamColor team) { void Client::SelectTeam(game::TeamColor team) {
if (!m_Connected) if (!m_Connected)
return; return;
protocol::SelectTeamPacket packet(team); protocol::SelectTeamPacket packet(team);
m_Connexion.SendPacket(&packet); m_Connexion.SendPacket(&packet);
} }
void Client::CloseConnection() { void Client::CloseConnection() {
if (!m_Connected) if (!m_Connected)
return; return;
m_Connected = false; m_Connected = false;
protocol::DisconnectPacket packet; protocol::DisconnectPacket packet;
m_Connexion.SendPacket(&packet); m_Connexion.SendPacket(&packet);
} }
void Client::Tick(std::uint64_t delta) { void Client::Tick(std::uint64_t delta) {
if (!m_Connected) if (!m_Connected)
return; return;
m_Connected = m_Connexion.UpdateSocket(); m_Connected = m_Connexion.UpdateSocket();
if (!m_Connected) { if (!m_Connected) {
utils::LOG(utils::format("Disconnected ! (Reason : %s)", m_Connexion.GetDisconnectReason().c_str())); utils::LOG(utils::format("Disconnected ! (Reason : %s)", m_Connexion.GetDisconnectReason().c_str()));
Reset(); Reset();
} else { } else {
m_Game->Tick(delta); m_Game->Tick(delta);
} }
} }
void Client::Render() { void Client::Render() {
m_Game->RenderWorld(); m_Game->RenderWorld();
} }
void Client::Reset() { void Client::Reset() {
m_Game.reset(0); m_Game.reset(0);
m_Game = std::make_unique<ClientGame>(this); m_Game = std::make_unique<ClientGame>(this);
} }
void Client::SendMobs(const std::vector<protocol::MobSend>& mobSends) { void Client::SendMobs(const std::vector<protocol::MobSend>& mobSends) {
protocol::SendMobsPacket packet(mobSends); protocol::SendMobsPacket packet(mobSends);
m_Connexion.SendPacket(&packet); m_Connexion.SendPacket(&packet);
} }
void Client::PlaceTower(game::TowerType type, const glm::vec2& position) { void Client::PlaceTower(game::TowerType type, const Vec2f& position) {
protocol::PlaceTowerPacket packet(position.x, position.y, type); protocol::PlaceTowerPacket packet(position.x, position.y, type);
m_Connexion.SendPacket(&packet); m_Connexion.SendPacket(&packet);
} }
void Client::UpgradeTower(game::TowerID tower, game::TowerLevel level) { void Client::UpgradeTower(game::TowerID tower, game::TowerLevel level) {
protocol::UpgradeTowerPacket packet(tower, level); protocol::UpgradeTowerPacket packet(tower, level);
m_Connexion.SendPacket(&packet); m_Connexion.SendPacket(&packet);
} }
void Client::RemoveTower(game::TowerID tower) { void Client::RemoveTower(game::TowerID tower) {
protocol::RemoveTowerPacket packet(tower); protocol::RemoveTowerPacket packet(tower);
m_Connexion.SendPacket(&packet); m_Connexion.SendPacket(&packet);
} }
} // namespace client } // namespace client

View File

@@ -5,43 +5,44 @@ namespace td {
namespace client { namespace client {
ClientConnexion::ClientConnexion() : Connexion(&m_Dispatcher), m_ServerTPS(0) { ClientConnexion::ClientConnexion() : Connexion(&m_Dispatcher), m_ServerTPS(0) {
RegisterHandlers(); RegisterHandlers();
} }
void ClientConnexion::RegisterHandlers() { void ClientConnexion::RegisterHandlers() {
GetDispatcher()->RegisterHandler(protocol::PacketType::KeepAlive, this); GetDispatcher()->RegisterHandler(protocol::PacketType::KeepAlive, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::ConnectionInfo, this); GetDispatcher()->RegisterHandler(protocol::PacketType::ConnectionInfo, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::Disconnect, this); GetDispatcher()->RegisterHandler(protocol::PacketType::Disconnect, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::ServerTps, this); GetDispatcher()->RegisterHandler(protocol::PacketType::ServerTps, this);
} }
void ClientConnexion::HandlePacket(const protocol::KeepAlivePacket* packet) { void ClientConnexion::HandlePacket(const protocol::KeepAlivePacket* packet) {
protocol::KeepAlivePacket keepAlivePacket(packet->GetAliveID()); protocol::KeepAlivePacket keepAlivePacket(packet->GetAliveID());
SendPacket(&keepAlivePacket); SendPacket(&keepAlivePacket);
} }
void ClientConnexion::HandlePacket(const protocol::ConnexionInfoPacket* packet) { void ClientConnexion::HandlePacket(const protocol::ConnexionInfoPacket* packet) {
m_ConnectionID = packet->GetConnectionID(); m_ConnectionID = packet->GetConnectionID();
Login(); Login();
} }
void ClientConnexion::HandlePacket(const protocol::ServerTpsPacket* packet) { void ClientConnexion::HandlePacket(const protocol::ServerTpsPacket* packet) {
m_ServerTPS = packet->GetTPS(); m_ServerTPS = packet->GetTPS();
m_Ping = utils::GetTime() - packet->GetPacketSendTime(); m_ServerMSPT = packet->GetMSPT();
m_Ping = utils::GetTime() - packet->GetPacketSendTime();
} }
void ClientConnexion::Login() { void ClientConnexion::Login() {
td::protocol::PlayerLoginPacket loginPacket("Persson" + std::to_string(m_ConnectionID)); td::protocol::PlayerLoginPacket loginPacket("Persson" + std::to_string(m_ConnectionID));
SendPacket(&loginPacket); SendPacket(&loginPacket);
} }
bool ClientConnexion::UpdateSocket() { bool ClientConnexion::UpdateSocket() {
return Connexion::UpdateSocket(); return Connexion::UpdateSocket();
} }
void ClientConnexion::HandlePacket(const protocol::DisconnectPacket* packet) { void ClientConnexion::HandlePacket(const protocol::DisconnectPacket* packet) {
m_DisconnectReason = packet->GetReason(); m_DisconnectReason = packet->GetReason();
CloseConnection(); CloseConnection();
} }
} // namespace client } // namespace client

View File

@@ -8,110 +8,110 @@ namespace client {
ClientGame::ClientGame(Client* client) : protocol::PacketHandler(client->GetConnexion().GetDispatcher()), ClientGame::ClientGame(Client* client) : protocol::PacketHandler(client->GetConnexion().GetDispatcher()),
game::Game(&m_WorldClient), m_Client(client), m_Renderer(client->GetRenderer()), m_WorldClient(this), game::Game(&m_WorldClient), m_Client(client), m_Renderer(client->GetRenderer()), m_WorldClient(this),
m_WorldRenderer(&m_WorldClient, this) { m_WorldRenderer(&m_WorldClient, this) {
GetDispatcher()->RegisterHandler(protocol::PacketType::ConnectionInfo, this); GetDispatcher()->RegisterHandler(protocol::PacketType::ConnectionInfo, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::PlayerJoin, this); GetDispatcher()->RegisterHandler(protocol::PacketType::PlayerJoin, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::PlayerList, this); GetDispatcher()->RegisterHandler(protocol::PacketType::PlayerList, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::PlayerLeave, this); GetDispatcher()->RegisterHandler(protocol::PacketType::PlayerLeave, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::UpdatePlayerTeam, this); GetDispatcher()->RegisterHandler(protocol::PacketType::UpdatePlayerTeam, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateLobbyTime, this); GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateLobbyTime, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateGameState, this); GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateGameState, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateMoney, this); GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateMoney, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateEXP, this); GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateEXP, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::Disconnect, this); GetDispatcher()->RegisterHandler(protocol::PacketType::Disconnect, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::WorldData, this); GetDispatcher()->RegisterHandler(protocol::PacketType::WorldData, this);
} }
ClientGame::~ClientGame() { ClientGame::~ClientGame() {
GetDispatcher()->UnregisterHandler(this); GetDispatcher()->UnregisterHandler(this);
} }
void ClientGame::Tick(std::uint64_t delta) { void ClientGame::Tick(std::uint64_t delta) {
game::Game::Tick(delta); game::Game::Tick(delta);
m_WorldRenderer.Update(); m_WorldRenderer.Update();
if (m_GameState == game::GameState::Lobby && m_LobbyTime > 0) { if (m_GameState == game::GameState::Lobby && m_LobbyTime > 0) {
m_LobbyTime -= delta; m_LobbyTime -= delta;
} }
} }
void ClientGame::HandlePacket(const protocol::PlayerJoinPacket* packet) { void ClientGame::HandlePacket(const protocol::PlayerJoinPacket* packet) {
game::Player player(packet->GetPlayerID()); game::Player player(packet->GetPlayerID());
player.SetName(packet->GetPlayerName()); player.SetName(packet->GetPlayerName());
m_Players.insert({ player.GetID(), player }); m_Players.insert({ player.GetID(), player });
} }
void ClientGame::HandlePacket(const protocol::PlayerLeavePacket* packet) { void ClientGame::HandlePacket(const protocol::PlayerLeavePacket* packet) {
game::Player* player = &m_Players[packet->GetPlayerID()]; game::Player* player = &m_Players[packet->GetPlayerID()];
if (player->GetTeamColor() != game::TeamColor::None) { if (player->GetTeamColor() != game::TeamColor::None) {
m_Teams[(std::size_t)player->GetTeamColor()].RemovePlayer(player); m_Teams[(std::size_t)player->GetTeamColor()].RemovePlayer(player);
} }
m_Players.erase(player->GetID()); m_Players.erase(player->GetID());
} }
void ClientGame::HandlePacket(const protocol::PlayerListPacket* packet) { void ClientGame::HandlePacket(const protocol::PlayerListPacket* packet) {
for (auto pair : packet->GetPlayers()) { for (auto pair : packet->GetPlayers()) {
std::uint8_t playerID = pair.first; std::uint8_t playerID = pair.first;
protocol::PlayerInfo playerInfo = pair.second; protocol::PlayerInfo playerInfo = pair.second;
game::Player player(playerID); game::Player player(playerID);
player.SetName(playerInfo.name); player.SetName(playerInfo.name);
player.SetTeamColor(playerInfo.team); player.SetTeamColor(playerInfo.team);
m_Players.insert({ playerID, player }); m_Players.insert({ playerID, player });
if (player.GetTeamColor() != game::TeamColor::None) { if (player.GetTeamColor() != game::TeamColor::None) {
m_Teams[(std::size_t)player.GetTeamColor()].AddPlayer(&m_Players[playerID]); m_Teams[(std::size_t)player.GetTeamColor()].AddPlayer(&m_Players[playerID]);
} }
} }
m_Player = &m_Players[m_ConnexionID]; m_Player = &m_Players[m_ConnexionID];
} }
void ClientGame::HandlePacket(const protocol::UpdatePlayerTeamPacket* packet) { void ClientGame::HandlePacket(const protocol::UpdatePlayerTeamPacket* packet) {
game::Player* player = &m_Players[packet->GetPlayerID()]; game::Player* player = &m_Players[packet->GetPlayerID()];
if (player->GetTeamColor() == game::TeamColor::None) { //join a team if (player->GetTeamColor() == game::TeamColor::None) { //join a team
GetTeam(packet->GetSelectedTeam()).AddPlayer(player); GetTeam(packet->GetSelectedTeam()).AddPlayer(player);
} else if (packet->GetSelectedTeam() == game::TeamColor::None) { // leave a team } else if (packet->GetSelectedTeam() == game::TeamColor::None) { // leave a team
GetTeam(player->GetTeamColor()).RemovePlayer(player); GetTeam(player->GetTeamColor()).RemovePlayer(player);
} else { // change team } else { // change team
GetTeam(player->GetTeamColor()).RemovePlayer(player); GetTeam(player->GetTeamColor()).RemovePlayer(player);
GetTeam(packet->GetSelectedTeam()).AddPlayer(player); GetTeam(packet->GetSelectedTeam()).AddPlayer(player);
} }
player->SetTeamColor(packet->GetSelectedTeam()); player->SetTeamColor(packet->GetSelectedTeam());
} }
void ClientGame::HandlePacket(const protocol::UpdateGameStatePacket* packet) { void ClientGame::HandlePacket(const protocol::UpdateGameStatePacket* packet) {
SetGameState(packet->GetGameState()); SetGameState(packet->GetGameState());
} }
void ClientGame::HandlePacket(const protocol::ConnexionInfoPacket* packet) { void ClientGame::HandlePacket(const protocol::ConnexionInfoPacket* packet) {
m_ConnexionID = packet->GetConnectionID(); m_ConnexionID = packet->GetConnectionID();
} }
void ClientGame::HandlePacket(const protocol::UpdateLobbyTimePacket* packet) { void ClientGame::HandlePacket(const protocol::UpdateLobbyTimePacket* packet) {
m_LobbyTime = packet->GetRemainingTime(); m_LobbyTime = packet->GetRemainingTime();
} }
void ClientGame::HandlePacket(const protocol::UpdateMoneyPacket* packet) { void ClientGame::HandlePacket(const protocol::UpdateMoneyPacket* packet) {
m_Player->SetGold(packet->GetGold()); m_Player->SetGold(packet->GetGold());
} }
void ClientGame::HandlePacket(const protocol::UpdateExpPacket* packet) { void ClientGame::HandlePacket(const protocol::UpdateExpPacket* packet) {
m_Player->SetExp(packet->GetExp()); m_Player->SetExp(packet->GetExp());
} }
void ClientGame::HandlePacket(const protocol::DisconnectPacket* packet) { void ClientGame::HandlePacket(const protocol::DisconnectPacket* packet) {
m_GameState = game::GameState::Disconnected; m_GameState = game::GameState::Disconnected;
m_Renderer->SetBackgroundColor({ 0, 0, 0 }); m_Renderer->SetBackgroundColor({ 0, 0, 0 });
} }
void ClientGame::HandlePacket(const protocol::WorldDataPacket* packet) { void ClientGame::HandlePacket(const protocol::WorldDataPacket* packet) {
m_WorldRenderer.LoadModels(); m_WorldRenderer.LoadModels();
// set cam pos to player spawn // set cam pos to player spawn
const game::Spawn& spawn = m_World->GetTeam(m_Player->GetTeamColor()).GetSpawn(); const game::Spawn& spawn = m_World->GetTeam(m_Player->GetTeamColor()).GetSpawn();
m_WorldRenderer.SetCamPos(spawn.GetCenterX(), spawn.GetCenterY()); m_WorldRenderer.SetCamPos(spawn.GetCenterX(), spawn.GetCenterY());
} }
void ClientGame::RenderWorld() { void ClientGame::RenderWorld() {
if (m_GameState == game::GameState::Game || m_GameState == game::GameState::EndGame) { if (m_GameState == game::GameState::Game || m_GameState == game::GameState::EndGame) {
m_WorldRenderer.Render(); m_WorldRenderer.Render();
} }
} }
} // namespace client } // namespace client

View File

@@ -7,69 +7,69 @@ namespace td {
namespace client { namespace client {
WorldClient::WorldClient(ClientGame* game) : game::World(game), protocol::PacketHandler(game->GetDispatcher()), m_Game(game) { WorldClient::WorldClient(ClientGame* game) : game::World(game), protocol::PacketHandler(game->GetDispatcher()), m_Game(game) {
GetDispatcher()->RegisterHandler(protocol::PacketType::WorldAddTower, this); GetDispatcher()->RegisterHandler(protocol::PacketType::WorldAddTower, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::WorldBeginData, this); GetDispatcher()->RegisterHandler(protocol::PacketType::WorldBeginData, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::WorldData, this); GetDispatcher()->RegisterHandler(protocol::PacketType::WorldData, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::SpawnMob, this); GetDispatcher()->RegisterHandler(protocol::PacketType::SpawnMob, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::UpgradeTower, this); GetDispatcher()->RegisterHandler(protocol::PacketType::UpgradeTower, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::RemoveTower, this); GetDispatcher()->RegisterHandler(protocol::PacketType::RemoveTower, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateCastleLife, this); GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateCastleLife, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateMobStates, this); GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateMobStates, this);
} }
void WorldClient::HandlePacket(const protocol::WorldBeginDataPacket* packet) { void WorldClient::HandlePacket(const protocol::WorldBeginDataPacket* packet) {
LoadMap(packet); LoadMap(packet);
if (m_Game->GetGameState() == game::GameState::Game) { if (m_Game->GetGameState() == game::GameState::Game) {
const game::Color& backgroundColor = GetBackgroundColor(); const Color& backgroundColor = GetBackgroundColor();
m_Game->GetRenderer()->SetBackgroundColor({ static_cast<float>(backgroundColor.r / 255.0f), static_cast<float>(backgroundColor.g / 255.0f), m_Game->GetRenderer()->SetBackgroundColor({ static_cast<float>(backgroundColor.r / 255.0f), static_cast<float>(backgroundColor.g / 255.0f),
static_cast<float>(backgroundColor.b / 255.0f) }); static_cast<float>(backgroundColor.b / 255.0f) });
} }
} }
void WorldClient::HandlePacket(const protocol::WorldDataPacket* packet) { void WorldClient::HandlePacket(const protocol::WorldDataPacket* packet) {
LoadMap(packet); LoadMap(packet);
} }
void WorldClient::HandlePacket(const protocol::SpawnMobPacket* packet) { void WorldClient::HandlePacket(const protocol::SpawnMobPacket* packet) {
SpawnMobAt(packet->GetMobID(), packet->GetMobType(), packet->GetMobLevel(), packet->GetSender(), SpawnMobAt(packet->GetMobID(), packet->GetMobType(), packet->GetMobLevel(), packet->GetSender(),
packet->GetMobX(), packet->GetMobY(), packet->GetMobDirection()); packet->GetMobX(), packet->GetMobY(), packet->GetMobDirection());
} }
void WorldClient::HandlePacket(const protocol::UpgradeTowerPacket* packet) { void WorldClient::HandlePacket(const protocol::UpgradeTowerPacket* packet) {
game::TowerPtr tower = GetTowerById(packet->GetTowerID()); game::TowerPtr tower = GetTowerById(packet->GetTowerID());
if (tower == nullptr) return; // this should not happen but who knows ? if (tower == nullptr) return; // this should not happen but who knows ?
tower->Upgrade(packet->GetTowerLevel().GetLevel(), packet->GetTowerLevel().GetPath()); tower->Upgrade(packet->GetTowerLevel().GetLevel(), packet->GetTowerLevel().GetPath());
} }
void WorldClient::HandlePacket(const protocol::WorldAddTowerPacket* packet) { void WorldClient::HandlePacket(const protocol::WorldAddTowerPacket* packet) {
game::TowerPtr newTower = PlaceTowerAt(packet->GetTowerID(), packet->GetTowerType(), packet->GetTowerX(), packet->GetTowerY(), packet->GetBuilder()); game::TowerPtr newTower = PlaceTowerAt(packet->GetTowerID(), packet->GetTowerType(), packet->GetTowerX(), packet->GetTowerY(), packet->GetBuilder());
GetWorldNotifier().NotifyListeners(&WorldListener::OnTowerAdd, newTower); GetWorldNotifier().NotifyListeners(&WorldListener::OnTowerAdd, newTower);
} }
void WorldClient::HandlePacket(const protocol::RemoveTowerPacket* packet) { void WorldClient::HandlePacket(const protocol::RemoveTowerPacket* packet) {
game::TowerPtr tower = RemoveTower(packet->GetTowerID()); game::TowerPtr tower = RemoveTower(packet->GetTowerID());
if (tower != nullptr) { if (tower != nullptr) {
GetWorldNotifier().NotifyListeners(&WorldListener::OnTowerRemove, tower); GetWorldNotifier().NotifyListeners(&WorldListener::OnTowerRemove, tower);
} }
} }
void WorldClient::HandlePacket(const protocol::UpdateMobStatesPacket* packet) { void WorldClient::HandlePacket(const protocol::UpdateMobStatesPacket* packet) {
for (auto mobState : packet->GetMobStates()) { for (auto mobState : packet->GetMobStates()) {
game::MobID mobId = mobState.GetMobId(); game::MobID mobId = mobState.GetMobId();
auto it = std::find_if(GetMobList().begin(), GetMobList().end(), [mobId](game::MobPtr mob) { return mob->GetMobID() == mobId; }); auto it = std::find_if(GetMobList().begin(), GetMobList().end(), [mobId](game::MobPtr mob) { return mob->GetMobID() == mobId; });
if (it != GetMobList().end()) { if (it != GetMobList().end()) {
game::MobPtr& mob = *it; game::MobPtr& mob = *it;
mob->SetCenter(mobState.GetMobPosition()); mob->SetCenter(mobState.GetMobPosition());
mob->SetDirection(mobState.GetMobDirection()); mob->SetDirection(mobState.GetMobDirection());
mob->SetHealth(mobState.GetMobLife()); mob->SetHealth(mobState.GetMobLife());
} }
} }
} }
void WorldClient::HandlePacket(const protocol::UpdateCastleLifePacket* packet) { void WorldClient::HandlePacket(const protocol::UpdateCastleLifePacket* packet) {
GetTeam(packet->GetTeamColor()).GetCastle().SetLife(packet->GetCastleLife()); GetTeam(packet->GetTeamColor()).GetCastle().SetLife(packet->GetCastleLife());
} }
} // namespace client } // namespace client

View File

@@ -13,17 +13,17 @@ namespace td {
namespace server { namespace server {
/*static constexpr std::uint8_t timeNotifications[] = { /*static constexpr std::uint8_t timeNotifications[] = {
2 * 60, // 2 min 2 * 60, // 2 min
60 + 30, // 1 min 30 s 60 + 30, // 1 min 30 s
60, // 1 min 60, // 1 min
30, // 30 s 30, // 30 s
15, // 15 s 15, // 15 s
10, // 10 s 10, // 10 s
5, // 5 s 5, // 5 s
4, // 4 s 4, // 4 s
3, // 3 s 3, // 3 s
2, // 2 s 2, // 2 s
1, // 1 s 1, // 1 s
};*/ };*/
Lobby::Lobby(Server* server) : m_Server(server), m_Timer(1000, std::bind(&Lobby::SendTimeRemaining, this)) { Lobby::Lobby(Server* server) : m_Server(server), m_Timer(1000, std::bind(&Lobby::SendTimeRemaining, this)) {
@@ -31,50 +31,50 @@ Lobby::Lobby(Server* server) : m_Server(server), m_Timer(1000, std::bind(&Lobby:
} }
void Lobby::Tick() { void Lobby::Tick() {
if (m_GameStarted || m_StartTimerTime == 0) if (m_GameStarted || m_StartTimerTime == 0)
return; return;
if (utils::GetTime() - m_StartTimerTime >= LobbyWaitingTime) { if (utils::GetTime() - m_StartTimerTime >= LobbyWaitingTime) {
m_Server->GetGame().NotifyListeners(&game::GameListener::OnGameBegin); m_Server->GetGame().NotifyListeners(&game::GameListener::OnGameBegin);
m_GameStarted = true; m_GameStarted = true;
return; return;
} }
m_Timer.Update(); m_Timer.Update();
} }
void Lobby::SendTimeRemaining() { void Lobby::SendTimeRemaining() {
protocol::UpdateLobbyTimePacket packet(LobbyWaitingTime - (utils::GetTime() - m_StartTimerTime)); // converting second to millis protocol::UpdateLobbyTimePacket packet(LobbyWaitingTime - (utils::GetTime() - m_StartTimerTime)); // converting second to millis
m_Server->BroadcastPacket(&packet); m_Server->BroadcastPacket(&packet);
} }
void Lobby::OnPlayerJoin(std::uint8_t playerID) { void Lobby::OnPlayerJoin(std::uint8_t playerID) {
if (m_GameStarted) if (m_GameStarted)
return; return;
utils::LOG("(Server) Player Joined Lobby !"); utils::LOG("(Server) Player Joined Lobby !");
m_Players.push_back(playerID); m_Players.push_back(playerID);
if (m_Players.size() == MIN_PLAYER_WAITING) { // start timer if a second player join the match if (m_Players.size() == MIN_PLAYER_WAITING) { // start timer if a second player join the match
m_StartTimerTime = utils::GetTime(); m_StartTimerTime = utils::GetTime();
m_Timer.Reset(); m_Timer.Reset();
SendTimeRemaining(); SendTimeRemaining();
} }
} }
void Lobby::OnPlayerLeave(std::uint8_t playerID) { void Lobby::OnPlayerLeave(std::uint8_t playerID) {
if (m_GameStarted) if (m_GameStarted)
return; return;
utils::LOG("(Server) Player Leaved Lobby !"); utils::LOG("(Server) Player Leaved Lobby !");
auto it = std::find(m_Players.begin(), m_Players.end(), playerID); auto it = std::find(m_Players.begin(), m_Players.end(), playerID);
if (it == m_Players.end()) if (it == m_Players.end())
return; return;
m_Players.erase(it); m_Players.erase(it);
if (m_Players.size() == 1) { if (m_Players.size() == 1) {
protocol::UpdateLobbyTimePacket packet(0); protocol::UpdateLobbyTimePacket packet(0);
m_Server->BroadcastPacket(&packet); m_Server->BroadcastPacket(&packet);
m_StartTimerTime = 0; // reset timer if there is only one player left m_StartTimerTime = 0; // reset timer if there is only one player left
} }
} }
} // namespace server } // namespace server

View File

@@ -7,139 +7,140 @@ namespace td {
namespace server { namespace server {
Server::Server(const std::string& worldFilePath) : m_ServerRunning(false) { Server::Server(const std::string& worldFilePath) : m_ServerRunning(false) {
m_Game.GetWorld()->LoadMapFromFile(worldFilePath); m_Game.GetWorld()->LoadMapFromFile(worldFilePath);
} }
Server::~Server() { Server::~Server() {
if (m_Thread.joinable()) if (m_Thread.joinable())
m_Thread.join(); m_Thread.join();
} }
void Server::StartThread() { void Server::StartThread() {
m_Thread = std::thread([this]() { m_Thread = std::thread([this]() {
std::uint64_t lastTime = td::utils::GetTime(); std::uint64_t lastTime = td::utils::GetTime();
while (m_ServerRunning) { while (m_ServerRunning) {
std::uint64_t time = td::utils::GetTime(); std::uint64_t time = td::utils::GetTime();
std::uint64_t delta = time - lastTime; std::uint64_t delta = time - lastTime;
if (delta >= SERVER_TICK) { if (delta >= SERVER_TICK) {
Tick(delta); Tick(delta);
lastTime = td::utils::GetTime(); lastTime = td::utils::GetTime();
std::uint64_t sleepTime = SERVER_TICK - (delta - SERVER_TICK); m_TickCounter.SetMSPT(lastTime - time);
std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime)); std::uint64_t sleepTime = SERVER_TICK - (delta - SERVER_TICK);
} std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime));
}
} }
Clean(); Clean();
}); });
} }
void Server::Close() { void Server::Close() {
StopThread(); StopThread();
} }
void Server::StopThread() { void Server::StopThread() {
m_ServerRunning = false; m_ServerRunning = false;
} }
bool Server::Start(std::uint16_t port) { bool Server::Start(std::uint16_t port) {
if (!m_Listener.Listen(port, 10)) { if (!m_Listener.Listen(port, 10)) {
utils::LOGE(utils::format("Failed to bind port %u !", port)); utils::LOGE(utils::format("Failed to bind port %u !", port));
return false; return false;
} }
if (!m_Listener.SetBlocking(false)) { if (!m_Listener.SetBlocking(false)) {
utils::LOGE("Failed to block server socket !"); utils::LOGE("Failed to block server socket !");
return false; return false;
} }
utils::LOG(utils::format("Server started at port %u !", port)); utils::LOG(utils::format("Server started at port %u !", port));
m_TickCounter.Reset(); m_TickCounter.Reset();
m_ServerRunning = true; m_ServerRunning = true;
StartThread(); StartThread();
return true; return true;
} }
void Server::Clean() { void Server::Clean() {
m_Listener.Close(); m_Listener.Close();
m_Listener.Destroy(); m_Listener.Destroy();
m_Connections.clear(); m_Connections.clear();
GetPlayers().clear(); GetPlayers().clear();
utils::LOG("Server successfully stopped !"); utils::LOG("Server successfully stopped !");
} }
void Server::Stop() { void Server::Stop() {
if (!m_ServerRunning) if (!m_ServerRunning)
return; return;
protocol::DisconnectPacket packet("Server closed"); protocol::DisconnectPacket packet("Server closed");
BroadcastPacket(&packet); BroadcastPacket(&packet);
StopThread(); StopThread();
} }
void Server::Tick(std::uint64_t delta) { void Server::Tick(std::uint64_t delta) {
Accept(); Accept();
UpdateSockets(); UpdateSockets();
m_Lobby.Tick(); m_Lobby.Tick();
m_Game.Tick(delta); m_Game.Tick(delta);
if (m_TickCounter.Update()) { if (m_TickCounter.Update()) {
protocol::ServerTpsPacket packet(m_TickCounter.GetTPS(), utils::GetTime()); protocol::ServerTpsPacket packet(m_TickCounter.GetTPS(), m_TickCounter.GetMSPT(), utils::GetTime());
BroadcastPacket(&packet); BroadcastPacket(&packet);
} }
} }
void Server::Accept() { void Server::Accept() {
static std::uint8_t newPlayerID = 0; static std::uint8_t newPlayerID = 0;
network::TCPSocket newSocket; network::TCPSocket newSocket;
if (m_Listener.Accept(newSocket)) { if (m_Listener.Accept(newSocket)) {
ServerConnexion con(newSocket, newPlayerID); ServerConnexion con(newSocket, newPlayerID);
m_Connections.insert(std::move(ConnexionMap::value_type{ newPlayerID, std::move(con) })); m_Connections.insert(std::move(ConnexionMap::value_type{ newPlayerID, std::move(con) }));
OnPlayerJoin(newPlayerID); OnPlayerJoin(newPlayerID);
m_Connections[newPlayerID].SetServer(this); m_Connections[newPlayerID].SetServer(this);
newPlayerID++; newPlayerID++;
} }
} }
void Server::UpdateSockets() { void Server::UpdateSockets() {
std::int16_t closedConnexionID = -1; std::int16_t closedConnexionID = -1;
for (auto& connection : m_Connections) { for (auto& connection : m_Connections) {
ServerConnexion& con = connection.second; ServerConnexion& con = connection.second;
if (con.GetSocketStatus() != network::Socket::Status::Connected) { if (con.GetSocketStatus() != network::Socket::Status::Connected) {
closedConnexionID = connection.first; closedConnexionID = connection.first;
} else { } else {
con.UpdateSocket(); con.UpdateSocket();
} }
} }
if (closedConnexionID != -1) { if (closedConnexionID != -1) {
RemoveConnexion(closedConnexionID); RemoveConnexion(closedConnexionID);
} }
} }
void Server::BroadcastPacket(const protocol::Packet* packet) { void Server::BroadcastPacket(const protocol::Packet* packet) {
for (auto& connection : m_Connections) { for (auto& connection : m_Connections) {
ServerConnexion& con = connection.second; ServerConnexion& con = connection.second;
con.SendPacket(packet); con.SendPacket(packet);
} }
} }
void Server::RemoveConnexion(std::uint8_t connexionID) { void Server::RemoveConnexion(std::uint8_t connexionID) {
GetPlayers().erase(GetPlayers().find(connexionID)); GetPlayers().erase(GetPlayers().find(connexionID));
m_Connections.erase(connexionID); m_Connections.erase(connexionID);
m_Lobby.OnPlayerLeave(connexionID); m_Lobby.OnPlayerLeave(connexionID);
OnPlayerLeave(connexionID); OnPlayerLeave(connexionID);
} }
void Server::OnPlayerJoin(std::uint8_t id) { void Server::OnPlayerJoin(std::uint8_t id) {
m_Lobby.OnPlayerJoin(id); m_Lobby.OnPlayerJoin(id);
GetPlayers().insert({ id, game::Player{id} }); GetPlayers().insert({ id, game::Player{id} });
} }
void Server::OnPlayerLeave(std::uint8_t id) { void Server::OnPlayerLeave(std::uint8_t id) {
protocol::PlayerLeavePacket packet(id); protocol::PlayerLeavePacket packet(id);
BroadcastPacket(&packet); BroadcastPacket(&packet);
} }
} // namespace server } // namespace server

View File

@@ -10,11 +10,13 @@
#define KEEP_ALIVE_TIMEOUT 10 * 1000 // 10s #define KEEP_ALIVE_TIMEOUT 10 * 1000 // 10s
#define SAFE_CHECK(expr) if(expr) return
namespace td { namespace td {
namespace server { namespace server {
/* /*
NEVER TRUST USER INPUT NEVER TRUST USER INPUT
*/ */
@@ -23,174 +25,174 @@ 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) { ServerConnexion::ServerConnexion(network::TCPSocket& socket, std::uint8_t id) : Connexion::Connexion(&m_Dispatcher, socket), m_ID(id), m_Player(0) {
Connexion::UpdateSocket(); Connexion::UpdateSocket();
} }
ServerConnexion::ServerConnexion(ServerConnexion&& move) : Connexion::Connexion(std::move(move)), m_Server(move.m_Server), 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) { m_ID(move.m_ID), m_KeepAlive(move.m_KeepAlive), m_Player(move.m_Player) {
move.m_Server = nullptr; move.m_Server = nullptr;
RegisterHandlers(); RegisterHandlers();
} }
void ServerConnexion::RegisterHandlers() { void ServerConnexion::RegisterHandlers() {
GetDispatcher()->RegisterHandler(protocol::PacketType::PlayerLogin, this); GetDispatcher()->RegisterHandler(protocol::PacketType::PlayerLogin, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::KeepAlive, this); GetDispatcher()->RegisterHandler(protocol::PacketType::KeepAlive, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::SelectTeam, this); GetDispatcher()->RegisterHandler(protocol::PacketType::SelectTeam, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::Disconnect, this); GetDispatcher()->RegisterHandler(protocol::PacketType::Disconnect, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::PlaceTower, this); GetDispatcher()->RegisterHandler(protocol::PacketType::PlaceTower, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::SendMobs, this); GetDispatcher()->RegisterHandler(protocol::PacketType::SendMobs, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::UpgradeTower, this); GetDispatcher()->RegisterHandler(protocol::PacketType::UpgradeTower, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::RemoveTower, this); GetDispatcher()->RegisterHandler(protocol::PacketType::RemoveTower, this);
} }
bool ServerConnexion::UpdateSocket() { bool ServerConnexion::UpdateSocket() {
CheckKeepAlive(); CheckKeepAlive();
return Connexion::UpdateSocket(); return Connexion::UpdateSocket();
} }
void ServerConnexion::CheckKeepAlive() { void ServerConnexion::CheckKeepAlive() {
std::uint64_t time = utils::GetTime(); std::uint64_t time = utils::GetTime();
if (time - m_KeepAlive.sendTime > KEEP_ALIVE_TIMEOUT) { if (time - m_KeepAlive.sendTime > KEEP_ALIVE_TIMEOUT) {
if (m_KeepAlive.recievedResponse) { if (m_KeepAlive.recievedResponse) {
SendKeepAlive(); SendKeepAlive();
} else { } else {
protocol::DisconnectPacket packet("Time out"); protocol::DisconnectPacket packet("Time out");
SendPacket(&packet); SendPacket(&packet);
CloseConnection(); CloseConnection();
} }
} }
} }
void ServerConnexion::SendKeepAlive() { void ServerConnexion::SendKeepAlive() {
m_KeepAlive.keepAliveID = utils::GetRandomInt<std::uint64_t>(0, RAND_MAX); m_KeepAlive.keepAliveID = utils::GetRandomInt<std::uint64_t>(0, RAND_MAX);
m_KeepAlive.recievedResponse = false; m_KeepAlive.recievedResponse = false;
protocol::KeepAlivePacket keepAlivePacket(m_KeepAlive.keepAliveID); protocol::KeepAlivePacket keepAlivePacket(m_KeepAlive.keepAliveID);
SendPacket(&keepAlivePacket); SendPacket(&keepAlivePacket);
std::uint64_t time = utils::GetTime(); std::uint64_t time = utils::GetTime();
m_KeepAlive.sendTime = time; m_KeepAlive.sendTime = time;
} }
void ServerConnexion::HandlePacket(const protocol::PlayerLoginPacket* packet) { void ServerConnexion::HandlePacket(const protocol::PlayerLoginPacket* packet) {
if (m_Player->GetName().empty() && !packet->GetPlayerName().empty()) { if (m_Player->GetName().empty() && !packet->GetPlayerName().empty()) {
m_Player->SetName(packet->GetPlayerName()); m_Player->SetName(packet->GetPlayerName());
protocol::PlayerJoinPacket joinPacket(m_ID, m_Player->GetName()); protocol::PlayerJoinPacket joinPacket(m_ID, m_Player->GetName());
m_Server->BroadcastPacket(&joinPacket); m_Server->BroadcastPacket(&joinPacket);
std::map<std::uint8_t, protocol::PlayerInfo> playerNames; std::map<std::uint8_t, protocol::PlayerInfo> playerNames;
for (const auto& pair : m_Server->GetPlayers()) { for (const auto& pair : m_Server->GetPlayers()) {
const game::Player& player = pair.second; const game::Player& player = pair.second;
if (!player.GetName().empty()) { if (!player.GetName().empty()) {
protocol::PlayerInfo playerInfo; protocol::PlayerInfo playerInfo;
playerInfo.name = player.GetName(); playerInfo.name = player.GetName();
playerInfo.team = player.GetTeamColor(); playerInfo.team = player.GetTeamColor();
playerNames.insert({ player.GetID(), playerInfo }); playerNames.insert({ player.GetID(), playerInfo });
} }
} }
protocol::PlayerListPacket listPacket(playerNames); protocol::PlayerListPacket listPacket(playerNames);
SendPacket(&listPacket); SendPacket(&listPacket);
} }
} }
void ServerConnexion::HandlePacket(const protocol::SelectTeamPacket* packet) { void ServerConnexion::HandlePacket(const protocol::SelectTeamPacket* packet) {
if (m_Server->GetGame().GetGameState() != game::GameState::Lobby) SAFE_CHECK(m_Server->GetGame().GetGameState() != game::GameState::Lobby);
return;
if (static_cast<std::int8_t>(packet->GetSelectedTeam()) >= -1 || static_cast<std::int8_t>(packet->GetSelectedTeam()) <= 1) { if (static_cast<std::int8_t>(packet->GetSelectedTeam()) >= -1 || static_cast<std::int8_t>(packet->GetSelectedTeam()) <= 1) {
if (m_Player->GetTeamColor() == game::TeamColor::None) { // join a team if (m_Player->GetTeamColor() == game::TeamColor::None) { // join a team
m_Server->GetGame().GetTeam(packet->GetSelectedTeam()).AddPlayer(m_Player); m_Server->GetGame().GetTeam(packet->GetSelectedTeam()).AddPlayer(m_Player);
} else if (packet->GetSelectedTeam() == game::TeamColor::None) { // leave a team } else if (packet->GetSelectedTeam() == game::TeamColor::None) { // leave a team
m_Server->GetGame().GetTeam(m_Player->GetTeamColor()).RemovePlayer(m_Player); m_Server->GetGame().GetTeam(m_Player->GetTeamColor()).RemovePlayer(m_Player);
m_Player->SetTeamColor(game::TeamColor::None); m_Player->SetTeamColor(game::TeamColor::None);
} else { // change team } else { // change team
m_Server->GetGame().GetTeam(m_Player->GetTeamColor()).RemovePlayer(m_Player); m_Server->GetGame().GetTeam(m_Player->GetTeamColor()).RemovePlayer(m_Player);
m_Server->GetGame().GetTeam(packet->GetSelectedTeam()).AddPlayer(m_Player); m_Server->GetGame().GetTeam(packet->GetSelectedTeam()).AddPlayer(m_Player);
} }
m_Player->SetTeamColor(packet->GetSelectedTeam()); m_Player->SetTeamColor(packet->GetSelectedTeam());
protocol::UpdatePlayerTeamPacket updateTeamPacket(m_ID, packet->GetSelectedTeam()); protocol::UpdatePlayerTeamPacket updateTeamPacket(m_ID, packet->GetSelectedTeam());
m_Server->BroadcastPacket(&updateTeamPacket); m_Server->BroadcastPacket(&updateTeamPacket);
} }
} }
void ServerConnexion::HandlePacket(const protocol::KeepAlivePacket* packet) { void ServerConnexion::HandlePacket(const protocol::KeepAlivePacket* packet) {
if (packet->GetAliveID() == m_KeepAlive.keepAliveID) if (packet->GetAliveID() == m_KeepAlive.keepAliveID)
m_KeepAlive.recievedResponse = true; m_KeepAlive.recievedResponse = true;
} }
void ServerConnexion::HandlePacket(const protocol::DisconnectPacket* packet) { void ServerConnexion::HandlePacket(const protocol::DisconnectPacket* packet) {
CloseConnection(); CloseConnection();
} }
void ServerConnexion::SetServer(Server* server) { void ServerConnexion::SetServer(Server* server) {
m_Server = server; m_Server = server;
m_Player = &m_Server->GetPlayers().at(m_ID); m_Player = &m_Server->GetPlayers().at(m_ID);
InitConnection(); InitConnection();
SendKeepAlive(); SendKeepAlive();
} }
void ServerConnexion::InitConnection() { void ServerConnexion::InitConnection() {
protocol::UpdateGameStatePacket statePacket(m_Server->GetGame().GetGameState()); protocol::UpdateGameStatePacket statePacket(m_Server->GetGame().GetGameState());
SendPacket(&statePacket); SendPacket(&statePacket);
protocol::ConnexionInfoPacket conPacket(m_ID); protocol::ConnexionInfoPacket conPacket(m_ID);
SendPacket(&conPacket); SendPacket(&conPacket);
if (m_Server->GetGame().GetGameState() == game::GameState::Game) { SAFE_CHECK(m_Server->GetGame().GetGameState() != game::GameState::Game);
protocol::WorldBeginDataPacket headerDataPacket(m_Server->GetGame().GetWorld());
protocol::WorldBeginDataPacket dataPacket(m_Server->GetGame().GetWorld()); protocol::WorldBeginDataPacket headerDataPacket(m_Server->GetGame().GetWorld());
SendPacket(&headerDataPacket); protocol::WorldBeginDataPacket dataPacket(m_Server->GetGame().GetWorld());
SendPacket(&dataPacket); SendPacket(&headerDataPacket);
} SendPacket(&dataPacket);
} }
void ServerConnexion::HandlePacket(const protocol::PlaceTowerPacket* packet) { void ServerConnexion::HandlePacket(const protocol::PlaceTowerPacket* packet) {
game::TowerType towerType = packet->GetTowerType(); game::TowerType towerType = packet->GetTowerType();
const game::TowerInfo& towerInfo = game::GetTowerInfo(towerType); const game::TowerInfo& towerInfo = game::GetTowerInfo(towerType);
server::ServerWorld* world = m_Server->GetGame().GetServerWorld(); server::ServerWorld* world = m_Server->GetGame().GetServerWorld();
if (!world->CanPlaceLittleTower({ packet->GetTowerX(), packet->GetTowerY() }, m_ID)) Vec2f towerPos = { static_cast<float>(packet->GetTowerX()), static_cast<float>(packet->GetTowerY()) };
return;
if (towerInfo.IsBigTower()) SAFE_CHECK(!world->CanPlaceLittleTower(towerPos, m_ID));
if (!world->CanPlaceBigTower({ packet->GetTowerX(), packet->GetTowerY() }, m_ID))
return;
game::TowerPtr tower = world->PlaceTowerAt(towerType, packet->GetTowerX(), packet->GetTowerY(), m_ID); if (towerInfo.IsBigTower())
SAFE_CHECK(!world->CanPlaceBigTower(towerPos, m_ID));
world->GetWorldNotifier().NotifyListeners(&game::WorldListener::OnTowerAdd, tower); game::TowerPtr tower = world->PlaceTowerAt(towerType, packet->GetTowerX(), packet->GetTowerY(), m_ID);
protocol::WorldAddTowerPacket addTowerPacket(tower->GetID(), packet->GetTowerX(), packet->GetTowerY(), packet->GetTowerType(), m_ID); world->GetWorldNotifier().NotifyListeners(&game::WorldListener::OnTowerAdd, tower);
m_Server->BroadcastPacket(&addTowerPacket);
protocol::WorldAddTowerPacket addTowerPacket(tower->GetID(), packet->GetTowerX(), packet->GetTowerY(), packet->GetTowerType(), m_ID);
m_Server->BroadcastPacket(&addTowerPacket);
} }
void ServerConnexion::HandlePacket(const protocol::SendMobsPacket* packet) { void ServerConnexion::HandlePacket(const protocol::SendMobsPacket* packet) {
const std::vector<protocol::MobSend>& mobSent = packet->GetMobSends(); const std::vector<protocol::MobSend>& mobSent = packet->GetMobSends();
//TODO: verify the packet //TODO: verify the packet
for (protocol::MobSend mobSend : mobSent) { for (protocol::MobSend mobSend : mobSent) {
m_Server->GetGame().GetServerWorld()->SpawnMobs(mobSend.mobType, mobSend.mobLevel, m_ID, mobSend.mobCount); m_Server->GetGame().GetServerWorld()->SpawnMobs(mobSend.mobType, mobSend.mobLevel, m_ID, mobSend.mobCount);
} }
} }
void ServerConnexion::HandlePacket(const protocol::UpgradeTowerPacket* packet) { void ServerConnexion::HandlePacket(const protocol::UpgradeTowerPacket* packet) {
//TODO: verify the packet //TODO: verify the packet
m_Server->BroadcastPacket(packet); m_Server->BroadcastPacket(packet);
} }
void ServerConnexion::HandlePacket(const protocol::RemoveTowerPacket* packet) { void ServerConnexion::HandlePacket(const protocol::RemoveTowerPacket* packet) {
//TODO: verify the packet //TODO: verify the packet
m_Server->BroadcastPacket(packet); m_Server->BroadcastPacket(packet);
} }
ServerConnexion::~ServerConnexion() { ServerConnexion::~ServerConnexion() {
if (GetDispatcher() != nullptr) if (GetDispatcher() != nullptr)
GetDispatcher()->UnregisterHandler(this); GetDispatcher()->UnregisterHandler(this);
} }
} // namespace server } // namespace server

View File

@@ -8,113 +8,113 @@ ServerGame::ServerGame(server::Server* server) : game::Game(&m_ServerWorld), m_S
m_GoldMineTimer{ 1000, std::bind(&ServerGame::UpdateGoldMines, this) }, m_GoldMineTimer{ 1000, std::bind(&ServerGame::UpdateGoldMines, this) },
m_MobStatesTimer{ 5000, std::bind(&ServerGame::UpdateMobStates, this) }, m_MobStatesTimer{ 5000, std::bind(&ServerGame::UpdateMobStates, this) },
m_EndGameCooldown{ 1000 * 10 } { m_EndGameCooldown{ 1000 * 10 } {
BindListener(this); BindListener(this);
} }
void ServerGame::Tick(std::uint64_t delta) { void ServerGame::Tick(std::uint64_t delta) {
if (m_GameState == game::GameState::Game) { if (m_GameState == game::GameState::Game) {
Game::Tick(delta); Game::Tick(delta);
m_MobStatesTimer.Update(delta); m_MobStatesTimer.Update(delta);
UpdatePlayerStats(); UpdatePlayerStats();
} else if (m_GameState == game::GameState::EndGame) { } else if (m_GameState == game::GameState::EndGame) {
if (m_EndGameCooldown.Update(delta)) { if (m_EndGameCooldown.Update(delta)) {
NotifyListeners(&game::GameListener::OnGameClose); NotifyListeners(&game::GameListener::OnGameClose);
} }
} }
} }
void ServerGame::StartGame() { void ServerGame::StartGame() {
BalanceTeams(); BalanceTeams();
protocol::WorldBeginDataPacket headerMapData(m_World); protocol::WorldBeginDataPacket headerMapData(m_World);
m_Server->BroadcastPacket(&headerMapData); m_Server->BroadcastPacket(&headerMapData);
protocol::WorldDataPacket mapData(m_World); protocol::WorldDataPacket mapData(m_World);
m_Server->BroadcastPacket(&mapData); m_Server->BroadcastPacket(&mapData);
InitPlayerStats(); InitPlayerStats();
m_GameState = game::GameState::Game; m_GameState = game::GameState::Game;
} }
void ServerGame::InitPlayerStats() { void ServerGame::InitPlayerStats() {
static const unsigned int START_GOLD = 100; static const unsigned int START_GOLD = 100;
static const unsigned int START_EXP = 0; static const unsigned int START_EXP = 0;
for (auto& [id, player] : m_Server->GetPlayers()) { for (auto& [id, player] : m_Server->GetPlayers()) {
player.SetGold(START_GOLD); player.SetGold(START_GOLD);
player.SetExp(START_EXP); player.SetExp(START_EXP);
player.getUpgrades().SetGoldPerSecond(5); player.getUpgrades().SetGoldPerSecond(5);
} }
} }
void ServerGame::UpdatePlayerStats() { void ServerGame::UpdatePlayerStats() {
m_GoldMineTimer.Update(); m_GoldMineTimer.Update();
} }
void ServerGame::UpdateGoldMines() { void ServerGame::UpdateGoldMines() {
for (auto& [id, player] : m_Server->GetPlayers()) { for (auto& [id, player] : m_Server->GetPlayers()) {
player.AddGold(player.getUpgrades().GetGoldPerSecond()); player.AddGold(player.getUpgrades().GetGoldPerSecond());
// Update player money and exp every second // Update player money and exp every second
protocol::UpdateMoneyPacket moneyPacket(player.GetGold()); protocol::UpdateMoneyPacket moneyPacket(player.GetGold());
m_Server->GetConnexions()[player.GetID()].SendPacket(&moneyPacket); m_Server->GetConnexions()[player.GetID()].SendPacket(&moneyPacket);
protocol::UpdateExpPacket expPacket(player.GetExp()); protocol::UpdateExpPacket expPacket(player.GetExp());
m_Server->GetConnexions()[player.GetID()].SendPacket(&expPacket); m_Server->GetConnexions()[player.GetID()].SendPacket(&expPacket);
} }
} }
void ServerGame::UpdateMobStates() { void ServerGame::UpdateMobStates() {
protocol::UpdateMobStatesPacket packet; protocol::UpdateMobStatesPacket packet;
for (auto mob : m_World->GetMobList()) { for (auto mob : m_World->GetMobList()) {
packet.addMobState({ mob->GetMobID(), mob->GetCenter(), mob->GetHealth(), mob->GetDirection() }); packet.addMobState({ mob->GetMobID(), mob->GetCenter(), mob->GetHealth(), mob->GetDirection() });
} }
m_Server->BroadcastPacket(&packet); m_Server->BroadcastPacket(&packet);
} }
void ServerGame::BalanceTeams() { void ServerGame::BalanceTeams() {
for (auto& playerInfo : Game::m_Players) { for (auto& playerInfo : Game::m_Players) {
game::Player& player = playerInfo.second; game::Player& player = playerInfo.second;
if (player.GetTeamColor() == game::TeamColor::None) { if (player.GetTeamColor() == game::TeamColor::None) {
game::Team& redTeam = GetRedTeam(); game::Team& redTeam = GetRedTeam();
game::Team& blueTeam = GetBlueTeam(); game::Team& blueTeam = GetBlueTeam();
if (blueTeam.GetPlayerCount() > redTeam.GetPlayerCount()) { if (blueTeam.GetPlayerCount() > redTeam.GetPlayerCount()) {
player.SetTeamColor(game::TeamColor::Red); player.SetTeamColor(game::TeamColor::Red);
redTeam.AddPlayer(&player); redTeam.AddPlayer(&player);
} else { } else {
player.SetTeamColor(game::TeamColor::Blue); player.SetTeamColor(game::TeamColor::Blue);
blueTeam.AddPlayer(&player); blueTeam.AddPlayer(&player);
} }
protocol::UpdatePlayerTeamPacket packet(player.GetID(), player.GetTeamColor()); protocol::UpdatePlayerTeamPacket packet(player.GetID(), player.GetTeamColor());
m_Server->BroadcastPacket(&packet); m_Server->BroadcastPacket(&packet);
} }
} }
} }
void ServerGame::OnGameStateUpdate(game::GameState newState) { void ServerGame::OnGameStateUpdate(game::GameState newState) {
SetGameState(newState); SetGameState(newState);
protocol::UpdateGameStatePacket packet(newState); protocol::UpdateGameStatePacket packet(newState);
m_Server->BroadcastPacket(&packet); m_Server->BroadcastPacket(&packet);
} }
void ServerGame::OnGameBegin() { void ServerGame::OnGameBegin() {
NotifyListeners(&game::GameListener::OnGameStateUpdate, game::GameState::Game); NotifyListeners(&game::GameListener::OnGameStateUpdate, game::GameState::Game);
StartGame(); StartGame();
} }
void ServerGame::OnGameEnd() { void ServerGame::OnGameEnd() {
NotifyListeners(&game::GameListener::OnGameStateUpdate, game::GameState::EndGame); NotifyListeners(&game::GameListener::OnGameStateUpdate, game::GameState::EndGame);
m_EndGameCooldown.ApplyCooldown(); m_EndGameCooldown.ApplyCooldown();
} }
void ServerGame::OnGameClose() { void ServerGame::OnGameClose() {
NotifyListeners(&game::GameListener::OnGameStateUpdate, game::GameState::Closed); NotifyListeners(&game::GameListener::OnGameStateUpdate, game::GameState::Closed);
// Disconnect clients // Disconnect clients
protocol::DisconnectPacket packet("Game finished"); protocol::DisconnectPacket packet("Game finished");
m_Server->BroadcastPacket(&packet); m_Server->BroadcastPacket(&packet);
// Closing server // Closing server
m_Server->Close(); m_Server->Close();
} }
} // namespace game } // namespace game

View File

@@ -12,66 +12,66 @@ ServerWorld::ServerWorld(Server* server, ServerGame* game) : game::World(game),
} }
void ServerWorld::SpawnMobs(game::MobType type, std::uint8_t level, game::PlayerID sender, std::uint8_t count) { void ServerWorld::SpawnMobs(game::MobType type, std::uint8_t level, game::PlayerID sender, std::uint8_t count) {
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
game::TeamColor senderTeam = m_Game->GetPlayers().at(sender).GetTeamColor(); game::TeamColor senderTeam = m_Game->GetPlayers().at(sender).GetTeamColor();
game::Spawn* enemyMobSpawn; game::Spawn* enemyMobSpawn;
if (senderTeam == game::TeamColor::Red) { if (senderTeam == game::TeamColor::Red) {
enemyMobSpawn = &GetTeam(game::TeamColor::Blue).GetSpawn(); enemyMobSpawn = &GetTeam(game::TeamColor::Blue).GetSpawn();
} else { } else {
enemyMobSpawn = &GetTeam(game::TeamColor::Red).GetSpawn(); enemyMobSpawn = &GetTeam(game::TeamColor::Red).GetSpawn();
} }
float spawnWidth = enemyMobSpawn->GetWidth(); float spawnWidth = enemyMobSpawn->GetWidth();
float spawnHeight = enemyMobSpawn->GetHeight(); float spawnHeight = enemyMobSpawn->GetHeight();
float spawnCenterX = enemyMobSpawn->GetCenterX(); float spawnCenterX = enemyMobSpawn->GetCenterX();
float spawnCenterY = enemyMobSpawn->GetCenterY(); float spawnCenterY = enemyMobSpawn->GetCenterY();
auto mobStats = GetMobStats(type, level); auto mobStats = GetMobStats(type, level);
auto mobSize = mobStats->GetSize(); auto mobSize = mobStats->GetSize();
float minSpawnX = spawnCenterX - spawnWidth / 2.0f + mobSize.x / 2.0f; float minSpawnX = spawnCenterX - spawnWidth / 2.0f + mobSize.x / 2.0f;
float maxSpawnX = spawnCenterX + spawnWidth / 2.0f - mobSize.x / 2.0f; float maxSpawnX = spawnCenterX + spawnWidth / 2.0f - mobSize.x / 2.0f;
float minSpawnY = spawnCenterY - spawnHeight / 2.0f + mobSize.y / 2.0f; float minSpawnY = spawnCenterY - spawnHeight / 2.0f + mobSize.y / 2.0f;
float maxSpawnY = spawnCenterY + spawnHeight / 2.0f - mobSize.y / 2.0f; float maxSpawnY = spawnCenterY + spawnHeight / 2.0f - mobSize.y / 2.0f;
float mobX = utils::GetRandomReal<float>(minSpawnX + MobSpawnBorder, maxSpawnX - MobSpawnBorder); float mobX = utils::GetRandomReal<float>(minSpawnX + MobSpawnBorder, maxSpawnX - MobSpawnBorder);
float mobY = utils::GetRandomReal<float>(minSpawnY + MobSpawnBorder, maxSpawnY - MobSpawnBorder); float mobY = utils::GetRandomReal<float>(minSpawnY + MobSpawnBorder, maxSpawnY - MobSpawnBorder);
SpawnMobAt(m_CurrentMobID, type, level, sender, mobX, mobY, enemyMobSpawn->GetDirection()); SpawnMobAt(m_CurrentMobID, type, level, sender, mobX, mobY, enemyMobSpawn->GetDirection());
protocol::SpawnMobPacket packet(m_CurrentMobID, type, level, sender, mobX, mobY, enemyMobSpawn->GetDirection()); protocol::SpawnMobPacket packet(m_CurrentMobID, type, level, sender, mobX, mobY, enemyMobSpawn->GetDirection());
m_Server->BroadcastPacket(&packet); m_Server->BroadcastPacket(&packet);
m_CurrentMobID++; m_CurrentMobID++;
} }
} }
game::TowerPtr ServerWorld::PlaceTowerAt(game::TowerType type, std::int32_t x, std::int32_t y, game::PlayerID builder) { game::TowerPtr ServerWorld::PlaceTowerAt(game::TowerType type, std::int32_t x, std::int32_t y, game::PlayerID builder) {
game::TowerPtr tower = World::PlaceTowerAt(m_CurrentTowerID, type, x, y, builder); game::TowerPtr tower = World::PlaceTowerAt(m_CurrentTowerID, type, x, y, builder);
m_CurrentTowerID++; m_CurrentTowerID++;
return tower; return tower;
} }
void ServerWorld::OnMobDie(game::Mob* mob) { void ServerWorld::OnMobDie(game::Mob* mob) {
if (mob->OnDeath(this)) { // check if the mob is actually dead (slimes ...) if (mob->OnDeath(this)) { // check if the mob is actually dead (slimes ...)
//reward players //reward players
game::Player* sender = m_Game->GetPlayerById(mob->GetSender()); game::Player* sender = m_Game->GetPlayerById(mob->GetSender());
sender->AddExp(mob->GetStats()->GetExpReward()); sender->AddExp(mob->GetStats()->GetExpReward());
game::Player* killer = m_Game->GetPlayerById(mob->GetLastDamageTower()->GetBuilder()); game::Player* killer = m_Game->GetPlayerById(mob->GetLastDamageTower()->GetBuilder());
killer->AddGold(mob->GetStats()->GetMoneyCost()); killer->AddGold(mob->GetStats()->GetMoneyCost());
} }
} }
void ServerWorld::OnMobCastleDamage(game::Mob* damager, game::TeamCastle* enemyCastle, float damage) { void ServerWorld::OnMobCastleDamage(game::Mob* damager, game::TeamCastle* enemyCastle, float damage) {
// calling base class event // calling base class event
World::OnMobCastleDamage(damager, enemyCastle, damage); World::OnMobCastleDamage(damager, enemyCastle, damage);
protocol::UpdateCastleLifePacket packet(enemyCastle->GetLife(), enemyCastle->GetTeam()->GetColor()); protocol::UpdateCastleLifePacket packet(enemyCastle->GetLife(), enemyCastle->GetTeam()->GetColor());
m_Server->BroadcastPacket(&packet); m_Server->BroadcastPacket(&packet);
} }
} // namespace server } // namespace server

View File

@@ -0,0 +1,25 @@
#include "game/Towers.h"
#include "game/World.h"
namespace td {
namespace game {
void ArcherTower::Tick(std::uint64_t delta, World* world) {
if (m_Timer.Update(delta)) {
std::uint8_t arrowsShot = 0;
bool explosiveArrows = GetLevel().GetPath() == TowerPath::Bottom;
std::uint8_t arrows = explosiveArrows ? 2 : GetLevel().GetLevel();
for (MobPtr mob : world->GetMobList()) {
if (IsMobInRange(mob)) {
world->GetWorldNotifier().NotifyListeners(&WorldListener::OnArcherTowerShot, mob, this);
m_Timer.ApplyCooldown();
arrowsShot++;
if (arrowsShot >= arrows)
break;
}
}
}
}
} // namespace game
} // namespace td

View File

@@ -0,0 +1,12 @@
#include "game/Towers.h"
#include "game/World.h"
namespace td {
namespace game {
void ArtilleryTower::Tick(std::uint64_t delta, World* world) {
}
} // namespace game
} // namespace td

View File

@@ -0,0 +1,22 @@
#include "game/Towers.h"
#include "game/World.h"
namespace td {
namespace game {
void IceTower::Tick(std::uint64_t delta, World* world) {
if (m_Timer.Update(delta)) {
float damage = GetStats()->GetDamage();
for (MobPtr mob : world->GetMobList()) {
if (IsMobInRange(mob)) {
mob->AddEffect(EffectType::Slowness, 1, this); // slowness for 1s every second
if (damage > 0)
world->GetMobNotifier().NotifyListeners(&MobListener::OnMobDamage, mob.get(), damage, this);
m_Timer.ApplyCooldown();
}
}
}
}
} // namespace game
} // namespace td

View File

@@ -0,0 +1,12 @@
#include "game/Towers.h"
#include "game/World.h"
namespace td {
namespace game {
void LeachTower::Tick(std::uint64_t delta, World* world) {
}
} // namespace game
} // namespace td

View File

@@ -0,0 +1,19 @@
#include "game/Towers.h"
#include "game/World.h"
namespace td {
namespace game {
void MageTower::Tick(std::uint64_t delta, World* world) {
if (m_Timer.Update(delta)) {
for (MobPtr mob : world->GetMobList()) {
if (IsMobInRange(mob)) {
mob->AddEffect(EffectType::Fire, GetLevel().GetLevel() * 3, this);
m_Timer.ApplyCooldown();
}
}
}
}
} // namespace game
} // namespace td

View File

@@ -0,0 +1,12 @@
#include "game/Towers.h"
#include "game/World.h"
namespace td {
namespace game {
void NecromancerTower::Tick(std::uint64_t delta, World* world) {
}
} // namespace game
} // namespace td

View File

@@ -0,0 +1,45 @@
#include "game/Towers.h"
#include "game/World.h"
namespace td {
namespace game {
void PoisonTower::Tick(std::uint64_t delta, World* world) {
if (m_Timer.Update(delta)) {
for (MobPtr mob : world->GetMobList()) {
if (IsMobInRange(mob)) {
if (GetLevel().GetPath() == TowerPath::Bottom) {
world->GetMobNotifier().NotifyListeners(&MobListener::OnMobDamage, mob.get(), GetStats()->GetDamage(), this);
} else {
float durationSec;
switch (GetLevel().GetLevel()) {
case 1:
durationSec = 5;
break;
case 2:
durationSec = 15;
break;
case 3:
durationSec = 30;
break;
case 4:
durationSec = 1e10; // about 3 million hours. It should be enough
break;
default:
durationSec = 0; // how did we get there ?
break;
}
mob->AddEffect(EffectType::Poison, durationSec, this);
}
m_Timer.ApplyCooldown();
}
}
}
}
} // namespace game
} // namespace td

View File

@@ -0,0 +1,12 @@
#include "game/Towers.h"
#include "game/World.h"
namespace td {
namespace game {
void QuakeTower::Tick(std::uint64_t delta, World* world) {
}
} // namespace game
} // namespace td

View File

@@ -0,0 +1,12 @@
#include "game/Towers.h"
#include "game/World.h"
namespace td {
namespace game {
void SorcererTower::Tick(std::uint64_t delta, World* world) {
}
} // namespace game
} // namespace td

View File

@@ -0,0 +1,12 @@
#include "game/Towers.h"
#include "game/World.h"
namespace td {
namespace game {
void TurretTower::Tick(std::uint64_t delta, World* world) {
}
} // namespace game
} // namespace td

View File

@@ -0,0 +1,12 @@
#include "game/Towers.h"
#include "game/World.h"
namespace td {
namespace game {
void ZeusTower::Tick(std::uint64_t delta, World* world) {
}
} // namespace game
} // namespace td

View File

@@ -9,79 +9,79 @@ namespace td {
namespace utils { namespace utils {
std::uint64_t Inflate(const std::string& source, std::string& dest) { std::uint64_t Inflate(const std::string& source, std::string& dest) {
std::size_t size; uLongf size = dest.size();
uncompress(reinterpret_cast<Bytef*>(dest.data()), reinterpret_cast<uLongf*>(&size), reinterpret_cast<const Bytef*>(source.c_str()), source.length()); uncompress(reinterpret_cast<Bytef*>(dest.data()), reinterpret_cast<uLongf*>(&size), reinterpret_cast<const Bytef*>(source.c_str()), source.length());
return size; return size;
} }
std::uint64_t Deflate(const std::string& source, std::string& dest) { std::uint64_t Deflate(const std::string& source, std::string& dest) {
std::size_t size; uLongf size = source.length();
dest.resize(source.size()); // Resize for the compressed data to fit into dest.resize(source.size()); // Resize for the compressed data to fit into
compress(reinterpret_cast<Bytef*>(dest.data()), reinterpret_cast<uLongf*>(&size), reinterpret_cast<const Bytef*>(source.c_str()), source.length()); compress(reinterpret_cast<Bytef*>(dest.data()), reinterpret_cast<uLongf*>(&size), reinterpret_cast<const Bytef*>(source.c_str()), source.length());
dest.resize(size); // Resize to cut useless data dest.resize(size); // Resize to cut useless data
return size; return size;
} }
DataBuffer Compress(const DataBuffer& buffer) { DataBuffer Compress(const DataBuffer& buffer) {
std::string compressedData; std::string compressedData;
DataBuffer packet; DataBuffer packet;
if (buffer.GetSize() < COMPRESSION_THRESHOLD) { if (buffer.GetSize() < COMPRESSION_THRESHOLD) {
// Don't compress since it's a small packet // Don't compress since it's a small packet
std::uint64_t dataLength = 0; std::uint64_t dataLength = 0;
std::uint64_t packetLength = buffer.GetSize() + sizeof(dataLength); std::uint64_t packetLength = buffer.GetSize() + sizeof(dataLength);
packet << packetLength; packet << packetLength;
packet << dataLength; packet << dataLength;
packet << buffer; packet << buffer;
return packet; return packet;
} }
Deflate(buffer.ToString(), compressedData); Deflate(buffer.ToString(), compressedData);
std::uint64_t dataLength = buffer.GetSize(); std::uint64_t dataLength = buffer.GetSize();
std::uint64_t packetLength = compressedData.length() + sizeof(dataLength); std::uint64_t packetLength = compressedData.length() + sizeof(dataLength);
packet << packetLength; packet << packetLength;
packet << dataLength; packet << dataLength;
packet << compressedData; packet << compressedData;
return packet; return packet;
} }
DataBuffer Decompress(DataBuffer& buffer, std::uint64_t packetLength) { DataBuffer Decompress(DataBuffer& buffer, std::uint64_t packetLength) {
std::uint64_t uncompressedLength; std::uint64_t uncompressedLength;
buffer >> uncompressedLength; buffer >> uncompressedLength;
std::uint64_t compressedLength = packetLength - sizeof(uncompressedLength); std::uint64_t compressedLength = packetLength - sizeof(uncompressedLength);
if (uncompressedLength == 0) { if (uncompressedLength == 0) {
// Uncompressed // Uncompressed
DataBuffer ret; DataBuffer ret;
buffer.ReadSome(ret, compressedLength); buffer.ReadSome(ret, compressedLength);
return ret; return ret;
} }
assert(buffer.GetReadOffset() + compressedLength <= buffer.GetSize()); assert(buffer.GetReadOffset() + compressedLength <= buffer.GetSize());
std::string deflatedData; std::string deflatedData;
buffer.ReadSome(deflatedData, compressedLength); buffer.ReadSome(deflatedData, compressedLength);
std::string inflated; std::string inflated;
inflated.resize(uncompressedLength); inflated.resize(uncompressedLength);
Inflate(deflatedData, inflated); Inflate(deflatedData, inflated);
assert(inflated.length() == uncompressedLength); assert(inflated.length() == uncompressedLength);
return DataBuffer(inflated); return DataBuffer(inflated);
} }
DataBuffer Decompress(DataBuffer& buffer) { DataBuffer Decompress(DataBuffer& buffer) {
std::uint64_t packetLength; std::uint64_t packetLength;
buffer >> packetLength; buffer >> packetLength;
return Decompress(buffer, packetLength); return Decompress(buffer, packetLength);
} }
} // namespace utils } // namespace utils

View File

@@ -7,88 +7,88 @@
namespace td { namespace td {
DataBuffer::DataBuffer() : m_ReadOffset(0) { } DataBuffer::DataBuffer() : m_ReadOffset(0) {}
DataBuffer::DataBuffer(const DataBuffer& other) : m_Buffer(other.m_Buffer), m_ReadOffset(other.m_ReadOffset) { } DataBuffer::DataBuffer(const DataBuffer& other) : m_Buffer(other.m_Buffer), m_ReadOffset(other.m_ReadOffset) {}
DataBuffer::DataBuffer(DataBuffer&& other) : m_Buffer(std::move(other.m_Buffer)), m_ReadOffset(std::move(other.m_ReadOffset)) { } DataBuffer::DataBuffer(DataBuffer&& other) : m_Buffer(std::move(other.m_Buffer)), m_ReadOffset(std::move(other.m_ReadOffset)) {}
DataBuffer::DataBuffer(const std::string& str) : m_Buffer(str.begin(), str.end()), m_ReadOffset(0) { } DataBuffer::DataBuffer(const std::string& str) : m_Buffer(str.begin(), str.end()), m_ReadOffset(0) {}
DataBuffer::DataBuffer(const DataBuffer& other, Data::difference_type offset) : m_ReadOffset(0) { DataBuffer::DataBuffer(const DataBuffer& other, Data::difference_type offset) : m_ReadOffset(0) {
m_Buffer.reserve(other.GetSize() - static_cast<std::size_t>(offset)); m_Buffer.reserve(other.GetSize() - static_cast<std::size_t>(offset));
std::copy(other.m_Buffer.begin() + offset, other.m_Buffer.end(), std::back_inserter(m_Buffer)); std::copy(other.m_Buffer.begin() + offset, other.m_Buffer.end(), std::back_inserter(m_Buffer));
} }
DataBuffer& DataBuffer::operator=(const DataBuffer& other) { DataBuffer& DataBuffer::operator=(const DataBuffer& other) {
m_Buffer = other.m_Buffer; m_Buffer = other.m_Buffer;
m_ReadOffset = other.m_ReadOffset; m_ReadOffset = other.m_ReadOffset;
return *this; return *this;
} }
DataBuffer& DataBuffer::operator=(DataBuffer&& other) { DataBuffer& DataBuffer::operator=(DataBuffer&& other) {
m_Buffer = std::move(other.m_Buffer); m_Buffer = std::move(other.m_Buffer);
m_ReadOffset = std::move(other.m_ReadOffset); m_ReadOffset = std::move(other.m_ReadOffset);
return *this; return *this;
} }
void DataBuffer::SetReadOffset(std::size_t pos) { void DataBuffer::SetReadOffset(std::size_t pos) {
assert(pos <= GetSize()); assert(pos <= GetSize());
m_ReadOffset = pos; m_ReadOffset = pos;
} }
std::string DataBuffer::ToString() const { std::string DataBuffer::ToString() const {
return std::string(m_Buffer.begin(), m_Buffer.end()); return std::string(m_Buffer.begin(), m_Buffer.end());
} }
std::size_t DataBuffer::GetSize() const { return m_Buffer.size(); } std::size_t DataBuffer::GetSize() const { return m_Buffer.size(); }
bool DataBuffer::IsEmpty() const { return m_Buffer.empty(); } bool DataBuffer::IsEmpty() const { return m_Buffer.empty(); }
std::size_t DataBuffer::GetRemaining() const { std::size_t DataBuffer::GetRemaining() const {
return m_Buffer.size() - m_ReadOffset; return m_Buffer.size() - m_ReadOffset;
} }
DataBuffer::iterator DataBuffer::begin() { DataBuffer::iterator DataBuffer::begin() {
return m_Buffer.begin(); return m_Buffer.begin();
} }
DataBuffer::iterator DataBuffer::end() { DataBuffer::iterator DataBuffer::end() {
return m_Buffer.end(); return m_Buffer.end();
} }
DataBuffer::const_iterator DataBuffer::begin() const { DataBuffer::const_iterator DataBuffer::begin() const {
return m_Buffer.begin(); return m_Buffer.begin();
} }
DataBuffer::const_iterator DataBuffer::end() const { DataBuffer::const_iterator DataBuffer::end() const {
return m_Buffer.end(); return m_Buffer.end();
} }
std::ostream& operator<<(std::ostream& os, const DataBuffer& buffer) { std::ostream& operator<<(std::ostream& os, const DataBuffer& buffer) {
for (unsigned char u : buffer) for (unsigned char u : buffer)
os << std::hex << std::setfill('0') << std::setw(2) << static_cast<int>(u) << " "; os << std::hex << std::setfill('0') << std::setw(2) << static_cast<int>(u) << " ";
os << std::dec; os << std::dec;
return os; return os;
} }
bool DataBuffer::ReadFile(const std::string& fileName) { bool DataBuffer::ReadFile(const std::string& fileName) {
try { try {
std::ifstream file(fileName, std::istream::binary); std::ifstream file(fileName, std::istream::binary);
std::ostringstream ss; std::ostringstream ss;
ss << file.rdbuf(); ss << file.rdbuf();
const std::string& s = ss.str(); const std::string& s = ss.str();
m_Buffer = DataBuffer::Data(s.begin(), s.end()); m_Buffer = DataBuffer::Data(s.begin(), s.end());
m_ReadOffset = 0; m_ReadOffset = 0;
} catch (std::exception& e) { } catch (std::exception& e) {
std::cerr << "Failed to read file \"" << fileName << "\" reason : " << e.what() << std::endl; std::cerr << "Failed to read file \"" << fileName << "\" reason : " << e.what() << std::endl;
return false; return false;
} }
return m_Buffer.size() > 0; return m_Buffer.size() > 0;
} }
bool DataBuffer::WriteFile(const std::string& fileName) { bool DataBuffer::WriteFile(const std::string& fileName) {
try { try {
std::ofstream file(fileName, std::ostream::binary); std::ofstream file(fileName, std::ostream::binary);
file.write(reinterpret_cast<const char*>(m_Buffer.data()), static_cast<std::streamsize>(m_Buffer.size())); file.write(reinterpret_cast<const char*>(m_Buffer.data()), static_cast<std::streamsize>(m_Buffer.size()));
file.flush(); file.flush();
} catch (std::exception& e) { } catch (std::exception& e) {
std::cerr << "Failed to write file \"" << fileName << "\" reason : " << e.what() << std::endl; std::cerr << "Failed to write file \"" << fileName << "\" reason : " << e.what() << std::endl;
return false; return false;
} }
return true; return true;
} }
} // td } // td

View File

@@ -10,195 +10,195 @@ namespace utils {
/* Sine functions */ /* Sine functions */
float EaseInSine(float x) { float EaseInSine(float x) {
return 1.0f - std::cos((x * PI) / 2.0f); return 1.0f - std::cos((x * PI) / 2.0f);
} }
float EaseOutSine(float x) { float EaseOutSine(float x) {
return std::sin((x * PI) / 2.0f); return std::sin((x * PI) / 2.0f);
} }
float EaseInOutSine(float x) { float EaseInOutSine(float x) {
return -(std::cos(PI * x) - 1.0f) / 2.0f; return -(std::cos(PI * x) - 1.0f) / 2.0f;
} }
/* Cubic functions */ /* Cubic functions */
float EaseInCubic(float x) { float EaseInCubic(float x) {
return x * EaseInQuad(x); return x * EaseInQuad(x);
} }
float EaseOutCubic(float x) { float EaseOutCubic(float x) {
return 1 - std::pow(1 - x, 3); return 1 - std::pow(1 - x, 3);
} }
float EaseInOutCubic(float x) { float EaseInOutCubic(float x) {
return x < 0.5 ? 4 * EaseInCubic(x) : 1 - std::pow(-2 * x + 2, 3) / 2.0f; return x < 0.5 ? 4 * EaseInCubic(x) : 1 - std::pow(-2 * x + 2, 3) / 2.0f;
} }
/* Quint functions */ /* Quint functions */
float EaseInQuint(float x) { float EaseInQuint(float x) {
return x * EaseInQuart(x); return x * EaseInQuart(x);
} }
float EaseOutQuint(float x) { float EaseOutQuint(float x) {
return 1 - std::pow(1 - x, 5); return 1 - std::pow(1 - x, 5);
} }
float EaseInOutQuint(float x) { float EaseInOutQuint(float x) {
return x < 0.5 ? 16 * EaseInQuint(x) : 1 - std::pow(-2 * x + 2, 5) / 2.0f; return x < 0.5 ? 16 * EaseInQuint(x) : 1 - std::pow(-2 * x + 2, 5) / 2.0f;
} }
/* Circ functions */ /* Circ functions */
float EaseInCirc(float x) { float EaseInCirc(float x) {
return 1 - std::sqrt(1 - std::pow(x, 2)); return 1 - std::sqrt(1 - std::pow(x, 2));
} }
float EaseOutCirc(float x) { float EaseOutCirc(float x) {
return std::sqrt(1 - std::pow(x - 1, 2)); return std::sqrt(1 - std::pow(x - 1, 2));
} }
float EaseInOutCirc(float x) { float EaseInOutCirc(float x) {
return x < 0.5 return x < 0.5
? (1 - std::sqrt(1 - std::pow(2 * x, 2))) / 2.0f ? (1 - std::sqrt(1 - std::pow(2 * x, 2))) / 2.0f
: (std::sqrt(1 - std::pow(-2 * x + 2, 2)) + 1) / 2.0f; : (std::sqrt(1 - std::pow(-2 * x + 2, 2)) + 1) / 2.0f;
} }
/* Elastic functions */ /* Elastic functions */
float EaseInElastic(float x) { float EaseInElastic(float x) {
const float c4 = (2 * PI) / 3.0f; const float c4 = (2 * PI) / 3.0f;
return x == 0 return x == 0
? 0 ? 0
: x == 1 : x == 1
? 1 ? 1
: -std::pow(2, 10 * x - 10) * std::sin((x * 10 - 10.75) * c4); : -std::pow(2, 10 * x - 10) * std::sin((x * 10 - 10.75) * c4);
} }
float EaseOutElastic(float x) { float EaseOutElastic(float x) {
const float c4 = (2 * PI) / 3.0f; const float c4 = (2 * PI) / 3.0f;
return x == 0 return x == 0
? 0 ? 0
: x == 1 : x == 1
? 1 ? 1
: std::pow(2, -10 * x) * std::sin((x * 10 - 0.75) * c4) + 1; : std::pow(2, -10 * x) * std::sin((x * 10 - 0.75) * c4) + 1;
} }
float EaseInOutElastic(float x) { float EaseInOutElastic(float x) {
const float c5 = (2 * PI) / 4.5; const float c5 = (2 * PI) / 4.5;
return x == 0 return x == 0
? 0 ? 0
: x == 1 : x == 1
? 1 ? 1
: x < 0.5 : x < 0.5
? -(std::pow(2, 20 * x - 10) * std::sin((20 * x - 11.125) * c5)) / 2.0f ? -(std::pow(2, 20 * x - 10) * std::sin((20 * x - 11.125) * c5)) / 2.0f
: (std::pow(2, -20 * x + 10) * std::sin((20 * x - 11.125) * c5)) / 2.0f + 1; : (std::pow(2, -20 * x + 10) * std::sin((20 * x - 11.125) * c5)) / 2.0f + 1;
} }
/* Quad functions */ /* Quad functions */
float EaseInQuad(float x) { float EaseInQuad(float x) {
return x * x; return x * x;
} }
float EaseOutQuad(float x) { float EaseOutQuad(float x) {
return 1 - (1 - x) * (1 - x); return 1 - (1 - x) * (1 - x);
} }
float EaseInOutQuad(float x) { float EaseInOutQuad(float x) {
return x < 0.5 ? 2 * x * x : 1 - std::pow(-2 * x + 2, 2) / 2.0f; return x < 0.5 ? 2 * x * x : 1 - std::pow(-2 * x + 2, 2) / 2.0f;
} }
/* Quart functions */ /* Quart functions */
float EaseInQuart(float x) { float EaseInQuart(float x) {
return x * EaseInCubic(x); return x * EaseInCubic(x);
} }
float EaseOutQuart(float x) { float EaseOutQuart(float x) {
return 1 - std::pow(1 - x, 4); return 1 - std::pow(1 - x, 4);
} }
float EaseInOutQuart(float x) { float EaseInOutQuart(float x) {
return x < 0.5 ? 8 * EaseInQuart(x) : 1 - std::pow(-2 * x + 2, 4) / 2.0f; return x < 0.5 ? 8 * EaseInQuart(x) : 1 - std::pow(-2 * x + 2, 4) / 2.0f;
} }
/* Expo functions */ /* Expo functions */
float EaseInExpo(float x) { float EaseInExpo(float x) {
return x == 0 ? 0 : std::pow(2, 10 * x - 10); return x == 0 ? 0 : std::pow(2, 10 * x - 10);
} }
float EaseOutExpo(float x) { float EaseOutExpo(float x) {
return x == 1 ? 1 : 1 - std::pow(2, -10 * x); return x == 1 ? 1 : 1 - std::pow(2, -10 * x);
} }
float EaseInOutExpo(float x) { float EaseInOutExpo(float x) {
return x == 0 return x == 0
? 0 ? 0
: x == 1 : x == 1
? 1 ? 1
: x < 0.5 ? std::pow(2, 20 * x - 10) / 2.0f : x < 0.5 ? std::pow(2, 20 * x - 10) / 2.0f
: (2 - std::pow(2, -20 * x + 10)) / 2.0f; : (2 - std::pow(2, -20 * x + 10)) / 2.0f;
} }
/* Back functions */ /* Back functions */
float EaseInBack(float x) { float EaseInBack(float x) {
const float c1 = 1.70158; const float c1 = 1.70158;
const float c3 = c1 + 1; const float c3 = c1 + 1;
return c3 * EaseInCubic(x) - c1 * EaseInQuad(x); return c3 * EaseInCubic(x) - c1 * EaseInQuad(x);
} }
float EaseOutBack(float x) { float EaseOutBack(float x) {
const float c1 = 1.70158; const float c1 = 1.70158;
const float c3 = c1 + 1; const float c3 = c1 + 1;
return 1 + c3 * std::pow(x - 1, 3) + c1 * std::pow(x - 1, 2); return 1 + c3 * std::pow(x - 1, 3) + c1 * std::pow(x - 1, 2);
} }
float EaseInOutBack(float x) { float EaseInOutBack(float x) {
const float c1 = 1.70158; const float c1 = 1.70158;
const float c2 = c1 * 1.525; const float c2 = c1 * 1.525;
return x < 0.5 return x < 0.5
? (std::pow(2 * x, 2) * ((c2 + 1) * 2 * x - c2)) / 2.0f ? (std::pow(2 * x, 2) * ((c2 + 1) * 2 * x - c2)) / 2.0f
: (std::pow(2 * x - 2, 2) * ((c2 + 1) * (x * 2 - 2) + c2) + 2) / 2.0f; : (std::pow(2 * x - 2, 2) * ((c2 + 1) * (x * 2 - 2) + c2) + 2) / 2.0f;
} }
/* Bounce functions */ /* Bounce functions */
float EaseInBounce(float x) { float EaseInBounce(float x) {
return 1 - EaseOutBounce(1 - x); return 1 - EaseOutBounce(1 - x);
} }
float EaseOutBounce(float x) { float EaseOutBounce(float x) {
const float n1 = 7.5625; const float n1 = 7.5625;
const float d1 = 2.75; const float d1 = 2.75;
if (x < 1 / d1) { if (x < 1 / d1) {
return n1 * EaseInQuad(x); return n1 * EaseInQuad(x);
} else if (x < 2 / d1) { } else if (x < 2 / d1) {
x -= 1.5; x -= 1.5;
return n1 * (x / d1) * x + 0.75; return n1 * (x / d1) * x + 0.75;
} else if (x < 2.5 / d1) { } else if (x < 2.5 / d1) {
x -= 2.25; x -= 2.25;
return n1 * (x / d1) * x + 0.9375; return n1 * (x / d1) * x + 0.9375;
} else { } else {
x -= 2.625; x -= 2.625;
return n1 * (x / d1) * x + 0.984375; return n1 * (x / d1) * x + 0.984375;
} }
} }
float EaseInOutBounce(float x) { float EaseInOutBounce(float x) {
return x < 0.5 return x < 0.5
? (1 - EaseOutBounce(1 - 2 * x)) / 2.0f ? (1 - EaseOutBounce(1 - 2 * x)) / 2.0f
: (1 + EaseOutBounce(2 * x - 1)) / 2.0f; : (1 + EaseOutBounce(2 * x - 1)) / 2.0f;
} }
} // namespace utils } // namespace utils

90
src/misc/Maths.cpp Normal file
View File

@@ -0,0 +1,90 @@
#include "misc/Maths.h"
#include <cassert>
namespace td {
namespace maths {
Mat4f Perspective(float fovY, float aspectRatio, float zNear, float zFar) {
const float tanHalfFovy = std::tan(fovY / 2.0f);
Mat4f result{};
result.x0 = 1.0f / (aspectRatio * tanHalfFovy);
result.y1 = 1.0f / (tanHalfFovy);
result.z2 = -(zFar + zNear) / (zFar - zNear);
result.z3 = -1.0f;
result.w2 = -(2.0f * zFar * zNear) / (zFar - zNear);
return result;
}
Mat4f Look(const Vec3f& eye, const Vec3f& front, const Vec3f& up) {
const Vec3f f = Normalize(front);
const Vec3f s = Normalize(Cross(f, up));
const Vec3f u = Cross(s, f);
Mat4f result = Identity<float>();
result.x0 = s.x;
result.y0 = s.y;
result.z0 = s.z;
result.x1 = u.x;
result.y1 = u.y;
result.z1 = u.z;
result.x2 = -f.x;
result.y2 = -f.y;
result.z2 = -f.z;
result.w0 = -Dot(s, eye);
result.w1 = -Dot(u, eye);
result.w2 = Dot(f, eye);
return result;
}
Mat4f Inverse(const Mat4f& mat) {
float s0 = mat.at(0, 0) * mat.at(1, 1) - mat.at(1, 0) * mat.at(0, 1);
float s1 = mat.at(0, 0) * mat.at(1, 2) - mat.at(1, 0) * mat.at(0, 2);
float s2 = mat.at(0, 0) * mat.at(1, 3) - mat.at(1, 0) * mat.at(0, 3);
float s3 = mat.at(0, 1) * mat.at(1, 2) - mat.at(1, 1) * mat.at(0, 2);
float s4 = mat.at(0, 1) * mat.at(1, 3) - mat.at(1, 1) * mat.at(0, 3);
float s5 = mat.at(0, 2) * mat.at(1, 3) - mat.at(1, 2) * mat.at(0, 3);
float c5 = mat.at(2, 2) * mat.at(3, 3) - mat.at(3, 2) * mat.at(2, 3);
float c4 = mat.at(2, 1) * mat.at(3, 3) - mat.at(3, 1) * mat.at(2, 3);
float c3 = mat.at(2, 1) * mat.at(3, 2) - mat.at(3, 1) * mat.at(2, 2);
float c2 = mat.at(2, 0) * mat.at(3, 3) - mat.at(3, 0) * mat.at(2, 3);
float c1 = mat.at(2, 0) * mat.at(3, 2) - mat.at(3, 0) * mat.at(2, 2);
float c0 = mat.at(2, 0) * mat.at(3, 1) - mat.at(3, 0) * mat.at(2, 1);
float det = s0 * c5 - s1 * c4 + s2 * c3 + s3 * c2 - s4 * c1 + s5 * c0;
assert(det != 0 && "Determinant equals 0 !");
float invdet = 1.0 / det;
Mat4f result;
result.at(0, 0) = ( mat.at(1, 1) * c5 - mat.at(1, 2) * c4 + mat.at(1, 3) * c3) * invdet;
result.at(0, 1) = (-mat.at(0, 1) * c5 + mat.at(0, 2) * c4 - mat.at(0, 3) * c3) * invdet;
result.at(0, 2) = ( mat.at(3, 1) * s5 - mat.at(3, 2) * s4 + mat.at(3, 3) * s3) * invdet;
result.at(0, 3) = (-mat.at(2, 1) * s5 + mat.at(2, 2) * s4 - mat.at(2, 3) * s3) * invdet;
result.at(1, 0) = (-mat.at(1, 0) * c5 + mat.at(1, 2) * c2 - mat.at(1, 3) * c1) * invdet;
result.at(1, 1) = ( mat.at(0, 0) * c5 - mat.at(0, 2) * c2 + mat.at(0, 3) * c1) * invdet;
result.at(1, 2) = (-mat.at(3, 0) * s5 + mat.at(3, 2) * s2 - mat.at(3, 3) * s1) * invdet;
result.at(1, 3) = ( mat.at(2, 0) * s5 - mat.at(2, 2) * s2 + mat.at(2, 3) * s1) * invdet;
result.at(2, 0) = ( mat.at(1, 0) * c4 - mat.at(1, 1) * c2 + mat.at(1, 3) * c0) * invdet;
result.at(2, 1) = (-mat.at(0, 0) * c4 + mat.at(0, 1) * c2 - mat.at(0, 3) * c0) * invdet;
result.at(2, 2) = ( mat.at(3, 0) * s4 - mat.at(3, 1) * s2 + mat.at(3, 3) * s0) * invdet;
result.at(2, 3) = (-mat.at(2, 0) * s4 + mat.at(2, 1) * s2 - mat.at(2, 3) * s0) * invdet;
result.at(3, 0) = (-mat.at(1, 0) * c3 + mat.at(1, 1) * c1 - mat.at(1, 2) * c0) * invdet;
result.at(3, 1) = ( mat.at(0, 0) * c3 - mat.at(0, 1) * c1 + mat.at(0, 2) * c0) * invdet;
result.at(3, 2) = (-mat.at(3, 0) * s3 + mat.at(3, 1) * s1 - mat.at(3, 2) * s0) * invdet;
result.at(3, 3) = ( mat.at(2, 0) * s3 - mat.at(2, 1) * s1 + mat.at(2, 2) * s0) * invdet;
return result;
}
} // namespace maths
} // namespace td

View File

@@ -8,44 +8,44 @@ namespace utils {
namespace shape { namespace shape {
float Point::Distance(const Point& point) const { float Point::Distance(const Point& point) const {
return std::sqrt(DistanceSquared(point)); return std::sqrt(DistanceSquared(point));
} }
float Point::DistanceSquared(const Point& point) const { float Point::DistanceSquared(const Point& point) const {
return (m_X - point.GetX()) * (m_X - point.GetX()) + (m_Y - point.GetY()) * (m_Y - point.GetY()); return (m_X - point.GetX()) * (m_X - point.GetX()) + (m_Y - point.GetY()) * (m_Y - point.GetY());
} }
bool Rectangle::CollidesWith(const Point& point) const { bool Rectangle::CollidesWith(const Point& point) const {
return point.GetX() > GetTopLeft().GetX() && point.GetX() < GetBottomRight().GetX() && return point.GetX() > GetTopLeft().GetX() && point.GetX() < GetBottomRight().GetX() &&
point.GetY() > GetTopLeft().GetY() && point.GetY() < GetBottomRight().GetY(); point.GetY() > GetTopLeft().GetY() && point.GetY() < GetBottomRight().GetY();
} }
bool Rectangle::CollidesWith(const Rectangle& rect) const { bool Rectangle::CollidesWith(const Rectangle& rect) const {
Point point1{ rect.GetTopLeft().GetX(), rect.GetTopLeft().GetY() }; Point point1{ rect.GetTopLeft().GetX(), rect.GetTopLeft().GetY() };
Point point2{ rect.GetTopLeft().GetX(), rect.GetBottomRight().GetY() }; Point point2{ rect.GetTopLeft().GetX(), rect.GetBottomRight().GetY() };
Point point3{ rect.GetBottomRight().GetX(), rect.GetTopLeft().GetY() }; Point point3{ rect.GetBottomRight().GetX(), rect.GetTopLeft().GetY() };
Point point4{ rect.GetBottomRight().GetX(), rect.GetBottomRight().GetY() }; Point point4{ rect.GetBottomRight().GetX(), rect.GetBottomRight().GetY() };
if (CollidesWith(point1)) return true; if (CollidesWith(point1)) return true;
if (CollidesWith(point2)) return true; if (CollidesWith(point2)) return true;
if (CollidesWith(point3)) return true; if (CollidesWith(point3)) return true;
if (CollidesWith(point4)) return true; if (CollidesWith(point4)) return true;
return false; return false;
} }
bool Rectangle::CollidesWith(const Circle& circle) const { bool Rectangle::CollidesWith(const Circle& circle) const {
return circle.CollidesWith(*this); return circle.CollidesWith(*this);
} }
float Rectangle::Distance(const Circle& circle) const { float Rectangle::Distance(const Circle& circle) const {
return circle.Distance(*this); return circle.Distance(*this);
} }
float Rectangle::DistanceSquared(const Circle& circle) const { float Rectangle::DistanceSquared(const Circle& circle) const {
return circle.DistanceSquared(*this); return circle.DistanceSquared(*this);
} }
@@ -53,31 +53,31 @@ float Rectangle::DistanceSquared(const Circle& circle) const {
bool Circle::CollidesWith(const Point& point) const { bool Circle::CollidesWith(const Point& point) const {
return m_Radius * m_Radius > m_Center.DistanceSquared(point); return m_Radius * m_Radius > m_Center.DistanceSquared(point);
} }
bool Circle::CollidesWith(const Rectangle& rect) const { bool Circle::CollidesWith(const Rectangle& rect) const {
float DistanceSquared_ = DistanceSquared(rect); float DistanceSquared_ = DistanceSquared(rect);
return DistanceSquared_ < m_Radius* m_Radius; return DistanceSquared_ < m_Radius* m_Radius;
} }
bool Circle::CollidesWith(const Circle& circle) const { bool Circle::CollidesWith(const Circle& circle) const {
return m_Radius + circle.GetRadius() > m_Center.DistanceSquared(circle.GetCenter()); return m_Radius + circle.GetRadius() > m_Center.DistanceSquared(circle.GetCenter());
} }
float Circle::Distance(const Rectangle& rect) const { float Circle::Distance(const Rectangle& rect) const {
return std::sqrt(DistanceSquared(rect)); return std::sqrt(DistanceSquared(rect));
} }
float Circle::DistanceSquared(const Rectangle& rect) const { float Circle::DistanceSquared(const Rectangle& rect) const {
float closestX = std::clamp(m_Center.GetX(), rect.GetTopLeft().GetX(), rect.GetBottomRight().GetX()); float closestX = std::clamp(m_Center.GetX(), rect.GetTopLeft().GetX(), rect.GetBottomRight().GetX());
float closestY = std::clamp(m_Center.GetY(), rect.GetTopLeft().GetY(), rect.GetBottomRight().GetY()); float closestY = std::clamp(m_Center.GetY(), rect.GetTopLeft().GetY(), rect.GetBottomRight().GetY());
float DistanceX = m_Center.GetX() - closestX; float DistanceX = m_Center.GetX() - closestX;
float DistanceY = m_Center.GetY() - closestY; float DistanceY = m_Center.GetY() - closestY;
return (DistanceX * DistanceX) + (DistanceY * DistanceY); return (DistanceX * DistanceX) + (DistanceY * DistanceY);
} }
} // namespace shape } // namespace shape

View File

@@ -7,60 +7,60 @@ namespace td {
namespace utils { namespace utils {
void AutoTimer::Update() { void AutoTimer::Update() {
m_InternalTime += GetTime() - m_LastTime; m_InternalTime += GetTime() - m_LastTime;
if (m_InternalTime >= m_Interval) { if (m_InternalTime >= m_Interval) {
if (m_Function != nullptr) if (m_Function != nullptr)
m_Function(); m_Function();
m_InternalTime %= m_Interval; m_InternalTime %= m_Interval;
} }
m_LastTime = GetTime(); m_LastTime = GetTime();
} }
void AutoTimer::Update(std::uint64_t delta) { void AutoTimer::Update(std::uint64_t delta) {
m_InternalTime += delta; m_InternalTime += delta;
if (m_InternalTime >= m_Interval) { if (m_InternalTime >= m_Interval) {
if (m_Function != nullptr) if (m_Function != nullptr)
m_Function(); m_Function();
m_InternalTime %= m_Interval; m_InternalTime %= m_Interval;
} }
m_LastTime = GetTime(); m_LastTime = GetTime();
} }
void AutoTimer::Reset() { void AutoTimer::Reset() {
m_InternalTime = 0; m_InternalTime = 0;
m_LastTime = GetTime(); m_LastTime = GetTime();
} }
bool Timer::Update(std::uint64_t delta) { bool Timer::Update(std::uint64_t delta) {
m_InternalTime += delta; m_InternalTime += delta;
if (m_InternalTime >= m_Interval) { if (m_InternalTime >= m_Interval) {
m_InternalTime %= m_Interval; m_InternalTime %= m_Interval;
return true; return true;
} }
return false; return false;
} }
void Timer::Reset() { void Timer::Reset() {
m_InternalTime = 0; // let the timer active once at the beginning m_InternalTime = 0; // let the timer active once at the beginning
} }
bool CooldownTimer::Update(std::uint64_t delta) { bool CooldownTimer::Update(std::uint64_t delta) {
if (m_Cooldown > 0) { if (m_Cooldown > 0) {
m_Cooldown = static_cast<std::uint64_t>(std::max(static_cast<std::int64_t>(0), static_cast<std::int64_t>(m_Cooldown - delta))); m_Cooldown = static_cast<std::uint64_t>(std::max(static_cast<std::int64_t>(0), static_cast<std::int64_t>(m_Cooldown - delta)));
} }
return m_Cooldown == 0; return m_Cooldown == 0;
} }
void CooldownTimer::Reset() { void CooldownTimer::Reset() {
m_Cooldown = 0; // let the timer active once at the beginning m_Cooldown = 0; // let the timer active once at the beginning
} }
void CooldownTimer::ApplyCooldown() { void CooldownTimer::ApplyCooldown() {
m_Cooldown = m_CooldownTime; m_Cooldown = m_CooldownTime;
} }
std::uint64_t GetTime() { std::uint64_t GetTime() {
return static_cast<std::uint64_t>(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock().now().time_since_epoch()).count()); return static_cast<std::uint64_t>(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock().now().time_since_epoch()).count());
} }
} // namespace utils } // namespace utils

View File

@@ -16,109 +16,109 @@ namespace network {
/* Create an invalid address */ /* Create an invalid address */
IPAddress::IPAddress() noexcept IPAddress::IPAddress() noexcept
: m_Address(0), m_Valid(false) { : m_Address(0), m_Valid(false) {
} }
/* Initialize by string IP */ /* Initialize by string IP */
IPAddress::IPAddress(const std::string& ip) IPAddress::IPAddress(const std::string& ip)
: m_Address(0), m_Valid(false) { : m_Address(0), m_Valid(false) {
std::sregex_iterator begin(ip.begin(), ip.end(), IPRegex); std::sregex_iterator begin(ip.begin(), ip.end(), IPRegex);
std::sregex_iterator end; std::sregex_iterator end;
if (begin == end) return; // m_Valid = false if (begin == end) return; // m_Valid = false
std::smatch match = *begin; std::smatch match = *begin;
std::uint8_t octet1 = std::stoul(std::string(match[1])); std::uint8_t octet1 = std::stoul(std::string(match[1]));
std::uint8_t octet2 = std::stoul(std::string(match[2])); std::uint8_t octet2 = std::stoul(std::string(match[2]));
std::uint8_t octet3 = std::stoul(std::string(match[3])); std::uint8_t octet3 = std::stoul(std::string(match[3]));
std::uint8_t octet4 = std::stoul(std::string(match[4])); std::uint8_t octet4 = std::stoul(std::string(match[4]));
m_Address = static_cast<std::uint32_t>((octet1 << 24) | (octet2 << 16) | (octet3 << 8) | octet4); m_Address = static_cast<std::uint32_t>((octet1 << 24) | (octet2 << 16) | (octet3 << 8) | octet4);
m_Valid = true; m_Valid = true;
} }
IPAddress::IPAddress(const std::wstring& ip) IPAddress::IPAddress(const std::wstring& ip)
: m_Address(0), m_Valid(false) { : m_Address(0), m_Valid(false) {
std::wsregex_iterator begin(ip.begin(), ip.end(), IPRegexW); std::wsregex_iterator begin(ip.begin(), ip.end(), IPRegexW);
std::wsregex_iterator end; std::wsregex_iterator end;
if (begin == end) return; // m_Valid = false if (begin == end) return; // m_Valid = false
std::wsmatch match = *begin; std::wsmatch match = *begin;
std::uint8_t octet1 = std::stoul(match[1]); std::uint8_t octet1 = std::stoul(match[1]);
std::uint8_t octet2 = std::stoul(match[2]); std::uint8_t octet2 = std::stoul(match[2]);
std::uint8_t octet3 = std::stoul(match[3]); std::uint8_t octet3 = std::stoul(match[3]);
std::uint8_t octet4 = std::stoul(match[4]); std::uint8_t octet4 = std::stoul(match[4]);
m_Address = static_cast<std::uint32_t>((octet1 << 24) | (octet2 << 16) | (octet3 << 8) | octet4); m_Address = static_cast<std::uint32_t>((octet1 << 24) | (octet2 << 16) | (octet3 << 8) | octet4);
m_Valid = true; m_Valid = true;
} }
/* Initialize by octets */ /* Initialize by octets */
IPAddress::IPAddress(uint8_t octet1, uint8_t octet2, uint8_t octet3, uint8_t octet4) noexcept IPAddress::IPAddress(uint8_t octet1, uint8_t octet2, uint8_t octet3, uint8_t octet4) noexcept
: m_Valid(true) { : m_Valid(true) {
m_Address = static_cast<std::uint32_t>((octet1 << 24) | (octet2 << 16) | (octet3 << 8) | octet4); m_Address = static_cast<std::uint32_t>((octet1 << 24) | (octet2 << 16) | (octet3 << 8) | octet4);
} }
/* Get the specific octet */ /* Get the specific octet */
uint8_t IPAddress::GetOctet(uint8_t num) const { uint8_t IPAddress::GetOctet(uint8_t num) const {
if (num == 0 || num > 4) throw std::invalid_argument("Invalid argument in IPAddress:GetOctet."); if (num == 0 || num > 4) throw std::invalid_argument("Invalid argument in IPAddress:GetOctet.");
return (m_Address >> (8 * (4 - num))) & 0xFF; return (m_Address >> (8 * (4 - num))) & 0xFF;
} }
/* Set the specific octet. 1-4 */ /* Set the specific octet. 1-4 */
void IPAddress::SetOctet(uint8_t num, uint8_t value) { void IPAddress::SetOctet(uint8_t num, uint8_t value) {
if (num == 0 || num > 4) throw std::invalid_argument("Invalid argument in IPAddress:GetOctet."); if (num == 0 || num > 4) throw std::invalid_argument("Invalid argument in IPAddress:GetOctet.");
uint8_t octets[4]; uint8_t octets[4];
for (int i = 0; i < 4; ++i) for (int i = 0; i < 4; ++i)
octets[i] = (m_Address >> ((3 - i) * 8)) & 0xFF; octets[i] = (m_Address >> ((3 - i) * 8)) & 0xFF;
octets[num - 1] = value; octets[num - 1] = value;
m_Address = static_cast<std::uint32_t>((octets[0] << 24) | (octets[1] << 16) | (octets[2] << 8) | octets[3]); m_Address = static_cast<std::uint32_t>((octets[0] << 24) | (octets[1] << 16) | (octets[2] << 8) | octets[3]);
} }
IPAddress IPAddress::LocalAddress() { IPAddress IPAddress::LocalAddress() {
return IPAddress(127, 0, 0, 1); return IPAddress(127, 0, 0, 1);
} }
std::string IPAddress::ToString() const { std::string IPAddress::ToString() const {
std::stringstream ss; std::stringstream ss;
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i) {
if (i != 0) ss << "."; if (i != 0) ss << ".";
ss << static_cast<unsigned int>(GetOctet(i + 1)); ss << static_cast<unsigned int>(GetOctet(i + 1));
} }
return ss.str(); return ss.str();
} }
bool IPAddress::operator==(const IPAddress& right) { bool IPAddress::operator==(const IPAddress& right) {
return m_Address == right.m_Address; return m_Address == right.m_Address;
} }
bool IPAddress::operator!=(const IPAddress& right) { bool IPAddress::operator!=(const IPAddress& right) {
return !(*this == right); return !(*this == right);
} }
bool IPAddress::operator==(bool b) { bool IPAddress::operator==(bool b) {
return IsValid() == b; return IsValid() == b;
} }
std::ostream& operator<<(std::ostream& os, const IPAddress& addr) { std::ostream& operator<<(std::ostream& os, const IPAddress& addr) {
return os << addr.ToString(); return os << addr.ToString();
} }
std::wostream& operator<<(std::wostream& os, const IPAddress& addr) { std::wostream& operator<<(std::wostream& os, const IPAddress& addr) {
std::string str = addr.ToString(); std::string str = addr.ToString();
return os << std::wstring(str.begin(), str.end()); return os << std::wstring(str.begin(), str.end());
} }
} // ns network } // ns network

View File

@@ -5,20 +5,20 @@ namespace network {
class NetworkInitializer { class NetworkInitializer {
public: public:
NetworkInitializer(); NetworkInitializer();
~NetworkInitializer(); ~NetworkInitializer();
NetworkInitializer(const NetworkInitializer& rhs) = delete; NetworkInitializer(const NetworkInitializer& rhs) = delete;
NetworkInitializer& operator=(const NetworkInitializer& rhs) = delete; NetworkInitializer& operator=(const NetworkInitializer& rhs) = delete;
}; };
#ifdef _WIN32 #ifdef _WIN32
NetworkInitializer::NetworkInitializer() { NetworkInitializer::NetworkInitializer() {
WSADATA wsaData; WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData); WSAStartup(MAKEWORD(2, 2), &wsaData);
} }
NetworkInitializer::~NetworkInitializer() { NetworkInitializer::~NetworkInitializer() {
WSACleanup(); WSACleanup();
} }
#else #else
NetworkInitializer::NetworkInitializer() { NetworkInitializer::NetworkInitializer() {
@@ -32,36 +32,36 @@ NetworkInitializer::~NetworkInitializer() {
NetworkInitializer initializer; NetworkInitializer initializer;
IPAddresses Dns::Resolve(const std::string& host) { IPAddresses Dns::Resolve(const std::string& host) {
IPAddresses list; IPAddresses list;
addrinfo hints{}; addrinfo hints{};
addrinfo* addresses = nullptr; addrinfo* addresses = nullptr;
//hints.ai_family = AF_UNSPEC; //hints.ai_family = AF_UNSPEC;
hints.ai_family = AF_INET; hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM; hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP; hints.ai_protocol = IPPROTO_TCP;
getaddrinfo(host.c_str(), NULL, &hints, &addresses); getaddrinfo(host.c_str(), NULL, &hints, &addresses);
for (addrinfo* p = addresses; p != NULL; p = p->ai_next) { for (addrinfo* p = addresses; p != NULL; p = p->ai_next) {
#ifdef _WIN32 #ifdef _WIN32
//wchar_t straddr[35]; //wchar_t straddr[35];
//char straddr[512]; //char straddr[512];
//DWORD len; //DWORD len;
//WSAAddressToStringA(p->ai_addr, p->ai_addrlen, NULL, straddr, &len); //WSAAddressToStringA(p->ai_addr, p->ai_addrlen, NULL, straddr, &len);
char* straddr = inet_ntoa(((sockaddr_in*)p->ai_addr)->sin_addr); char* straddr = inet_ntoa(((sockaddr_in*)p->ai_addr)->sin_addr);
#else #else
char straddr[512]; char straddr[512];
inet_ntop(p->ai_family, &(reinterpret_cast<sockaddr_in*>(p->ai_addr))->sin_addr, straddr, sizeof(straddr)); inet_ntop(p->ai_family, &(reinterpret_cast<sockaddr_in*>(p->ai_addr))->sin_addr, straddr, sizeof(straddr));
#endif #endif
list.push_back(IPAddress(straddr)); list.push_back(IPAddress(straddr));
} }
return list; return list;
} }
} // ns network } // ns network

View File

@@ -13,68 +13,67 @@ namespace td {
namespace network { namespace network {
Socket::Socket(Type type) Socket::Socket(Type type)
: m_Blocking(false), : m_Blocking(false),
m_Type(type), m_Type(type),
m_Status(Disconnected), m_Status(Disconnected),
m_Handle(static_cast<SocketHandle>(INVALID_SOCKET)) m_Handle(static_cast<SocketHandle>(INVALID_SOCKET)) {
{
} }
Socket::~Socket() { Socket::~Socket() {
Disconnect(); Disconnect();
} }
bool Socket::SetBlocking(bool block) { bool Socket::SetBlocking(bool block) {
unsigned long mode = block ? 0 : 1; unsigned long mode = block ? 0 : 1;
if (ioctl(m_Handle, FIONBIO, &mode) < 0) { if (ioctl(m_Handle, FIONBIO, &mode) < 0) {
return false; return false;
} }
m_Blocking = block; m_Blocking = block;
return true; return true;
} }
bool Socket::IsBlocking() const noexcept { bool Socket::IsBlocking() const noexcept {
return m_Blocking; return m_Blocking;
} }
Socket::Type Socket::GetType() const noexcept { Socket::Type Socket::GetType() const noexcept {
return m_Type; return m_Type;
} }
SocketHandle Socket::GetHandle() const noexcept { SocketHandle Socket::GetHandle() const noexcept {
return m_Handle; return m_Handle;
} }
void Socket::SetStatus(Socket::Status status) { void Socket::SetStatus(Socket::Status status) {
m_Status = status; m_Status = status;
} }
Socket::Status Socket::GetStatus() const noexcept { Socket::Status Socket::GetStatus() const noexcept {
return m_Status; return m_Status;
} }
bool Socket::Connect(const std::string& ip, uint16_t port) { bool Socket::Connect(const std::string& ip, uint16_t port) {
IPAddress addr(ip); IPAddress addr(ip);
return Connect(addr, port); return Connect(addr, port);
} }
std::size_t Socket::Send(const std::string& data) { std::size_t Socket::Send(const std::string& data) {
return this->Send(reinterpret_cast<const unsigned char*>(data.c_str()), data.length()); return this->Send(reinterpret_cast<const unsigned char*>(data.c_str()), data.length());
} }
std::size_t Socket::Send(DataBuffer& buffer) { std::size_t Socket::Send(DataBuffer& buffer) {
std::string data = buffer.ToString(); std::string data = buffer.ToString();
return this->Send(reinterpret_cast<const unsigned char*>(data.c_str()), data.length()); return this->Send(reinterpret_cast<const unsigned char*>(data.c_str()), data.length());
} }
void Socket::Disconnect() { void Socket::Disconnect() {
if (m_Handle < 0) if (m_Handle < 0)
closesocket(m_Handle); closesocket(m_Handle);
m_Status = Disconnected; m_Status = Disconnected;
} }
} // ns network } // ns network

View File

@@ -14,58 +14,58 @@ namespace network {
TCPListener::TCPListener() {} TCPListener::TCPListener() {}
TCPListener::~TCPListener() { TCPListener::~TCPListener() {
Destroy(); Destroy();
} }
bool TCPListener::Listen(uint16_t port, int maxConnections) { bool TCPListener::Listen(uint16_t port, int maxConnections) {
if ((m_Handle = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) if ((m_Handle = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
return false; return false;
struct sockaddr_in address; struct sockaddr_in address;
address.sin_family = AF_INET; address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY; address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(port); address.sin_port = htons(port);
if (::bind(m_Handle, reinterpret_cast<sockaddr*>(&address), sizeof(address)) < 0) if (::bind(m_Handle, reinterpret_cast<sockaddr*>(&address), sizeof(address)) < 0)
return false; return false;
if (::listen(m_Handle, maxConnections) < 0) if (::listen(m_Handle, maxConnections) < 0)
return false; return false;
m_Port = port; m_Port = port;
m_MaxConnections = maxConnections; m_MaxConnections = maxConnections;
return true; return true;
} }
bool TCPListener::Accept(TCPSocket& newSocket) { bool TCPListener::Accept(TCPSocket& newSocket) {
int addrlen = sizeof(newSocket.m_RemoteAddr); int addrlen = sizeof(newSocket.m_RemoteAddr);
if ((newSocket.m_Handle = ::accept(m_Handle, reinterpret_cast<sockaddr*>(&newSocket.m_RemoteAddr), if ((newSocket.m_Handle = ::accept(m_Handle, reinterpret_cast<sockaddr*>(&newSocket.m_RemoteAddr),
reinterpret_cast<socklen_t*>(&addrlen))) < 0) reinterpret_cast<socklen_t*>(&addrlen))) < 0)
return false; return false;
newSocket.SetStatus(Socket::Status::Connected); newSocket.SetStatus(Socket::Status::Connected);
newSocket.SetBlocking(false); newSocket.SetBlocking(false);
return true; return true;
} }
void TCPListener::Destroy() { void TCPListener::Destroy() {
if (m_Handle < 0) if (m_Handle < 0)
::closesocket(m_Handle); ::closesocket(m_Handle);
} }
bool TCPListener::Close() { bool TCPListener::Close() {
if (::shutdown(m_Handle, SD_BOTH) == 0) if (::shutdown(m_Handle, SD_BOTH) == 0)
return true; return true;
return false; return false;
} }
bool TCPListener::SetBlocking(bool blocking) { bool TCPListener::SetBlocking(bool blocking) {
unsigned long mode = blocking ? 0 : 1; unsigned long mode = blocking ? 0 : 1;
if (::ioctlsocket(m_Handle, FIONBIO, &mode) < 0) { if (::ioctlsocket(m_Handle, FIONBIO, &mode) < 0) {
return false; return false;
} }
return true; return true;
} }
} // namespace network } // namespace network
} // namespace td } // namespace td

View File

@@ -14,132 +14,132 @@ namespace td {
namespace network { namespace network {
TCPSocket::TCPSocket() : Socket(Socket::TCP), m_Port(0) { TCPSocket::TCPSocket() : Socket(Socket::TCP), m_Port(0) {
m_Handle = static_cast<SocketHandle>(INVALID_SOCKET); m_Handle = static_cast<SocketHandle>(INVALID_SOCKET);
} }
bool TCPSocket::Connect(const IPAddress& address, unsigned short port) { bool TCPSocket::Connect(const IPAddress& address, unsigned short port) {
if (this->GetStatus() == Connected) if (this->GetStatus() == Connected)
return true; return true;
struct addrinfo hints {}; struct addrinfo hints {};
memset(&hints, 0, sizeof(addrinfo)); memset(&hints, 0, sizeof(addrinfo));
struct addrinfo* result = nullptr; struct addrinfo* result = nullptr;
hints.ai_family = AF_INET; hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM; hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP; hints.ai_protocol = IPPROTO_TCP;
if (::getaddrinfo(address.ToString().c_str(), std::to_string(static_cast<int>(port)).c_str(), &hints, &result) != 0) { if (::getaddrinfo(address.ToString().c_str(), std::to_string(static_cast<int>(port)).c_str(), &hints, &result) != 0) {
std::cerr << "Failed to get address info !\n"; std::cerr << "Failed to get address info !\n";
return false; return false;
} }
if ((m_Handle = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { if ((m_Handle = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
std::cerr << "Failed to create socket !\n"; std::cerr << "Failed to create socket !\n";
return false; return false;
} }
struct addrinfo* ptr = nullptr; struct addrinfo* ptr = nullptr;
for (ptr = result; ptr != nullptr; ptr = ptr->ai_next) { for (ptr = result; ptr != nullptr; ptr = ptr->ai_next) {
struct sockaddr* sockaddr = ptr->ai_addr; struct sockaddr* sockaddr = ptr->ai_addr;
if (::connect(m_Handle, sockaddr, sizeof(sockaddr_in)) != 0) { if (::connect(m_Handle, sockaddr, sizeof(sockaddr_in)) != 0) {
std::cerr << "Failed to connect with this address !\n"; std::cerr << "Failed to connect with this address !\n";
continue; continue;
} }
m_RemoteAddr = *sockaddr; m_RemoteAddr = *sockaddr;
break; break;
} }
freeaddrinfo(result); freeaddrinfo(result);
if (!ptr) { if (!ptr) {
std::cerr << "Could not find a suitable interface for connecting !\n"; std::cerr << "Could not find a suitable interface for connecting !\n";
return false; return false;
} }
this->SetStatus(Connected); this->SetStatus(Connected);
m_RemoteIP = address; m_RemoteIP = address;
m_Port = port; m_Port = port;
return true; return true;
} }
size_t TCPSocket::Send(const unsigned char* data, size_t size) { size_t TCPSocket::Send(const unsigned char* data, size_t size) {
if (this->GetStatus() != Connected) if (this->GetStatus() != Connected)
return 0; return 0;
size_t sent = 0; size_t sent = 0;
while (sent < size) { while (sent < size) {
int cur = ::send(m_Handle, reinterpret_cast<const char*>(data + sent), size - sent, 0); int cur = ::send(m_Handle, reinterpret_cast<const char*>(data + sent), size - sent, 0);
if (cur <= 0) { if (cur <= 0) {
Disconnect(); Disconnect();
return 0; return 0;
} }
sent += static_cast<std::size_t>(cur); sent += static_cast<std::size_t>(cur);
} }
return sent; return sent;
} }
std::size_t TCPSocket::Receive(DataBuffer& buffer, std::size_t amount) { std::size_t TCPSocket::Receive(DataBuffer& buffer, std::size_t amount) {
buffer.Resize(amount); buffer.Resize(amount);
buffer.SetReadOffset(0); buffer.SetReadOffset(0);
int recvAmount = ::recv(m_Handle, reinterpret_cast<char*>(buffer.data()), amount, 0); int recvAmount = ::recv(m_Handle, reinterpret_cast<char*>(buffer.data()), amount, 0);
if (recvAmount <= 0) { if (recvAmount <= 0) {
#if defined(_WIN32) || defined(WIN32) #if defined(_WIN32) || defined(WIN32)
int err = WSAGetLastError(); int err = WSAGetLastError();
#else #else
int err = errno; int err = errno;
#endif #endif
if (err == WOULDBLOCK) { if (err == WOULDBLOCK) {
buffer.Clear(); buffer.Clear();
return 0; return 0;
} }
Disconnect(); Disconnect();
buffer.Clear(); buffer.Clear();
return 0; return 0;
} }
buffer.Resize(static_cast<std::size_t>(recvAmount)); buffer.Resize(static_cast<std::size_t>(recvAmount));
return static_cast<std::size_t>(recvAmount); return static_cast<std::size_t>(recvAmount);
} }
DataBuffer TCPSocket::Receive(std::size_t amount) { DataBuffer TCPSocket::Receive(std::size_t amount) {
std::unique_ptr<char[]> buf(new char[amount]); std::unique_ptr<char[]> buf(new char[amount]);
int received = ::recv(m_Handle, buf.get(), amount, 0); int received = ::recv(m_Handle, buf.get(), amount, 0);
if (received <= 0) { if (received <= 0) {
#if defined(_WIN32) || defined(WIN32) #if defined(_WIN32) || defined(WIN32)
int err = WSAGetLastError(); int err = WSAGetLastError();
#else #else
int err = errno; int err = errno;
#endif #endif
if (err == WOULDBLOCK) if (err == WOULDBLOCK)
return DataBuffer(); return DataBuffer();
Disconnect(); Disconnect();
return DataBuffer(); return DataBuffer();
} }
return DataBuffer(std::string(buf.get(), static_cast<std::size_t>(received))); return DataBuffer(std::string(buf.get(), static_cast<std::size_t>(received)));
} }
TCPSocket::TCPSocket(TCPSocket&& other) : Socket(TCP) { TCPSocket::TCPSocket(TCPSocket&& other) : Socket(TCP) {
m_Handle = other.m_Handle; m_Handle = other.m_Handle;
m_Port = other.m_Port; m_Port = other.m_Port;
m_RemoteAddr = other.m_RemoteAddr; m_RemoteAddr = other.m_RemoteAddr;
m_RemoteIP = other.m_RemoteIP; m_RemoteIP = other.m_RemoteIP;
SetStatus(other.GetStatus()); SetStatus(other.GetStatus());
SetBlocking(other.IsBlocking()); SetBlocking(other.IsBlocking());
other.m_Handle = static_cast<SocketHandle>(INVALID_SOCKET); other.m_Handle = static_cast<SocketHandle>(INVALID_SOCKET);
} }
void SendPacket(const DataBuffer& data, network::TCPSocket& socket) { void SendPacket(const DataBuffer& data, network::TCPSocket& socket) {
DataBuffer compressed = utils::Compress(data); DataBuffer compressed = utils::Compress(data);
socket.Send(reinterpret_cast<const std::uint8_t*>(compressed.ToString().data()), compressed.GetSize()); socket.Send(reinterpret_cast<const std::uint8_t*>(compressed.ToString().data()), compressed.GetSize());
} }

View File

@@ -12,92 +12,91 @@ namespace td {
namespace network { namespace network {
UDPSocket::UDPSocket() UDPSocket::UDPSocket()
: Socket(Socket::UDP), m_Port(0) : Socket(Socket::UDP), m_Port(0) {
{ m_Handle = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
m_Handle = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
} }
bool UDPSocket::Connect(const IPAddress& address, unsigned short port) { bool UDPSocket::Connect(const IPAddress& address, unsigned short port) {
if (this->GetStatus() == Connected) if (this->GetStatus() == Connected)
return true; return true;
m_RemoteAddr.sin_port = htons(port); m_RemoteAddr.sin_port = htons(port);
m_RemoteAddr.sin_family = AF_INET; m_RemoteAddr.sin_family = AF_INET;
m_RemoteAddr.sin_addr.s_addr = inet_addr(address.ToString().c_str()); m_RemoteAddr.sin_addr.s_addr = inet_addr(address.ToString().c_str());
this->SetStatus(Connected); this->SetStatus(Connected);
m_RemoteIP = IPAddress(address); m_RemoteIP = IPAddress(address);
m_Port = port; m_Port = port;
return true; return true;
} }
std::size_t UDPSocket::Send(const unsigned char* data, std::size_t size) { std::size_t UDPSocket::Send(const unsigned char* data, std::size_t size) {
std::size_t sent = 0; std::size_t sent = 0;
if (this->GetStatus() != Connected) if (this->GetStatus() != Connected)
return 0; return 0;
while (sent < size) { while (sent < size) {
int cur = ::sendto(m_Handle, reinterpret_cast<const char*>(data + sent), size - sent, 0, int cur = ::sendto(m_Handle, reinterpret_cast<const char*>(data + sent), size - sent, 0,
reinterpret_cast<sockaddr*>(&m_RemoteAddr), sizeof(sockaddr_in)); reinterpret_cast<sockaddr*>(&m_RemoteAddr), sizeof(sockaddr_in));
if (cur <= 0) { if (cur <= 0) {
Disconnect(); Disconnect();
return 0; return 0;
} }
sent += static_cast<std::size_t>(cur); sent += static_cast<std::size_t>(cur);
} }
return sent; return sent;
} }
DataBuffer UDPSocket::Receive(std::size_t amount) { DataBuffer UDPSocket::Receive(std::size_t amount) {
std::unique_ptr<char[]> buf(new char[amount]); std::unique_ptr<char[]> buf(new char[amount]);
socklen_t slen = sizeof(sockaddr_in); socklen_t slen = sizeof(sockaddr_in);
int received = ::recvfrom(m_Handle, buf.get(), amount, 0, int received = ::recvfrom(m_Handle, buf.get(), amount, 0,
reinterpret_cast<sockaddr*>(&m_RemoteAddr), &slen); reinterpret_cast<sockaddr*>(&m_RemoteAddr), &slen);
if (received <= 0) { if (received <= 0) {
#if defined(_WIN32) || defined(WIN32) #if defined(_WIN32) || defined(WIN32)
int err = WSAGetLastError(); int err = WSAGetLastError();
#else #else
int err = errno; int err = errno;
#endif #endif
if (err == WOULDBLOCK) if (err == WOULDBLOCK)
return DataBuffer(std::string(buf.get(), static_cast<std::size_t>(received))); return DataBuffer(std::string(buf.get(), static_cast<std::size_t>(received)));
Disconnect(); Disconnect();
return DataBuffer(); return DataBuffer();
} }
return DataBuffer(std::string(buf.get(), static_cast<std::size_t>(received))); return DataBuffer(std::string(buf.get(), static_cast<std::size_t>(received)));
} }
std::size_t UDPSocket::Receive(DataBuffer& buffer, std::size_t amount) { std::size_t UDPSocket::Receive(DataBuffer& buffer, std::size_t amount) {
buffer.Resize(amount); buffer.Resize(amount);
buffer.SetReadOffset(0); buffer.SetReadOffset(0);
socklen_t slen = sizeof(sockaddr_in); socklen_t slen = sizeof(sockaddr_in);
int recvAmount = ::recvfrom(m_Handle, reinterpret_cast<char*>(buffer.data()), amount, 0, int recvAmount = ::recvfrom(m_Handle, reinterpret_cast<char*>(buffer.data()), amount, 0,
reinterpret_cast<sockaddr*>(&m_RemoteAddr), &slen); reinterpret_cast<sockaddr*>(&m_RemoteAddr), &slen);
if (recvAmount <= 0) { if (recvAmount <= 0) {
#if defined(_WIN32) || defined(WIN32) #if defined(_WIN32) || defined(WIN32)
int err = WSAGetLastError(); int err = WSAGetLastError();
#else #else
int err = errno; int err = errno;
#endif #endif
if (err == WOULDBLOCK) { if (err == WOULDBLOCK) {
buffer.Clear(); buffer.Clear();
return 0; return 0;
} }
Disconnect(); Disconnect();
buffer.Clear(); buffer.Clear();
return 0; return 0;
} }
buffer.Resize(static_cast<std::size_t>(recvAmount)); buffer.Resize(static_cast<std::size_t>(recvAmount));
return static_cast<std::size_t>(recvAmount); return static_cast<std::size_t>(recvAmount);
} }
} // ns network } // ns network

View File

@@ -4,33 +4,33 @@ namespace td {
namespace protocol { namespace protocol {
void PacketDispatcher::RegisterHandler(PacketType type, PacketHandler* handler) { void PacketDispatcher::RegisterHandler(PacketType type, PacketHandler* handler) {
auto found = std::find(m_Handlers[type].begin(), m_Handlers[type].end(), handler); auto found = std::find(m_Handlers[type].begin(), m_Handlers[type].end(), handler);
if (found == m_Handlers[type].end()) if (found == m_Handlers[type].end())
m_Handlers[type].push_back(handler); m_Handlers[type].push_back(handler);
} }
void PacketDispatcher::UnregisterHandler(PacketType type, PacketHandler* handler) { void PacketDispatcher::UnregisterHandler(PacketType type, PacketHandler* handler) {
auto found = std::find(m_Handlers[type].begin(), m_Handlers[type].end(), handler); auto found = std::find(m_Handlers[type].begin(), m_Handlers[type].end(), handler);
if (found != m_Handlers[type].end()) if (found != m_Handlers[type].end())
m_Handlers[type].erase(found); m_Handlers[type].erase(found);
} }
void PacketDispatcher::UnregisterHandler(PacketHandler* handler) { void PacketDispatcher::UnregisterHandler(PacketHandler* handler) {
for (auto& pair : m_Handlers) { for (auto& pair : m_Handlers) {
if (pair.second.empty()) continue; if (pair.second.empty()) continue;
PacketType type = pair.first; PacketType type = pair.first;
m_Handlers[type].erase(std::remove(m_Handlers[type].begin(), m_Handlers[type].end(), handler), m_Handlers[type].end()); m_Handlers[type].erase(std::remove(m_Handlers[type].begin(), m_Handlers[type].end(), handler), m_Handlers[type].end());
} }
} }
void PacketDispatcher::Dispatch(const PacketPtr& packet) { void PacketDispatcher::Dispatch(const PacketPtr& packet) {
if (!packet) return; if (!packet) return;
PacketType type = packet->GetType(); PacketType type = packet->GetType();
for (PacketHandler* handler : m_Handlers[type]) for (PacketHandler* handler : m_Handlers[type])
packet->Dispatch(handler); packet->Dispatch(handler);
} }
} // namespace protocol } // namespace protocol

View File

@@ -9,38 +9,38 @@ namespace PacketFactory {
using PacketCreator = std::function<PacketPtr()>; using PacketCreator = std::function<PacketPtr()>;
static std::map<PacketType, PacketCreator> packets = { static std::map<PacketType, PacketCreator> packets = {
{PacketType::PlayerLogin, []() -> PacketPtr {return std::make_unique<PlayerLoginPacket>();} }, {PacketType::PlayerLogin, []() -> PacketPtr {return std::make_unique<PlayerLoginPacket>();} },
{PacketType::WorldBeginData, []() -> PacketPtr {return std::make_unique<WorldBeginDataPacket>();} }, {PacketType::WorldBeginData, []() -> PacketPtr {return std::make_unique<WorldBeginDataPacket>();} },
{PacketType::WorldData, []() -> PacketPtr {return std::make_unique<WorldDataPacket>();} }, {PacketType::WorldData, []() -> PacketPtr {return std::make_unique<WorldDataPacket>();} },
{PacketType::KeepAlive, []() -> PacketPtr {return std::make_unique<KeepAlivePacket>();} }, {PacketType::KeepAlive, []() -> PacketPtr {return std::make_unique<KeepAlivePacket>();} },
{PacketType::UpdateMoney, []() -> PacketPtr {return std::make_unique<UpdateMoneyPacket>();} }, {PacketType::UpdateMoney, []() -> PacketPtr {return std::make_unique<UpdateMoneyPacket>();} },
{PacketType::UpdateEXP, []() -> PacketPtr {return std::make_unique<UpdateExpPacket>();} }, {PacketType::UpdateEXP, []() -> PacketPtr {return std::make_unique<UpdateExpPacket>();} },
{PacketType::UpdateLobbyTime, []() -> PacketPtr {return std::make_unique<UpdateLobbyTimePacket>(); } }, {PacketType::UpdateLobbyTime, []() -> PacketPtr {return std::make_unique<UpdateLobbyTimePacket>(); } },
{PacketType::UpdateGameState, []() -> PacketPtr {return std::make_unique<UpdateGameStatePacket>(); } }, {PacketType::UpdateGameState, []() -> PacketPtr {return std::make_unique<UpdateGameStatePacket>(); } },
{PacketType::PlayerList, []() -> PacketPtr {return std::make_unique<PlayerListPacket>(); } }, {PacketType::PlayerList, []() -> PacketPtr {return std::make_unique<PlayerListPacket>(); } },
{PacketType::PlayerJoin, []() -> PacketPtr {return std::make_unique<PlayerJoinPacket>(); } }, {PacketType::PlayerJoin, []() -> PacketPtr {return std::make_unique<PlayerJoinPacket>(); } },
{PacketType::PlayerLeave, []() -> PacketPtr {return std::make_unique<PlayerLeavePacket>(); } }, {PacketType::PlayerLeave, []() -> PacketPtr {return std::make_unique<PlayerLeavePacket>(); } },
{PacketType::ConnectionInfo, []() -> PacketPtr {return std::make_unique<ConnexionInfoPacket>(); } }, {PacketType::ConnectionInfo, []() -> PacketPtr {return std::make_unique<ConnexionInfoPacket>(); } },
{PacketType::SelectTeam, []() -> PacketPtr {return std::make_unique<SelectTeamPacket>(); } }, {PacketType::SelectTeam, []() -> PacketPtr {return std::make_unique<SelectTeamPacket>(); } },
{PacketType::UpdatePlayerTeam, []() -> PacketPtr {return std::make_unique<UpdatePlayerTeamPacket>(); } }, {PacketType::UpdatePlayerTeam, []() -> PacketPtr {return std::make_unique<UpdatePlayerTeamPacket>(); } },
{PacketType::Disconnect, []() -> PacketPtr {return std::make_unique<DisconnectPacket>(); } }, {PacketType::Disconnect, []() -> PacketPtr {return std::make_unique<DisconnectPacket>(); } },
{PacketType::ServerTps, []() -> PacketPtr {return std::make_unique<ServerTpsPacket>(); } }, {PacketType::ServerTps, []() -> PacketPtr {return std::make_unique<ServerTpsPacket>(); } },
{PacketType::SpawnMob, []() -> PacketPtr {return std::make_unique<SpawnMobPacket>(); } }, {PacketType::SpawnMob, []() -> PacketPtr {return std::make_unique<SpawnMobPacket>(); } },
{PacketType::PlaceTower, []() -> PacketPtr {return std::make_unique<PlaceTowerPacket>(); } }, {PacketType::PlaceTower, []() -> PacketPtr {return std::make_unique<PlaceTowerPacket>(); } },
{PacketType::WorldAddTower, []() -> PacketPtr {return std::make_unique<WorldAddTowerPacket>(); } }, {PacketType::WorldAddTower, []() -> PacketPtr {return std::make_unique<WorldAddTowerPacket>(); } },
{PacketType::RemoveTower, []() -> PacketPtr {return std::make_unique<RemoveTowerPacket>(); } }, {PacketType::RemoveTower, []() -> PacketPtr {return std::make_unique<RemoveTowerPacket>(); } },
{PacketType::SendMobs, []() -> PacketPtr {return std::make_unique<SendMobsPacket>(); } }, {PacketType::SendMobs, []() -> PacketPtr {return std::make_unique<SendMobsPacket>(); } },
{PacketType::UpgradeTower, []() -> PacketPtr {return std::make_unique<UpgradeTowerPacket>(); } }, {PacketType::UpgradeTower, []() -> PacketPtr {return std::make_unique<UpgradeTowerPacket>(); } },
{PacketType::UpdateCastleLife, []() -> PacketPtr {return std::make_unique<UpdateCastleLifePacket>(); } }, {PacketType::UpdateCastleLife, []() -> PacketPtr {return std::make_unique<UpdateCastleLifePacket>(); } },
{PacketType::UpdateMobStates, []() -> PacketPtr {return std::make_unique<UpdateMobStatesPacket>(); } }, {PacketType::UpdateMobStates, []() -> PacketPtr {return std::make_unique<UpdateMobStatesPacket>(); } },
{PacketType::PlayerBuyItem, []() -> PacketPtr {return std::make_unique<PlayerBuyItemPacket>(); } }, {PacketType::PlayerBuyItem, []() -> PacketPtr {return std::make_unique<PlayerBuyItemPacket>(); } },
{PacketType::PlayerBuyMobUpgrade, []() -> PacketPtr {return std::make_unique<PlayerBuyMobUpgradePacket>(); } }, {PacketType::PlayerBuyMobUpgrade, []() -> PacketPtr {return std::make_unique<PlayerBuyMobUpgradePacket>(); } },
}; };
PacketPtr CreatePacket(PacketType type, DataBuffer& buffer) { PacketPtr CreatePacket(PacketType type, DataBuffer& buffer) {
PacketPtr packet = packets[type](); PacketPtr packet = packets[type]();
packet->Deserialize(buffer); packet->Deserialize(buffer);
return packet; return packet;
} }
} }

View File

@@ -13,559 +13,559 @@ const int BITS_IN_BYTE = 8;
const int BITS_IN_LONG = BITS_IN_BYTE * sizeof(std::uint64_t); const int BITS_IN_LONG = BITS_IN_BYTE * sizeof(std::uint64_t);
static unsigned int countBits(unsigned int number) { static unsigned int countBits(unsigned int number) {
// log function in base 2 // log function in base 2
// take only integer part // take only integer part
return static_cast<unsigned int>(std::log2(number) + 1); return static_cast<unsigned int>(std::log2(number) + 1);
} }
void Packet::WritePacketID(DataBuffer& data, bool packetID) const { void Packet::WritePacketID(DataBuffer& data, bool packetID) const {
if (packetID) if (packetID)
data << GetID(); data << GetID();
} }
static DataBuffer& operator<<(DataBuffer& buffer, game::TilePtr tile) { static DataBuffer& operator<<(DataBuffer& buffer, game::TilePtr tile) {
buffer << tile->GetType(); buffer << tile->GetType();
switch (tile->GetType()) { switch (tile->GetType()) {
case game::TileType::Tower: { case game::TileType::Tower: {
const game::TowerTile* towerTile = dynamic_cast<const game::TowerTile*>(tile.get()); const game::TowerTile* towerTile = dynamic_cast<const game::TowerTile*>(tile.get());
buffer << towerTile->color_palette_ref << towerTile->team_owner; buffer << towerTile->color_palette_ref << towerTile->team_owner;
break; break;
} }
case game::TileType::Walk: { case game::TileType::Walk: {
const game::WalkableTile* walkTile = dynamic_cast<const game::WalkableTile*>(tile.get()); const game::WalkableTile* walkTile = dynamic_cast<const game::WalkableTile*>(tile.get());
buffer << walkTile->direction; buffer << walkTile->direction;
break; break;
} }
case game::TileType::Decoration: { case game::TileType::Decoration: {
const game::DecorationTile* decoTile = dynamic_cast<const game::DecorationTile*>(tile.get()); const game::DecorationTile* decoTile = dynamic_cast<const game::DecorationTile*>(tile.get());
buffer << decoTile->color_palette_ref; buffer << decoTile->color_palette_ref;
break; break;
} }
default: default:
break; break;
} }
return buffer; return buffer;
} }
static DataBuffer& operator>>(DataBuffer& buffer, game::TilePtr& tile) { static DataBuffer& operator>>(DataBuffer& buffer, game::TilePtr& tile) {
game::TileType tileType; game::TileType tileType;
buffer >> tileType; buffer >> tileType;
switch (tileType) { switch (tileType) {
case game::TileType::Tower: { case game::TileType::Tower: {
auto tilePtr = std::make_shared<game::TowerTile>(); auto tilePtr = std::make_shared<game::TowerTile>();
buffer >> tilePtr->color_palette_ref >> tilePtr->team_owner; buffer >> tilePtr->color_palette_ref >> tilePtr->team_owner;
tile = tilePtr; tile = tilePtr;
break; break;
} }
case game::TileType::Walk: { case game::TileType::Walk: {
auto tilePtr = std::make_shared<game::WalkableTile>(); auto tilePtr = std::make_shared<game::WalkableTile>();
buffer >> tilePtr->direction; buffer >> tilePtr->direction;
tile = tilePtr; tile = tilePtr;
break; break;
} }
case game::TileType::Decoration: { case game::TileType::Decoration: {
auto tilePtr = std::make_shared<game::DecorationTile>(); auto tilePtr = std::make_shared<game::DecorationTile>();
buffer >> tilePtr->color_palette_ref; buffer >> tilePtr->color_palette_ref;
tile = tilePtr; tile = tilePtr;
break; break;
} }
default: default:
break; break;
} }
return buffer; return buffer;
} }
DataBuffer PlayerLoginPacket::Serialize(bool packetID) const { DataBuffer PlayerLoginPacket::Serialize(bool packetID) const {
DataBuffer data; DataBuffer data;
WritePacketID(data, packetID); WritePacketID(data, packetID);
data << m_PlayerName; data << m_PlayerName;
return data; return data;
} }
void PlayerLoginPacket::Deserialize(DataBuffer& data) { void PlayerLoginPacket::Deserialize(DataBuffer& data) {
data >> m_PlayerName; data >> m_PlayerName;
} }
DataBuffer WorldBeginDataPacket::Serialize(bool packetID) const { DataBuffer WorldBeginDataPacket::Serialize(bool packetID) const {
DataBuffer data; DataBuffer data;
const game::TowerTileColorPalette& towerTilePalette = m_Header.m_World->GetTowerTileColorPalette(); const game::TowerTileColorPalette& towerTilePalette = m_Header.m_World->GetTowerTileColorPalette();
const std::vector<game::Color>& decoTilePalette = m_Header.m_World->GetDecorationPalette(); const std::vector<Color>& decoTilePalette = m_Header.m_World->GetDecorationPalette();
WritePacketID(data, packetID); WritePacketID(data, packetID);
data << towerTilePalette << m_Header.m_World->GetWalkableTileColor() data << towerTilePalette << m_Header.m_World->GetWalkableTileColor()
<< static_cast<std::uint16_t>(decoTilePalette.size()); << static_cast<std::uint16_t>(decoTilePalette.size());
// deco color palette // deco color palette
std::size_t bufferSize = data.GetSize(); std::size_t bufferSize = data.GetSize();
data.Resize(bufferSize + decoTilePalette.size() * sizeof(game::Color)); data.Resize(bufferSize + decoTilePalette.size() * sizeof(Color));
memcpy(reinterpret_cast<std::uint8_t*>(data.data()) + bufferSize, decoTilePalette.data(), decoTilePalette.size() * sizeof(game::Color)); memcpy(reinterpret_cast<std::uint8_t*>(data.data()) + bufferSize, decoTilePalette.data(), decoTilePalette.size() * sizeof(Color));
data << m_Header.m_World->GetBackgroundColor(); data << m_Header.m_World->GetBackgroundColor();
const game::Spawn& redSpawn = m_Header.m_World->GetRedTeam().GetSpawn(), blueSpawn = m_Header.m_World->GetBlueTeam().GetSpawn(); const game::Spawn& redSpawn = m_Header.m_World->GetRedTeam().GetSpawn(), blueSpawn = m_Header.m_World->GetBlueTeam().GetSpawn();
const game::TeamCastle& redCastle = m_Header.m_World->GetRedTeam().GetCastle(), blueCastle = m_Header.m_World->GetBlueTeam().GetCastle(); const game::TeamCastle& redCastle = m_Header.m_World->GetRedTeam().GetCastle(), blueCastle = m_Header.m_World->GetBlueTeam().GetCastle();
data << redSpawn << static_cast<utils::shape::Rectangle>(redCastle); data << redSpawn << static_cast<utils::shape::Rectangle>(redCastle);
data << blueSpawn << static_cast<utils::shape::Rectangle>(blueCastle); data << blueSpawn << static_cast<utils::shape::Rectangle>(blueCastle);
// tile palette // tile palette
data << static_cast<std::uint64_t>(m_Header.m_World->GetTilePalette().size()); data << static_cast<std::uint64_t>(m_Header.m_World->GetTilePalette().size());
for (game::TilePtr tile : m_Header.m_World->GetTilePalette()) { for (game::TilePtr tile : m_Header.m_World->GetTilePalette()) {
data << tile; data << tile;
} }
data << m_Header.m_World->GetSpawnColors(); data << m_Header.m_World->GetSpawnColors();
return data; return data;
} }
void WorldBeginDataPacket::Deserialize(DataBuffer& data) { void WorldBeginDataPacket::Deserialize(DataBuffer& data) {
data >> m_Header.m_TowerPlacePalette >> m_Header.m_WalkablePalette; data >> m_Header.m_TowerPlacePalette >> m_Header.m_WalkablePalette;
std::uint16_t decoPaletteSize; std::uint16_t decoPaletteSize;
data >> decoPaletteSize; data >> decoPaletteSize;
std::size_t decoPalletteSizeByte = decoPaletteSize * sizeof(game::Color); std::size_t decoPalletteSizeByte = decoPaletteSize * sizeof(Color);
m_Header.m_DecorationPalette.resize(decoPaletteSize); m_Header.m_DecorationPalette.resize(decoPaletteSize);
memcpy(reinterpret_cast<std::uint8_t*>(m_Header.m_DecorationPalette.data()), data.data() + data.GetReadOffset(), decoPalletteSizeByte); memcpy(reinterpret_cast<std::uint8_t*>(m_Header.m_DecorationPalette.data()), data.data() + data.GetReadOffset(), decoPalletteSizeByte);
data.SetReadOffset(data.GetReadOffset() + decoPalletteSizeByte); data.SetReadOffset(data.GetReadOffset() + decoPalletteSizeByte);
data >> m_Header.m_Background; data >> m_Header.m_Background;
utils::shape::Rectangle redCastle, blueCastle; utils::shape::Rectangle redCastle, blueCastle;
data >> m_Header.m_RedSpawn >> redCastle; data >> m_Header.m_RedSpawn >> redCastle;
data >> m_Header.m_BlueSpawn >> blueCastle; data >> m_Header.m_BlueSpawn >> blueCastle;
m_Header.m_RedCastle.SetShape(redCastle); m_Header.m_RedCastle.SetShape(redCastle);
m_Header.m_BlueCastle.SetShape(blueCastle); m_Header.m_BlueCastle.SetShape(blueCastle);
std::uint64_t tilePaletteSize; std::uint64_t tilePaletteSize;
data >> tilePaletteSize; data >> tilePaletteSize;
m_Header.m_TilePalette.reserve(tilePaletteSize); m_Header.m_TilePalette.reserve(tilePaletteSize);
for (std::uint64_t tileNumber = 0; tileNumber < tilePaletteSize; tileNumber++) { for (std::uint64_t tileNumber = 0; tileNumber < tilePaletteSize; tileNumber++) {
game::TilePtr tile; game::TilePtr tile;
data >> tile; data >> tile;
m_Header.m_TilePalette.push_back(tile); m_Header.m_TilePalette.push_back(tile);
} }
data >> m_Header.m_SpawnColorPalette; data >> m_Header.m_SpawnColorPalette;
} }
typedef std::vector<uint64_t> ChunkPackedData; typedef std::vector<uint64_t> ChunkPackedData;
DataBuffer WorldDataPacket::Serialize(bool packetID) const { DataBuffer WorldDataPacket::Serialize(bool packetID) const {
DataBuffer data; DataBuffer data;
WritePacketID(data, packetID); WritePacketID(data, packetID);
data << m_World->GetChunks().size(); data << m_World->GetChunks().size();
for (const auto& pair : m_World->GetChunks()) { for (const auto& pair : m_World->GetChunks()) {
game::ChunkCoord coords = pair.first; game::ChunkCoord coords = pair.first;
game::ChunkPtr chunk = pair.second; game::ChunkPtr chunk = pair.second;
data << coords.x << coords.y << static_cast<std::uint64_t>(chunk->palette.size()); data << coords.x << coords.y << static_cast<std::uint64_t>(chunk->palette.size());
std::size_t bufferSize = data.GetSize(); std::size_t bufferSize = data.GetSize();
data.Resize(data.GetSize() + chunk->palette.size() * sizeof(game::ChunkPalette::value_type)); data.Resize(data.GetSize() + chunk->palette.size() * sizeof(game::ChunkPalette::value_type));
memcpy(reinterpret_cast<std::uint8_t*>(data.data()) + bufferSize, chunk->palette.data(), chunk->palette.size() * sizeof(game::ChunkPalette::value_type)); memcpy(reinterpret_cast<std::uint8_t*>(data.data()) + bufferSize, chunk->palette.data(), chunk->palette.size() * sizeof(game::ChunkPalette::value_type));
std::uint8_t bitsPerTile = countBits(chunk->palette.size()); std::uint8_t bitsPerTile = countBits(chunk->palette.size());
game::Chunk::ChunkData::value_type individualValueMask = ((1 << bitsPerTile) - 1); game::Chunk::ChunkData::value_type individualValueMask = ((1 << bitsPerTile) - 1);
ChunkPackedData chunkData(game::Chunk::ChunkSize / (BITS_IN_BYTE * sizeof(ChunkPackedData::value_type) / bitsPerTile), 0); ChunkPackedData chunkData(game::Chunk::ChunkSize / (BITS_IN_BYTE * sizeof(ChunkPackedData::value_type) / bitsPerTile), 0);
for (unsigned int tileNumber = 0; tileNumber < game::Chunk::ChunkSize; tileNumber++) { for (unsigned int tileNumber = 0; tileNumber < game::Chunk::ChunkSize; tileNumber++) {
std::size_t startLong = static_cast<std::size_t>((tileNumber * bitsPerTile) / BITS_IN_LONG); std::size_t startLong = static_cast<std::size_t>((tileNumber * bitsPerTile) / BITS_IN_LONG);
std::size_t startOffset = static_cast<std::size_t>((tileNumber * bitsPerTile) % BITS_IN_LONG); std::size_t startOffset = static_cast<std::size_t>((tileNumber * bitsPerTile) % BITS_IN_LONG);
std::size_t endLong = static_cast<std::size_t>(((tileNumber + 1) * bitsPerTile - 1) / BITS_IN_LONG); std::size_t endLong = static_cast<std::size_t>(((tileNumber + 1) * bitsPerTile - 1) / BITS_IN_LONG);
std::uint64_t value = static_cast<std::uint64_t>(chunk->tiles[tileNumber]); std::uint64_t value = static_cast<std::uint64_t>(chunk->tiles[tileNumber]);
value &= individualValueMask; value &= individualValueMask;
chunkData[startLong] |= (value << startOffset); chunkData[startLong] |= (value << startOffset);
if (startLong != endLong) { if (startLong != endLong) {
chunkData[endLong] = (value >> (BITS_IN_LONG - startOffset)); chunkData[endLong] = (value >> (BITS_IN_LONG - startOffset));
} }
} }
bufferSize = data.GetSize(); bufferSize = data.GetSize();
data.Resize(data.GetSize() + chunkData.size() * sizeof(ChunkPackedData::value_type)); data.Resize(data.GetSize() + chunkData.size() * sizeof(ChunkPackedData::value_type));
memcpy(reinterpret_cast<std::uint8_t*>(data.data()) + bufferSize, chunkData.data(), chunkData.size() * sizeof(ChunkPackedData::value_type)); memcpy(reinterpret_cast<std::uint8_t*>(data.data()) + bufferSize, chunkData.data(), chunkData.size() * sizeof(ChunkPackedData::value_type));
} }
return data; return data;
} }
void WorldDataPacket::Deserialize(DataBuffer& data) { void WorldDataPacket::Deserialize(DataBuffer& data) {
std::uint64_t chunkCount; std::uint64_t chunkCount;
data >> chunkCount; data >> chunkCount;
for (std::uint64_t chunkNumber = 0; chunkNumber < chunkCount; chunkNumber++) { for (std::uint64_t chunkNumber = 0; chunkNumber < chunkCount; chunkNumber++) {
game::ChunkPtr chunk = std::make_shared<game::Chunk>(); game::ChunkPtr chunk = std::make_shared<game::Chunk>();
decltype(game::ChunkCoord::x) chunkX, chunkY; decltype(game::ChunkCoord::x) chunkX, chunkY;
data >> chunkX >> chunkY; data >> chunkX >> chunkY;
std::uint64_t chunkPaletteSize; std::uint64_t chunkPaletteSize;
data >> chunkPaletteSize; data >> chunkPaletteSize;
game::ChunkPalette chunkPalette(chunkPaletteSize); game::ChunkPalette chunkPalette(chunkPaletteSize);
memcpy(reinterpret_cast<void*>(chunkPalette.data()), data.data() + data.GetReadOffset(), chunkPaletteSize * sizeof(game::ChunkPalette::value_type)); memcpy(reinterpret_cast<void*>(chunkPalette.data()), data.data() + data.GetReadOffset(), chunkPaletteSize * sizeof(game::ChunkPalette::value_type));
data.SetReadOffset(data.GetReadOffset() + chunkPaletteSize * sizeof(game::ChunkPalette::value_type)); data.SetReadOffset(data.GetReadOffset() + chunkPaletteSize * sizeof(game::ChunkPalette::value_type));
chunk->palette = chunkPalette; chunk->palette = chunkPalette;
std::uint8_t bitsPerTile = countBits(chunkPaletteSize); std::uint8_t bitsPerTile = countBits(chunkPaletteSize);
// A bitmask that contains bitsPerTile set bits // A bitmask that contains bitsPerTile set bits
game::Chunk::ChunkData::value_type individualValueMask = ((1 << bitsPerTile) - 1); game::Chunk::ChunkData::value_type individualValueMask = ((1 << bitsPerTile) - 1);
ChunkPackedData chunkData(game::Chunk::ChunkSize / (BITS_IN_BYTE * sizeof(ChunkPackedData::value_type) / bitsPerTile), 0); ChunkPackedData chunkData(game::Chunk::ChunkSize / (BITS_IN_BYTE * sizeof(ChunkPackedData::value_type) / bitsPerTile), 0);
memcpy(reinterpret_cast<void*>(chunkData.data()), data.data() + data.GetReadOffset(), chunkData.size() * sizeof(ChunkPackedData::value_type)); memcpy(reinterpret_cast<void*>(chunkData.data()), data.data() + data.GetReadOffset(), chunkData.size() * sizeof(ChunkPackedData::value_type));
data.SetReadOffset(data.GetReadOffset() + chunkData.size() * sizeof(ChunkPackedData::value_type)); data.SetReadOffset(data.GetReadOffset() + chunkData.size() * sizeof(ChunkPackedData::value_type));
for (unsigned int tileNumber = 0; tileNumber < game::Chunk::ChunkSize; tileNumber++) { for (unsigned int tileNumber = 0; tileNumber < game::Chunk::ChunkSize; tileNumber++) {
std::size_t startLong = (tileNumber * bitsPerTile) / BITS_IN_LONG; std::size_t startLong = (tileNumber * bitsPerTile) / BITS_IN_LONG;
std::size_t startOffset = (tileNumber * bitsPerTile) % BITS_IN_LONG; std::size_t startOffset = (tileNumber * bitsPerTile) % BITS_IN_LONG;
std::size_t endLong = ((tileNumber + 1) * bitsPerTile - 1) / BITS_IN_LONG; std::size_t endLong = ((tileNumber + 1) * bitsPerTile - 1) / BITS_IN_LONG;
game::Chunk::ChunkData::value_type value; game::Chunk::ChunkData::value_type value;
if (startLong == endLong) { if (startLong == endLong) {
value = (chunkData[startLong] >> startOffset); value = (chunkData[startLong] >> startOffset);
} else { } else {
int endOffset = BITS_IN_LONG - startOffset; int endOffset = BITS_IN_LONG - startOffset;
value = (chunkData[startLong] >> startOffset | chunkData[endLong] << endOffset); value = (chunkData[startLong] >> startOffset | chunkData[endLong] << endOffset);
} }
value &= individualValueMask; value &= individualValueMask;
chunk->tiles[tileNumber] = value; chunk->tiles[tileNumber] = value;
} }
m_WorldData.m_Chunks.insert({ {chunkX, chunkY}, chunk }); m_WorldData.m_Chunks.insert({ {chunkX, chunkY}, chunk });
} }
} }
DataBuffer KeepAlivePacket::Serialize(bool packetID) const { DataBuffer KeepAlivePacket::Serialize(bool packetID) const {
DataBuffer data; DataBuffer data;
WritePacketID(data, packetID); WritePacketID(data, packetID);
data << m_AliveID; data << m_AliveID;
return data; return data;
} }
void KeepAlivePacket::Deserialize(DataBuffer& data) { void KeepAlivePacket::Deserialize(DataBuffer& data) {
data >> m_AliveID; data >> m_AliveID;
} }
DataBuffer UpdateMoneyPacket::Serialize(bool packetID) const { DataBuffer UpdateMoneyPacket::Serialize(bool packetID) const {
DataBuffer data; DataBuffer data;
WritePacketID(data, packetID); WritePacketID(data, packetID);
data << m_NewAmount; data << m_NewAmount;
return data; return data;
} }
void UpdateMoneyPacket::Deserialize(DataBuffer& data) { void UpdateMoneyPacket::Deserialize(DataBuffer& data) {
data >> m_NewAmount; data >> m_NewAmount;
} }
DataBuffer UpdateExpPacket::Serialize(bool packetID) const { DataBuffer UpdateExpPacket::Serialize(bool packetID) const {
DataBuffer data; DataBuffer data;
WritePacketID(data, packetID); WritePacketID(data, packetID);
data << m_NewAmount; data << m_NewAmount;
return data; return data;
} }
void UpdateExpPacket::Deserialize(DataBuffer& data) { void UpdateExpPacket::Deserialize(DataBuffer& data) {
data >> m_NewAmount; data >> m_NewAmount;
} }
DataBuffer UpdateLobbyTimePacket::Serialize(bool packetID) const { DataBuffer UpdateLobbyTimePacket::Serialize(bool packetID) const {
DataBuffer data; DataBuffer data;
WritePacketID(data, packetID); WritePacketID(data, packetID);
data << m_RemainingTime; data << m_RemainingTime;
return data; return data;
} }
void UpdateLobbyTimePacket::Deserialize(DataBuffer& data) { void UpdateLobbyTimePacket::Deserialize(DataBuffer& data) {
data >> m_RemainingTime; data >> m_RemainingTime;
} }
DataBuffer UpdateGameStatePacket::Serialize(bool packetID) const { DataBuffer UpdateGameStatePacket::Serialize(bool packetID) const {
DataBuffer data; DataBuffer data;
WritePacketID(data, packetID); WritePacketID(data, packetID);
data << m_GameState; data << m_GameState;
return data; return data;
} }
void UpdateGameStatePacket::Deserialize(DataBuffer& data) { void UpdateGameStatePacket::Deserialize(DataBuffer& data) {
data >> m_GameState; data >> m_GameState;
} }
DataBuffer PlayerListPacket::Serialize(bool packetID) const { DataBuffer PlayerListPacket::Serialize(bool packetID) const {
DataBuffer data; DataBuffer data;
WritePacketID(data, packetID); WritePacketID(data, packetID);
data << static_cast<std::uint8_t>(m_Players.size()); data << static_cast<std::uint8_t>(m_Players.size());
for (auto [playerID, playerInfo] : m_Players) { for (auto [playerID, playerInfo] : m_Players) {
data << playerID << playerInfo.name << playerInfo.team; data << playerID << playerInfo.name << playerInfo.team;
} }
return data; return data;
} }
void PlayerListPacket::Deserialize(DataBuffer& data) { void PlayerListPacket::Deserialize(DataBuffer& data) {
std::uint8_t playerCount; std::uint8_t playerCount;
data >> playerCount; data >> playerCount;
for (int i = 0; i < playerCount; i++) { for (int i = 0; i < playerCount; i++) {
std::uint8_t playerID; std::uint8_t playerID;
PlayerInfo playerInfo; PlayerInfo playerInfo;
data >> playerID >> playerInfo.name >> playerInfo.team; data >> playerID >> playerInfo.name >> playerInfo.team;
m_Players.insert({ playerID, playerInfo }); m_Players.insert({ playerID, playerInfo });
} }
} }
DataBuffer PlayerJoinPacket::Serialize(bool packetID) const { DataBuffer PlayerJoinPacket::Serialize(bool packetID) const {
DataBuffer data; DataBuffer data;
WritePacketID(data, packetID); WritePacketID(data, packetID);
data << m_PlayerID << m_PlayerName; data << m_PlayerID << m_PlayerName;
return data; return data;
} }
void PlayerJoinPacket::Deserialize(DataBuffer& data) { void PlayerJoinPacket::Deserialize(DataBuffer& data) {
data >> m_PlayerID >> m_PlayerName; data >> m_PlayerID >> m_PlayerName;
} }
DataBuffer PlayerLeavePacket::Serialize(bool packetID) const { DataBuffer PlayerLeavePacket::Serialize(bool packetID) const {
DataBuffer data; DataBuffer data;
WritePacketID(data, packetID); WritePacketID(data, packetID);
data << m_PlayerID; data << m_PlayerID;
return data; return data;
} }
void PlayerLeavePacket::Deserialize(DataBuffer& data) { void PlayerLeavePacket::Deserialize(DataBuffer& data) {
data >> m_PlayerID; data >> m_PlayerID;
} }
DataBuffer ConnexionInfoPacket::Serialize(bool packetID) const { DataBuffer ConnexionInfoPacket::Serialize(bool packetID) const {
DataBuffer data; DataBuffer data;
WritePacketID(data, packetID); WritePacketID(data, packetID);
data << m_ConnectionID; data << m_ConnectionID;
return data; return data;
} }
void ConnexionInfoPacket::Deserialize(DataBuffer& data) { void ConnexionInfoPacket::Deserialize(DataBuffer& data) {
data >> m_ConnectionID; data >> m_ConnectionID;
} }
DataBuffer SelectTeamPacket::Serialize(bool packetID) const { DataBuffer SelectTeamPacket::Serialize(bool packetID) const {
DataBuffer data; DataBuffer data;
WritePacketID(data, packetID); WritePacketID(data, packetID);
data << m_SelectedTeam; data << m_SelectedTeam;
return data; return data;
} }
void SelectTeamPacket::Deserialize(DataBuffer& data) { void SelectTeamPacket::Deserialize(DataBuffer& data) {
data >> m_SelectedTeam; data >> m_SelectedTeam;
} }
DataBuffer UpdatePlayerTeamPacket::Serialize(bool packetID) const { DataBuffer UpdatePlayerTeamPacket::Serialize(bool packetID) const {
DataBuffer data; DataBuffer data;
WritePacketID(data, packetID); WritePacketID(data, packetID);
data << m_PlayerID << m_SelectedTeam; data << m_PlayerID << m_SelectedTeam;
return data; return data;
} }
void UpdatePlayerTeamPacket::Deserialize(DataBuffer& data) { void UpdatePlayerTeamPacket::Deserialize(DataBuffer& data) {
data >> m_PlayerID >> m_SelectedTeam; data >> m_PlayerID >> m_SelectedTeam;
} }
DataBuffer DisconnectPacket::Serialize(bool packetID) const { DataBuffer DisconnectPacket::Serialize(bool packetID) const {
DataBuffer data; DataBuffer data;
WritePacketID(data, packetID); WritePacketID(data, packetID);
data << m_Reason; data << m_Reason;
return data; return data;
} }
void DisconnectPacket::Deserialize(DataBuffer& data) { void DisconnectPacket::Deserialize(DataBuffer& data) {
data >> m_Reason; data >> m_Reason;
} }
DataBuffer ServerTpsPacket::Serialize(bool packetID) const { DataBuffer ServerTpsPacket::Serialize(bool packetID) const {
DataBuffer data; DataBuffer data;
WritePacketID(data, packetID); WritePacketID(data, packetID);
data << m_TPS << m_PacketSendTime; data << m_TPS << m_MSPT << m_PacketSendTime;
return data; return data;
} }
void ServerTpsPacket::Deserialize(DataBuffer& data) { void ServerTpsPacket::Deserialize(DataBuffer& data) {
data >> m_TPS >> m_PacketSendTime; data >> m_TPS >> m_MSPT >> m_PacketSendTime;
} }
DataBuffer SpawnMobPacket::Serialize(bool packetID) const { DataBuffer SpawnMobPacket::Serialize(bool packetID) const {
DataBuffer data; DataBuffer data;
WritePacketID(data, packetID); WritePacketID(data, packetID);
data << m_MobID << m_MobType << m_MobLevel << m_MobDirection data << m_MobID << m_MobType << m_MobLevel << m_MobDirection
<< m_Sender << m_MobX << m_MobY; << m_Sender << m_MobX << m_MobY;
return data; return data;
} }
void SpawnMobPacket::Deserialize(DataBuffer& data) { void SpawnMobPacket::Deserialize(DataBuffer& data) {
data >> m_MobID >> m_MobType >> m_MobLevel >> m_MobDirection data >> m_MobID >> m_MobType >> m_MobLevel >> m_MobDirection
>> m_Sender >> m_MobX >> m_MobY; >> m_Sender >> m_MobX >> m_MobY;
} }
DataBuffer PlaceTowerPacket::Serialize(bool packetID) const { DataBuffer PlaceTowerPacket::Serialize(bool packetID) const {
DataBuffer data; DataBuffer data;
WritePacketID(data, packetID); WritePacketID(data, packetID);
data << m_TowerX << m_TowerY << m_TowerType; data << m_TowerX << m_TowerY << m_TowerType;
return data; return data;
} }
void PlaceTowerPacket::Deserialize(DataBuffer& data) { void PlaceTowerPacket::Deserialize(DataBuffer& data) {
data >> m_TowerX >> m_TowerY >> m_TowerType; data >> m_TowerX >> m_TowerY >> m_TowerType;
} }
DataBuffer WorldAddTowerPacket::Serialize(bool packetID) const { DataBuffer WorldAddTowerPacket::Serialize(bool packetID) const {
DataBuffer data; DataBuffer data;
WritePacketID(data, packetID); WritePacketID(data, packetID);
data << m_TowerID << m_TowerX << m_TowerY << m_TowerType << m_Builder; data << m_TowerID << m_TowerX << m_TowerY << m_TowerType << m_Builder;
return data; return data;
} }
void WorldAddTowerPacket::Deserialize(DataBuffer& data) { void WorldAddTowerPacket::Deserialize(DataBuffer& data) {
data >> m_TowerID >> m_TowerX >> m_TowerY >> m_TowerType >> m_Builder; data >> m_TowerID >> m_TowerX >> m_TowerY >> m_TowerType >> m_Builder;
} }
DataBuffer RemoveTowerPacket::Serialize(bool packetID) const { DataBuffer RemoveTowerPacket::Serialize(bool packetID) const {
DataBuffer data; DataBuffer data;
WritePacketID(data, packetID); WritePacketID(data, packetID);
data << m_TowerID; data << m_TowerID;
return data; return data;
} }
void RemoveTowerPacket::Deserialize(DataBuffer& data) { void RemoveTowerPacket::Deserialize(DataBuffer& data) {
data >> m_TowerID; data >> m_TowerID;
} }
DataBuffer SendMobsPacket::Serialize(bool packetID) const { DataBuffer SendMobsPacket::Serialize(bool packetID) const {
DataBuffer data; DataBuffer data;
WritePacketID(data, packetID); WritePacketID(data, packetID);
data << static_cast<std::uint8_t>(m_MobSends.size()); data << static_cast<std::uint8_t>(m_MobSends.size());
data.WriteSome(reinterpret_cast<const std::uint8_t*>(m_MobSends.data()), m_MobSends.size() * sizeof(m_MobSends)); data.WriteSome(reinterpret_cast<const std::uint8_t*>(m_MobSends.data()), m_MobSends.size() * sizeof(m_MobSends));
return data; return data;
} }
void SendMobsPacket::Deserialize(DataBuffer& data) { void SendMobsPacket::Deserialize(DataBuffer& data) {
std::uint8_t mobSendCount; std::uint8_t mobSendCount;
data >> mobSendCount; data >> mobSendCount;
m_MobSends.resize(mobSendCount); m_MobSends.resize(mobSendCount);
data.ReadSome(reinterpret_cast<std::uint8_t*>(m_MobSends.data()), mobSendCount * sizeof(MobSend)); data.ReadSome(reinterpret_cast<std::uint8_t*>(m_MobSends.data()), mobSendCount * sizeof(MobSend));
} }
DataBuffer UpgradeTowerPacket::Serialize(bool packetID) const { DataBuffer UpgradeTowerPacket::Serialize(bool packetID) const {
DataBuffer data; DataBuffer data;
WritePacketID(data, packetID); WritePacketID(data, packetID);
data << m_TowerID << m_TowerLevel; data << m_TowerID << m_TowerLevel;
return data; return data;
} }
void UpgradeTowerPacket::Deserialize(DataBuffer& data) { void UpgradeTowerPacket::Deserialize(DataBuffer& data) {
data >> m_TowerID >> m_TowerLevel; data >> m_TowerID >> m_TowerLevel;
} }
DataBuffer UpdateCastleLifePacket::Serialize(bool packetID) const { DataBuffer UpdateCastleLifePacket::Serialize(bool packetID) const {
DataBuffer data; DataBuffer data;
WritePacketID(data, packetID); WritePacketID(data, packetID);
data << m_CastleLife << m_Team; data << m_CastleLife << m_Team;
return data; return data;
} }
void UpdateCastleLifePacket::Deserialize(DataBuffer& data) { void UpdateCastleLifePacket::Deserialize(DataBuffer& data) {
data >> m_CastleLife >> m_Team; data >> m_CastleLife >> m_Team;
} }
DataBuffer UpdateMobStatesPacket::Serialize(bool packetID) const { DataBuffer UpdateMobStatesPacket::Serialize(bool packetID) const {
DataBuffer data; DataBuffer data;
WritePacketID(data, packetID); WritePacketID(data, packetID);
data << static_cast<std::uint64_t>(m_MobStates.size()); data << static_cast<std::uint64_t>(m_MobStates.size());
data.WriteSome(reinterpret_cast<const std::uint8_t*>(m_MobStates.data()), m_MobStates.size() * sizeof(MobState)); data.WriteSome(reinterpret_cast<const std::uint8_t*>(m_MobStates.data()), m_MobStates.size() * sizeof(MobState));
return data; return data;
} }
void UpdateMobStatesPacket::Deserialize(DataBuffer& data) { void UpdateMobStatesPacket::Deserialize(DataBuffer& data) {
std::uint64_t mobCount; std::uint64_t mobCount;
data >> mobCount; data >> mobCount;
m_MobStates.resize(mobCount); m_MobStates.resize(mobCount);
data.ReadSome(reinterpret_cast<std::uint8_t*>(m_MobStates.data()), mobCount * sizeof(MobState)); data.ReadSome(reinterpret_cast<std::uint8_t*>(m_MobStates.data()), mobCount * sizeof(MobState));
} }
DataBuffer PlayerBuyItemPacket::Serialize(bool packetID) const { DataBuffer PlayerBuyItemPacket::Serialize(bool packetID) const {
DataBuffer data; DataBuffer data;
WritePacketID(data, packetID); WritePacketID(data, packetID);
data << m_ItemType << m_Count; data << m_ItemType << m_Count;
return data; return data;
} }
void PlayerBuyItemPacket::Deserialize(DataBuffer& data) { void PlayerBuyItemPacket::Deserialize(DataBuffer& data) {
data >> m_ItemType >> m_Count; data >> m_ItemType >> m_Count;
} }
DataBuffer PlayerBuyMobUpgradePacket::Serialize(bool packetID) const { DataBuffer PlayerBuyMobUpgradePacket::Serialize(bool packetID) const {
DataBuffer data; DataBuffer data;
WritePacketID(data, packetID); WritePacketID(data, packetID);
data << m_MobType << m_MobLevel; data << m_MobType << m_MobLevel;
return data; return data;
} }
void PlayerBuyMobUpgradePacket::Deserialize(DataBuffer& data) { void PlayerBuyMobUpgradePacket::Deserialize(DataBuffer& data) {
data >> m_MobType >> m_MobLevel; data >> m_MobType >> m_MobLevel;
} }
REGISTER_DISPATCH_CLASS(PlayerLoginPacket) REGISTER_DISPATCH_CLASS(PlayerLoginPacket)

Some files were not shown because too many files have changed in this diff Show More