Compare commits
107 Commits
alpha-0.0.
...
discord
| Author | SHA1 | Date | |
|---|---|---|---|
| 28b8659e16 | |||
| 0b9fc0520e | |||
| c54017c7be | |||
| bbfe341d23 | |||
| 14efe2cc39 | |||
| fcda12e321 | |||
| 1200a6e087 | |||
| 512fb23d0e | |||
| 5a547b6514 | |||
| ed45995645 | |||
| 0b6d826eba | |||
| 6d0c6be166 | |||
| 222b79b40a | |||
| 8f95b1a750 | |||
| 7d30017742 | |||
| 386ea5b6ad | |||
| 8949c37891 | |||
| 019174128c | |||
| 4e8b095e31 | |||
| 0e0368cada | |||
|
|
6e0923ac75 | ||
|
|
bba9ef8219 | ||
| fd2288ac3c | |||
| 660952aed3 | |||
| 243b153309 | |||
| 73fa10d8d6 | |||
| 0b8a7d8db7 | |||
| e2ec9d6a3b | |||
| eb5b3c8ce2 | |||
| ddbba7399d | |||
| 9ce1f4a1a8 | |||
| ea4349af4c | |||
| d6fbb58da8 | |||
| 66376eaeda | |||
| 85eb9bbc32 | |||
| bbb84c0061 | |||
| 2f1161959b | |||
| f506307653 | |||
| 40f0d50991 | |||
| 663ad60ee3 | |||
| 3fbb6acac7 | |||
| 377e98f583 | |||
| ef9712629f | |||
| ed481de03e | |||
| 7d667d9c5e | |||
| 16006adc6e | |||
| 19062b5c77 | |||
| d3c6ff3988 | |||
| 31a0027bfc | |||
| d4b1805998 | |||
| b84f1fd302 | |||
| 98f73f467d | |||
| dc8a4ce947 | |||
| 113a831f39 | |||
| f906aa1bf0 | |||
| 1bbf607b22 | |||
| d5b42caf39 | |||
| d3edc0cb6c | |||
| 87e4e65843 | |||
| 7509cc1bf2 | |||
| 6df59b1487 | |||
| 553b2f6aad | |||
| 916fa0e7c0 | |||
| bc271bc01e | |||
| 97a33e5517 | |||
| bdebabb79e | |||
| 387cff36ad | |||
| 790237a1b5 | |||
| 840d5edbe4 | |||
| 36a9e1921c | |||
| 784c558840 | |||
| 5d366b6f6c | |||
| f70661694b | |||
| 36a1ab0572 | |||
| 409268b604 | |||
| 174d144d26 | |||
| 360258e4cf | |||
| 2148c0050c | |||
| 61166023df | |||
| e7bf22cea6 | |||
| f09f79198d | |||
| 8c19d3cc3c | |||
| 208892d266 | |||
| 4384806cf0 | |||
| 1a091baeaf | |||
| 43f21ffd44 | |||
| 24617c539f | |||
| 4611a198c9 | |||
| d40ffe8f6c | |||
| 384b7ad51e | |||
| fd9b448fa4 | |||
| c4a2b08416 | |||
| a241d7691b | |||
| 0af4cd506c | |||
| 6b5c56b37d | |||
| 1474220a77 | |||
| a802b5cef5 | |||
| 7e91b863da | |||
| 129bb47286 | |||
| e4a9c5f763 | |||
| 78cf2d0f18 | |||
| 00d2b5394f | |||
| 00414abe61 | |||
| cb847d0edd | |||
| 2da0bd9b79 | |||
| cf9633c061 | |||
| 7a6fdc30b6 |
63
include/Defines.h
Normal file
63
include/Defines.h
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 Color = Vec3<unsigned char>;
|
||||||
|
|
||||||
|
} // namespace td
|
||||||
@@ -12,42 +12,58 @@ enum class GameState : std::uint8_t {
|
|||||||
Game,
|
Game,
|
||||||
EndGame,
|
EndGame,
|
||||||
Disconnected,
|
Disconnected,
|
||||||
|
Closed
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::map<std::uint8_t, Player> PlayerList;
|
typedef std::map<std::uint8_t, Player> PlayerList;
|
||||||
|
|
||||||
class Game {
|
class GameListener {
|
||||||
|
public:
|
||||||
|
virtual void OnPlayerJoin(PlayerID player) {}
|
||||||
|
virtual void OnPlayerLeave(PlayerID player) {}
|
||||||
|
|
||||||
|
virtual void OnGameStateUpdate(GameState newState) {}
|
||||||
|
virtual void OnGameBegin() {}
|
||||||
|
virtual void OnGameEnd() {}
|
||||||
|
virtual void OnGameClose() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef utils::ObjectNotifier<GameListener> GameNotifier;
|
||||||
|
|
||||||
|
class Game : public GameNotifier {
|
||||||
protected:
|
protected:
|
||||||
World* m_World;
|
World* m_World;
|
||||||
std::array<Team, 2> 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[(std::uint8_t)TeamColor::Red]; }
|
Team& GetRedTeam() { return m_Teams[static_cast<std::uint8_t>(TeamColor::Red)]; }
|
||||||
const Team& getRedTeam() const { return m_Teams[(std::uint8_t)TeamColor::Red]; }
|
const Team& GetRedTeam() const { return m_Teams[static_cast<std::uint8_t>(TeamColor::Red)]; }
|
||||||
|
|
||||||
Team& getBlueTeam() { return m_Teams[(std::uint8_t)TeamColor::Blue]; }
|
Team& GetBlueTeam() { return m_Teams[static_cast<std::uint8_t>(TeamColor::Blue)]; }
|
||||||
const Team& getBlueTeam() const { return m_Teams[(std::uint8_t)TeamColor::Blue]; }
|
const Team& GetBlueTeam() const { return m_Teams[static_cast<std::uint8_t>(TeamColor::Red)]; }
|
||||||
|
|
||||||
Team& getTeam(TeamColor team) { return m_Teams[(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[(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; };
|
virtual 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 { return m_Players.find(id)->second; }
|
const Player* GetPlayerById(PlayerID id) const;
|
||||||
Player& getPlayerById(PlayerID id) { return m_Players.find(id)->second; }
|
Player* GetPlayerById(PlayerID id);
|
||||||
|
|
||||||
|
const TeamList& GetTeams() const { return m_Teams; }
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -20,14 +20,14 @@ public:
|
|||||||
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);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,12 +10,12 @@
|
|||||||
|
|
||||||
namespace GameManager {
|
namespace GameManager {
|
||||||
|
|
||||||
void render();
|
void Render();
|
||||||
void init();
|
void Init();
|
||||||
void destroy();
|
void Destroy();
|
||||||
void tick();
|
void Tick();
|
||||||
|
|
||||||
void startServer();
|
void StartServer();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,20 @@
|
|||||||
#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"
|
||||||
|
|
||||||
|
#include "misc/ObjectNotifier.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
|
||||||
|
|
||||||
namespace td {
|
namespace td {
|
||||||
namespace game {
|
namespace game {
|
||||||
|
|
||||||
|
struct WalkableTile;
|
||||||
|
|
||||||
enum class EffectType : std::uint8_t {
|
enum class EffectType : std::uint8_t {
|
||||||
Slowness = 0,
|
Slowness = 0,
|
||||||
Stun,
|
Stun,
|
||||||
@@ -44,37 +47,37 @@ 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
|
||||||
const 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);
|
||||||
const TowerImmunities& getMobTowerImmunities(MobType type, std::uint8_t level);
|
const TowerImmunities& GetMobTowerImmunities(MobType type, std::uint8_t level);
|
||||||
const EffectImmunities& getMobEffectImmunities(MobType type, std::uint8_t level);
|
const EffectImmunities& GetMobEffectImmunities(MobType type, std::uint8_t level);
|
||||||
|
|
||||||
class Mob : public utils::shape::Rectangle {
|
class Mob : public utils::shape::Rectangle {
|
||||||
protected:
|
protected:
|
||||||
@@ -86,138 +89,173 @@ private:
|
|||||||
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
|
||||||
bool m_HasReachedCastle; // if true, no need to walk anymore
|
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;
|
||||||
|
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_HasReachedCastle(false), m_EffectFireTimer(1000), m_EffectPoisonTimer(1000),
|
m_HitCooldown(0), m_EffectFireTimer(1000), m_EffectPoisonTimer(1000),
|
||||||
m_EffectHealTimer(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);
|
virtual void Tick(std::uint64_t delta, World* world);
|
||||||
|
|
||||||
virtual bool OnDeath(World* world) { return true; }
|
virtual bool OnDeath(World* world) { return true; }
|
||||||
|
|
||||||
const TowerImmunities& getTowerImmunities() const { return getMobTowerImmunities(getType(), m_Level); }
|
MobID GetMobID() const { return m_ID; }
|
||||||
const EffectImmunities& getEffectImmunities() const { return getMobEffectImmunities(getType(), m_Level); }
|
const TowerImmunities& GetTowerImmunities() const { return GetMobTowerImmunities(GetType(), m_Level); }
|
||||||
PlayerID getSender() const { return m_Sender; }
|
const EffectImmunities& GetEffectImmunities() const { return GetMobEffectImmunities(GetType(), m_Level); }
|
||||||
MobLevel getLevel() const { return m_Level; }
|
PlayerID GetSender() const { return m_Sender; }
|
||||||
const MobStats* getStats() const { return getMobStats(getType(), m_Level); }
|
MobLevel GetLevel() const { return m_Level; }
|
||||||
float getHealth() const { return m_Health; }
|
const MobStats* GetStats() const { return GetMobStats(GetType(), m_Level); }
|
||||||
bool isDead() const { return m_Health <= 0; }
|
void SetHealth(float newHealth) { m_Health = newHealth; }
|
||||||
bool isAlive() const { return m_Health > 0; }
|
float GetHealth() const { return m_Health; }
|
||||||
const Tower* getLastDamageTower() { return m_LastDamage; }
|
bool IsDead() const { return m_Health <= 0; }
|
||||||
bool hasReachedEnemyCastle() { return m_HasReachedCastle; }
|
bool IsAlive() const { return m_Health > 0; }
|
||||||
|
const Tower* GetLastDamageTower() { return m_LastDamage; }
|
||||||
|
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() { m_HasReachedCastle = true; } // 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, const 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);
|
void UpdateEffects(std::uint64_t delta, World* world);
|
||||||
EffectDuration& getEffect(EffectType type);
|
void AttackCastle(std::uint64_t delta, World* world);
|
||||||
|
void Move(std::uint64_t delta, World* world);
|
||||||
|
void Walk(std::uint64_t delta, World* world);
|
||||||
|
void MoveBack(const TeamCastle& castle, World* world);
|
||||||
|
void ChangeDirection(const WalkableTile& tile, World* world);
|
||||||
|
bool IsTouchingCastle(const TeamCastle& castle) const;
|
||||||
|
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 {
|
||||||
MobPtr createMob(MobID id, MobType type, std::uint8_t level, PlayerID sender);
|
|
||||||
std::string getMobName(MobType type);
|
MobPtr CreateMob(MobID id, MobType type, std::uint8_t level, PlayerID sender);
|
||||||
|
std::string GetMobName(MobType type);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class MobListener {
|
||||||
|
public:
|
||||||
|
virtual void OnMobSpawn(Mob* mob) {}
|
||||||
|
virtual void OnMobDie(Mob* mob) {}
|
||||||
|
|
||||||
|
virtual void OnMobDamage(Mob* target, float damage, Tower* damager) {}
|
||||||
|
|
||||||
|
virtual void OnMobTouchCastle(Mob* damager, TeamCastle* enemyCastle) {}
|
||||||
|
virtual void OnMobCastleDamage(Mob* damager, TeamCastle* enemyCastle, float damage) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef utils::ObjectNotifier<MobListener> MobNotifier;
|
||||||
|
|
||||||
} // namespace game
|
} // namespace game
|
||||||
} // namespace td
|
} // namespace td
|
||||||
|
|||||||
@@ -1,56 +1,50 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "game/Team.h"
|
#include "game/Team.h"
|
||||||
|
#include "game/PlayerUpgrades.h"
|
||||||
|
|
||||||
namespace td {
|
namespace td {
|
||||||
namespace game {
|
namespace game {
|
||||||
|
|
||||||
class Player {
|
class Player {
|
||||||
private:
|
private:
|
||||||
game::TeamColor m_TeamColor;
|
TeamColor m_TeamColor;
|
||||||
|
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;
|
||||||
std::uint8_t m_ID;
|
PlayerID m_ID;
|
||||||
|
|
||||||
std::uint8_t m_GoldPerSecond;
|
|
||||||
|
|
||||||
bool m_GoldChanged;
|
|
||||||
bool m_ExpChanged;
|
|
||||||
public:
|
public:
|
||||||
Player(std::uint8_t id = 0) : m_TeamColor(game::TeamColor::None), m_Gold(0), m_Exp(0), m_ID(id), m_GoldPerSecond(5),
|
|
||||||
m_GoldChanged(false), m_ExpChanged(false) {}
|
|
||||||
|
|
||||||
const std::string& getName() const { return m_Name; }
|
Player(std::uint8_t id = 0) : m_TeamColor(TeamColor::None), m_Gold(0), m_Exp(0), m_ID(id) {}
|
||||||
void setName(const std::string& name) { m_Name = name; }
|
|
||||||
|
|
||||||
game::TeamColor getTeamColor() const { return m_TeamColor; }
|
const std::string& GetName() const { return m_Name; }
|
||||||
void setTeamColor(game::TeamColor teamColor) { m_TeamColor = teamColor; }
|
void SetName(const std::string& name) { m_Name = name; }
|
||||||
|
|
||||||
std::uint8_t getGoldPerSecond() const { return m_GoldPerSecond; }
|
TeamColor GetTeamColor() const { return m_TeamColor; }
|
||||||
void setGoldPerSecond(std::uint8_t goldPerSecond) { m_GoldPerSecond = goldPerSecond; }
|
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_GoldChanged = true; m_Gold = gold; }
|
void SetGold(std::uint32_t gold) { m_Gold = gold; }
|
||||||
void addGold(std::uint32_t gold) { m_GoldChanged = true; m_Gold += gold; }
|
void AddGold(std::uint32_t gold) { m_Gold += gold; }
|
||||||
void removeGold(std::uint32_t gold) { m_GoldChanged = true; 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_ExpChanged = true; m_Exp = exp; }
|
void SetExp(std::uint32_t exp) { m_Exp = exp; }
|
||||||
void addExp(std::uint32_t exp) { m_ExpChanged = true; m_Exp += exp; }
|
void AddExp(std::uint32_t exp) { m_Exp += exp; }
|
||||||
void removeExp(std::uint32_t exp) { m_ExpChanged = true; m_Exp -= exp; }
|
void RemoveExp(std::uint32_t exp) { m_Exp -= exp; }
|
||||||
|
|
||||||
bool hasGoldChanged() const { return m_GoldChanged; }
|
const PlayerUpgrades& getUpgrades() const { return m_Upgrades; }
|
||||||
bool hasExpChanged() const { return m_ExpChanged; }
|
PlayerUpgrades& getUpgrades() { return m_Upgrades; }
|
||||||
|
|
||||||
void updateGold() { m_GoldChanged = false; }
|
bool HasEnoughGold(std::uint32_t gold) const { return m_Gold >= gold; }
|
||||||
void updateExp() { m_ExpChanged = false; }
|
bool HasEnoughExp(std::uint32_t exp) const { return m_Exp >= exp; }
|
||||||
|
|
||||||
std::uint8_t getID() const { return m_ID; }
|
PlayerID GetID() const { return m_ID; }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace game
|
} // namespace game
|
||||||
|
|||||||
34
include/game/PlayerUpgrades.h
Normal file
34
include/game/PlayerUpgrades.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Mobs.h"
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace game {
|
||||||
|
|
||||||
|
class PlayerUpgrades {
|
||||||
|
private:
|
||||||
|
std::uint8_t m_ClickerLevel;
|
||||||
|
std::uint8_t m_GoldPerSecond;
|
||||||
|
std::array<std::uint8_t, static_cast<std::size_t>(MobType::MOB_COUNT)> m_MobsUpgradeLevel;
|
||||||
|
public:
|
||||||
|
static const int MAX_MOB_LEVEL = 5;
|
||||||
|
static const int MAX_CLICKER_LEVEL = 3;
|
||||||
|
|
||||||
|
PlayerUpgrades() : m_ClickerLevel(1), m_GoldPerSecond(5) {}
|
||||||
|
|
||||||
|
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 GetGoldPerSecond() const { return m_GoldPerSecond; }
|
||||||
|
|
||||||
|
|
||||||
|
void UpgradeMob(MobType mob) {
|
||||||
|
std::uint8_t& mobLevel = m_MobsUpgradeLevel.at(static_cast<std::size_t>(mob));
|
||||||
|
mobLevel = std::min(mobLevel + 1, MAX_MOB_LEVEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpgradeClicker() { m_ClickerLevel = std::min(m_ClickerLevel + 1, MAX_CLICKER_LEVEL); }
|
||||||
|
void SetGoldPerSecond(std::uint8_t goldPerSecond) { m_GoldPerSecond = goldPerSecond; }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace game
|
||||||
|
} // namespace td
|
||||||
@@ -23,29 +23,44 @@ 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; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TeamCastle : public utils::shape::Rectangle{
|
class Team;
|
||||||
|
|
||||||
|
class TeamCastle : public utils::shape::Rectangle {
|
||||||
private:
|
private:
|
||||||
|
const Team* m_Team;
|
||||||
float m_Life;
|
float m_Life;
|
||||||
public:
|
public:
|
||||||
TeamCastle() : m_Life(1000) {
|
static constexpr int CastleMaxLife = 1000;
|
||||||
setWidth(5);
|
|
||||||
setHeight(5);
|
TeamCastle(const Team* team) : m_Team(team), m_Life(CastleMaxLife) {
|
||||||
|
SetWidth(5);
|
||||||
|
SetHeight(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
float getLife() const { return m_Life; }
|
TeamCastle() : TeamCastle(nullptr) {}
|
||||||
|
|
||||||
void setLife(float life) { m_Life = life; }
|
float GetLife() const { return m_Life; }
|
||||||
void damage(float damage) { m_Life = std::max(0.0f, m_Life - damage); }
|
|
||||||
|
const Team* GetTeam() const { return m_Team; }
|
||||||
|
void SetTeam(const Team* team) { m_Team = team; }
|
||||||
|
|
||||||
|
void SetLife(float life) { m_Life = life; }
|
||||||
|
void Damage(float damage) { m_Life = std::max(0.0f, m_Life - damage); }
|
||||||
|
|
||||||
|
void SetShape(utils::shape::Rectangle rect) {
|
||||||
|
SetCenter(rect.GetCenter());
|
||||||
|
SetSize(rect.GetSize());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class Team {
|
class Team {
|
||||||
@@ -57,19 +72,21 @@ private:
|
|||||||
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;
|
||||||
|
|
||||||
} // namespace game
|
} // namespace game
|
||||||
} // namespace td
|
} // namespace td
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@@ -55,9 +54,9 @@ public:
|
|||||||
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 {
|
||||||
@@ -70,20 +69,20 @@ 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);
|
||||||
|
|
||||||
typedef std::uint16_t TowerID;
|
typedef std::uint16_t TowerID;
|
||||||
|
|
||||||
@@ -97,36 +96,36 @@ 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;
|
||||||
|
|
||||||
namespace TowerFactory {
|
namespace TowerFactory {
|
||||||
|
|
||||||
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);
|
||||||
std::string getTowerName(TowerType type);
|
std::string GetTowerName(TowerType type);
|
||||||
|
|
||||||
} // namespace TowerFactory
|
} // namespace TowerFactory
|
||||||
|
|
||||||
@@ -137,15 +136,16 @@ private:
|
|||||||
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);
|
||||||
|
|
||||||
// ---------- Little Towers ----------
|
// ---------- Little Towers ----------
|
||||||
|
|
||||||
@@ -153,76 +153,77 @@ 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;
|
||||||
|
|
||||||
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 ----------
|
||||||
@@ -231,34 +232,34 @@ 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
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
// include Log for every files
|
||||||
|
#include "misc/Log.h"
|
||||||
|
|
||||||
namespace td {
|
namespace td {
|
||||||
namespace game {
|
namespace game {
|
||||||
|
|
||||||
|
|||||||
@@ -4,33 +4,37 @@
|
|||||||
#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"
|
||||||
#include "Team.h"
|
#include "Team.h"
|
||||||
|
|
||||||
#include "misc/ObjectNotifier.h"
|
|
||||||
|
|
||||||
namespace td {
|
namespace td {
|
||||||
namespace game {
|
namespace game {
|
||||||
typedef std::pair<std::int16_t, std::int16_t> ChunkCoord;
|
|
||||||
|
struct ChunkCoord {
|
||||||
|
std::int16_t x, y;
|
||||||
|
|
||||||
|
friend bool operator==(const td::game::ChunkCoord& first, const td::game::ChunkCoord& other) {
|
||||||
|
return first.x == other.x && first.y == other.y;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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 {
|
std::size_t operator()(const td::game::ChunkCoord& key) const noexcept {
|
||||||
// Compute individual hash values for first,
|
return std::hash<std::int16_t>()(key.x << 16 | key.y);
|
||||||
// second and third and combine them using XOR
|
|
||||||
// and bit shifting:
|
|
||||||
return ((std::hash<std::int16_t>()(key.first) ^ (std::hash<std::int16_t>()(key.second) << 1)) >> 1);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace td {
|
namespace td {
|
||||||
|
|
||||||
namespace protocol {
|
namespace protocol {
|
||||||
|
|
||||||
class WorldBeginDataPacket;
|
class WorldBeginDataPacket;
|
||||||
@@ -54,31 +58,34 @@ enum class TileType : std::uint8_t {
|
|||||||
Ice,*/
|
Ice,*/
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Color {
|
static constexpr Color BLACK{ 0, 0, 0 };
|
||||||
std::uint8_t r, g, b;
|
static constexpr Color WHITE{ 255, 255, 255 };
|
||||||
};
|
|
||||||
|
static constexpr Color RED{ 255, 0, 0 };
|
||||||
|
static constexpr Color GREEN{ 0, 255, 0 };
|
||||||
|
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;
|
||||||
@@ -86,17 +93,18 @@ typedef std::vector<std::uint16_t> ChunkPalette;
|
|||||||
|
|
||||||
typedef std::shared_ptr<WalkableTile> WalkableTilePtr;
|
typedef std::shared_ptr<WalkableTile> WalkableTilePtr;
|
||||||
|
|
||||||
typedef std::array<std::uint16_t, 32 * 32> ChunkData;
|
|
||||||
typedef std::uint32_t TileIndex;
|
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;
|
||||||
|
|
||||||
// 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;
|
||||||
@@ -118,25 +126,25 @@ typedef std::vector<TowerPtr> TowerList;
|
|||||||
|
|
||||||
class WorldListener {
|
class WorldListener {
|
||||||
public:
|
public:
|
||||||
WorldListener(){}
|
WorldListener() {}
|
||||||
|
|
||||||
virtual void OnArcherTowerShot(MobPtr target, ArcherTower* shooter){}
|
virtual void OnTowerAdd(TowerPtr tower) {}
|
||||||
|
virtual void OnTowerRemove(TowerPtr tower) {}
|
||||||
|
|
||||||
virtual void OnArrowShot(MobPtr target, Tower* shooter){}
|
virtual void OnArcherTowerShot(MobPtr target, ArcherTower* shooter) {}
|
||||||
virtual void OnExplosion(utils::shape::Circle explosion, float centerDamage, Tower* shooter){}
|
|
||||||
|
|
||||||
virtual void OnMobDamage(MobPtr target, float damage, Tower* damager){}
|
virtual void OnArrowShot(MobPtr target, bool fire, Tower* shooter) {}
|
||||||
|
virtual void OnExplosion(utils::shape::Circle explosion, float centerDamage, Tower* shooter) {}
|
||||||
virtual void OnMobDead(MobPtr mob){}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef utils::ObjectNotifier<WorldListener> WorldNotifier;
|
typedef utils::ObjectNotifier<WorldListener> WorldNotifier;
|
||||||
|
|
||||||
class World : public WorldNotifier, public WorldListener{
|
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;
|
||||||
|
|
||||||
std::unordered_map<ChunkCoord, ChunkPtr> m_Chunks;
|
std::unordered_map<ChunkCoord, ChunkPtr> m_Chunks;
|
||||||
|
|
||||||
@@ -149,80 +157,88 @@ protected:
|
|||||||
TowerList m_Towers;
|
TowerList m_Towers;
|
||||||
|
|
||||||
Game* m_Game;
|
Game* m_Game;
|
||||||
|
|
||||||
|
WorldNotifier m_WorldNotifier;
|
||||||
|
MobNotifier m_MobNotifier;
|
||||||
public:
|
public:
|
||||||
World(Game* game);
|
World(Game* game);
|
||||||
|
|
||||||
static constexpr std::uint8_t CastleWidth = 5, CastleHeight = 5;
|
bool LoadMap(const protocol::WorldBeginDataPacket* worldHeader);
|
||||||
|
bool LoadMap(const protocol::WorldDataPacket* worldData);
|
||||||
|
|
||||||
bool loadMap(const protocol::WorldBeginDataPacket* worldHeader);
|
bool LoadMapFromFile(const std::string& fileName);
|
||||||
bool loadMap(const protocol::WorldDataPacket* worldData);
|
bool SaveMap(const std::string& fileName) const;
|
||||||
|
|
||||||
bool loadMapFromFile(const std::string& fileName);
|
void Tick(std::uint64_t delta);
|
||||||
bool saveMap(const std::string& fileName) const;
|
|
||||||
|
|
||||||
void tick(std::uint64_t delta);
|
void SpawnMobAt(MobID id, MobType type, std::uint8_t level, PlayerID sender, float x, float y, Direction dir);
|
||||||
|
|
||||||
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 RemoveTower(TowerID id);
|
||||||
|
|
||||||
TowerPtr placeTowerAt(TowerID id, TowerType type, std::int32_t x, std::int32_t y, PlayerID builder);
|
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 Color& GetWalkableTileColor() const { return m_WalkablePalette; }
|
||||||
|
const std::vector<Color>& GetDecorationPalette() const { return m_DecorationPalette; }
|
||||||
|
const Color& GetBackgroundColor() const { return m_Background; }
|
||||||
|
|
||||||
const TowerTileColorPalette& getTowerTileColorPalette() const { return m_TowerPlacePalette; }
|
const TilePalette& GetTilePalette() const { return m_TilePalette; }
|
||||||
const Color& getWalkableTileColor() const { return m_WalkablePalette; }
|
|
||||||
const std::vector<Color>& getDecorationPalette() const { return m_DecorationPalette; }
|
|
||||||
|
|
||||||
const TilePalette& getTilePalette() const { return m_TilePalette; }
|
TilePtr GetTilePtr(TileIndex index) const {
|
||||||
|
|
||||||
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[(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 TowerList& getTowers() const { return m_Towers; };
|
const TeamList& GetTeams() const;
|
||||||
TowerPtr getTowerById(TowerID tower);
|
|
||||||
|
const TowerList& GetTowers() const { return m_Towers; }
|
||||||
|
TowerPtr GetTowerById(TowerID tower);
|
||||||
|
|
||||||
|
const Player* GetPlayerById(PlayerID id) const;
|
||||||
|
|
||||||
|
WorldNotifier& GetWorldNotifier() { return m_WorldNotifier; }
|
||||||
|
MobNotifier& GetMobNotifier() { return m_MobNotifier; }
|
||||||
|
|
||||||
// WorldListener
|
// WorldListener
|
||||||
|
|
||||||
virtual void OnArcherTowerShot(MobPtr target, ArcherTower* shooter);
|
virtual void OnArcherTowerShot(MobPtr target, ArcherTower* 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 OnArrowShot(MobPtr target, Tower* shooter);
|
// MobListener
|
||||||
virtual void OnExplosion(utils::shape::Circle explosion, float centerDamage, Tower* shooter);
|
|
||||||
|
virtual void OnMobDamage(Mob* target, float damage, Tower* source) override;
|
||||||
|
virtual void OnMobCastleDamage(Mob* damager, TeamCastle* enemyCastle, float damage) override;
|
||||||
|
|
||||||
virtual void OnMobDamage(MobPtr target, float damage, Tower* source);
|
|
||||||
private:
|
private:
|
||||||
void moveMobs(std::uint64_t delta);
|
void TickMobs(std::uint64_t delta);
|
||||||
void moveMob(MobPtr mob, std::uint64_t delta);
|
void CleanDeadMobs();
|
||||||
void moveBackMob(MobPtr mob, const TeamCastle& castle);
|
|
||||||
void changeMobDirection(MobPtr mob, WalkableTilePtr tile);
|
|
||||||
bool isMobTouchingCastle(MobPtr mob, const TeamCastle& castle) const;
|
|
||||||
void tickMobs(std::uint64_t delta);
|
|
||||||
void cleanDeadMobs();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace game
|
} // namespace game
|
||||||
|
|||||||
@@ -19,31 +19,36 @@ class Client {
|
|||||||
private:
|
private:
|
||||||
render::Renderer* m_Renderer;
|
render::Renderer* m_Renderer;
|
||||||
ClientConnexion m_Connexion;
|
ClientConnexion m_Connexion;
|
||||||
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(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; }
|
||||||
|
|
||||||
void tick(std::uint64_t delta);
|
const game::Player* GetPlayer() { return m_Game->GetPlayer(); }
|
||||||
|
|
||||||
void render();
|
void Tick(std::uint64_t delta);
|
||||||
|
|
||||||
bool connect(const network::IPAddresses& addresses, std::uint16_t port);
|
void Render();
|
||||||
void closeConnection();
|
|
||||||
|
|
||||||
bool isConnected() const { return m_Connexion.getSocketStatus() == network::Socket::Connected; }
|
bool Connect(const network::IPAddresses& addresses, std::uint16_t port);
|
||||||
|
void CloseConnection();
|
||||||
|
|
||||||
void selectTeam(game::TeamColor team);
|
bool IsConnected() const { return m_Connexion.GetSocketStatus() == network::Socket::Connected; }
|
||||||
void sendMobs(const std::vector<protocol::MobSend>& mobSends);
|
|
||||||
void placeTower(game::TowerType type, const glm::vec2& position);
|
void SelectTeam(game::TeamColor team);
|
||||||
void upgradeTower(game::TowerID tower, game::TowerLevel level);
|
void SendMobs(const std::vector<protocol::MobSend>& mobSends);
|
||||||
|
void PlaceTower(game::TowerType type, const Vec2f& position);
|
||||||
|
void UpgradeTower(game::TowerID tower, game::TowerLevel level);
|
||||||
|
void RemoveTower(game::TowerID tower);
|
||||||
|
private:
|
||||||
|
void Reset();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace client
|
} // namespace client
|
||||||
|
|||||||
@@ -12,25 +12,27 @@ 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;
|
||||||
|
float m_ServerMSPT;
|
||||||
int m_Ping = 0;
|
int m_Ping = 0;
|
||||||
public:
|
public:
|
||||||
ClientConnexion();
|
ClientConnexion();
|
||||||
|
|
||||||
virtual bool updateSocket();
|
virtual bool UpdateSocket();
|
||||||
|
|
||||||
virtual void HandlePacket(const protocol::KeepAlivePacket* packet);
|
virtual void HandlePacket(const protocol::KeepAlivePacket* packet) override;
|
||||||
virtual void HandlePacket(const protocol::ConnexionInfoPacket* packet);
|
virtual void HandlePacket(const protocol::ConnexionInfoPacket* packet) override;
|
||||||
virtual void HandlePacket(const protocol::DisconnectPacket* packet);
|
virtual void HandlePacket(const protocol::DisconnectPacket* packet) override;
|
||||||
virtual void HandlePacket(const protocol::ServerTpsPacket* packet);
|
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
|
||||||
|
|||||||
@@ -27,28 +27,32 @@ 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; }
|
||||||
|
|
||||||
|
void SetGameState(game::GameState gameState) override;
|
||||||
|
|
||||||
|
virtual void HandlePacket(const protocol::ConnexionInfoPacket* packet) override;
|
||||||
|
virtual void HandlePacket(const protocol::PlayerJoinPacket* packet) override;
|
||||||
|
virtual void HandlePacket(const protocol::PlayerLeavePacket* packet) override;
|
||||||
|
virtual void HandlePacket(const protocol::PlayerListPacket* packet) override;
|
||||||
|
virtual void HandlePacket(const protocol::UpdatePlayerTeamPacket* packet) override;
|
||||||
|
virtual void HandlePacket(const protocol::UpdateGameStatePacket* packet) override;
|
||||||
|
virtual void HandlePacket(const protocol::UpdateLobbyTimePacket* packet) override;
|
||||||
|
virtual void HandlePacket(const protocol::UpdateMoneyPacket* packet) override;
|
||||||
|
virtual void HandlePacket(const protocol::UpdateExpPacket* packet) override;
|
||||||
|
virtual void HandlePacket(const protocol::DisconnectPacket* packet) override;
|
||||||
|
virtual void HandlePacket(const protocol::WorldDataPacket* packet) override;
|
||||||
|
|
||||||
virtual void HandlePacket(const protocol::ConnexionInfoPacket* packet);
|
|
||||||
virtual void HandlePacket(const protocol::PlayerJoinPacket* packet);
|
|
||||||
virtual void HandlePacket(const protocol::PlayerLeavePacket* packet);
|
|
||||||
virtual void HandlePacket(const protocol::PlayerListPacket* packet);
|
|
||||||
virtual void HandlePacket(const protocol::UpdatePlayerTeamPacket* packet);
|
|
||||||
virtual void HandlePacket(const protocol::UpdateGameStatePacket* packet);
|
|
||||||
virtual void HandlePacket(const protocol::UpdateLobbyTimePacket* packet);
|
|
||||||
virtual void HandlePacket(const protocol::UpdateMoneyPacket* packet);
|
|
||||||
virtual void HandlePacket(const protocol::DisconnectPacket* packet);
|
|
||||||
virtual void HandlePacket(const protocol::WorldDataPacket* packet);
|
|
||||||
virtual void HandlePacket(const protocol::WorldAddTowerPacket* packet);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace client
|
} // namespace client
|
||||||
|
|||||||
@@ -18,8 +18,11 @@ public:
|
|||||||
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::RemoveTowerPacket* packet) override;
|
||||||
|
virtual void HandlePacket(const protocol::UpdateMobStatesPacket* packet) override;
|
||||||
|
virtual void HandlePacket(const protocol::UpdateCastleLifePacket* packet) override;
|
||||||
|
|
||||||
virtual void OnArrowShot(game::MobPtr target, game::Tower* shooter) override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace client
|
} // namespace client
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ public:
|
|||||||
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
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
@@ -23,30 +22,34 @@ typedef std::map<std::uint8_t, ServerConnexion> ConnexionMap;
|
|||||||
class TickCounter {
|
class TickCounter {
|
||||||
private:
|
private:
|
||||||
float m_TPS;
|
float m_TPS;
|
||||||
|
float m_MSPT;
|
||||||
std::uint64_t m_LastTPSTime;
|
std::uint64_t m_LastTPSTime;
|
||||||
std::uint8_t m_TickCount;
|
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 = (float)SERVER_TPS / (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 {
|
||||||
@@ -61,36 +64,38 @@ private:
|
|||||||
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();
|
void Stop(); // force the server to stop
|
||||||
|
void Close(); // at the end of a game
|
||||||
|
|
||||||
void lauchGame();
|
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; }
|
||||||
|
|
||||||
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 startThread();
|
void Clean();
|
||||||
void stopThread();
|
void StartThread();
|
||||||
void tick(std::uint64_t delta);
|
void StopThread();
|
||||||
|
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);
|
||||||
|
|||||||
@@ -11,8 +11,7 @@ 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;
|
||||||
@@ -31,28 +30,29 @@ public:
|
|||||||
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);
|
virtual void HandlePacket(const protocol::PlayerLoginPacket* packet) override;
|
||||||
virtual void HandlePacket(const protocol::KeepAlivePacket* packet);
|
virtual void HandlePacket(const protocol::KeepAlivePacket* packet) override;
|
||||||
virtual void HandlePacket(const protocol::SelectTeamPacket* packet);
|
virtual void HandlePacket(const protocol::SelectTeamPacket* packet) override;
|
||||||
virtual void HandlePacket(const protocol::DisconnectPacket* packet);
|
virtual void HandlePacket(const protocol::DisconnectPacket* packet) override;
|
||||||
virtual void HandlePacket(const protocol::PlaceTowerPacket* packet);
|
virtual void HandlePacket(const protocol::PlaceTowerPacket* packet) override;
|
||||||
virtual void HandlePacket(const protocol::SendMobsPacket* packet);
|
virtual void HandlePacket(const protocol::SendMobsPacket* packet) override;
|
||||||
virtual void HandlePacket(const protocol::UpgradeTowerPacket* packet);
|
virtual void HandlePacket(const protocol::UpgradeTowerPacket* 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
|
||||||
|
|||||||
@@ -9,23 +9,34 @@ namespace server {
|
|||||||
|
|
||||||
class Server;
|
class Server;
|
||||||
|
|
||||||
class ServerGame : public game::Game {
|
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{ 1000, std::bind(&ServerGame::updateGoldMines, this) };
|
utils::AutoTimer m_GoldMineTimer;
|
||||||
|
utils::AutoTimer m_MobStatesTimer;
|
||||||
|
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
|
||||||
|
|
||||||
|
virtual void OnGameStateUpdate(game::GameState newState) override;
|
||||||
|
virtual void OnGameBegin() override;
|
||||||
|
virtual void OnGameEnd() override;
|
||||||
|
virtual void OnGameClose() override;
|
||||||
private:
|
private:
|
||||||
void balanceTeams();
|
void BalanceTeams();
|
||||||
void updateGoldMines();
|
void InitPlayerStats();
|
||||||
void updatePlayerStats();
|
void UpdateMobStates();
|
||||||
|
void UpdateGoldMines();
|
||||||
|
void UpdatePlayerStats();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace game
|
} // namespace game
|
||||||
|
|||||||
@@ -14,12 +14,16 @@ private:
|
|||||||
game::TowerID m_CurrentTowerID;
|
game::TowerID m_CurrentTowerID;
|
||||||
Server* m_Server;
|
Server* m_Server;
|
||||||
public:
|
public:
|
||||||
|
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 OnMobCastleDamage(game::Mob* damager, game::TeamCastle* enemyCastle, float damage) override;
|
||||||
|
|
||||||
virtual void OnArrowShot(game::MobPtr target, game::Tower* shooter) override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace server
|
} // namespace server
|
||||||
|
|||||||
4465
include/misc/Backward.hpp
Normal file
4465
include/misc/Backward.hpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -6,6 +6,9 @@
|
|||||||
namespace td {
|
namespace td {
|
||||||
namespace utils {
|
namespace utils {
|
||||||
|
|
||||||
|
std::uint64_t Inflate(const std::string& source, std::string& dest);
|
||||||
|
std::uint64_t Deflate(const std::string& source, std::string& dest);
|
||||||
|
|
||||||
DataBuffer Compress(const DataBuffer& buffer);
|
DataBuffer Compress(const DataBuffer& buffer);
|
||||||
DataBuffer Decompress(DataBuffer& buffer);
|
DataBuffer Decompress(DataBuffer& buffer);
|
||||||
DataBuffer Decompress(DataBuffer& buffer, std::uint64_t packetLength);
|
DataBuffer Decompress(DataBuffer& buffer, std::uint64_t packetLength);
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef MCLIB_COMMON_DATA_BUFFER_H_
|
#pragma once
|
||||||
#define MCLIB_COMMON_DATA_BUFFER_H_
|
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@@ -13,7 +12,7 @@ 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 = 0;
|
std::size_t m_ReadOffset;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef Data::iterator iterator;
|
typedef Data::iterator iterator;
|
||||||
@@ -23,7 +22,7 @@ public:
|
|||||||
|
|
||||||
DataBuffer();
|
DataBuffer();
|
||||||
DataBuffer(const DataBuffer& other);
|
DataBuffer(const DataBuffer& other);
|
||||||
DataBuffer(const DataBuffer& other, std::size_t 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);
|
||||||
|
|
||||||
@@ -64,7 +63,7 @@ public:
|
|||||||
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 = *(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;
|
||||||
@@ -72,42 +71,55 @@ public:
|
|||||||
|
|
||||||
DataBuffer& operator>>(DataBuffer& data) {
|
DataBuffer& operator>>(DataBuffer& data) {
|
||||||
data.Resize(GetSize() - m_ReadOffset);
|
data.Resize(GetSize() - m_ReadOffset);
|
||||||
std::copy(m_Buffer.begin() + 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((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() + m_ReadOffset, m_Buffer.begin() + m_ReadOffset + stringSize, str.begin());
|
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_ReadOffset += stringSize;
|
m_ReadOffset += stringSize;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WriteSome(const char* buffer, std::size_t amount) {
|
||||||
|
std::size_t end_pos = m_Buffer.size();
|
||||||
|
m_Buffer.resize(m_Buffer.size() + amount);
|
||||||
|
memcpy(m_Buffer.data() + end_pos, buffer, amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteSome(const std::uint8_t* buffer, std::size_t amount) {
|
||||||
|
std::size_t end_pos = m_Buffer.size();
|
||||||
|
m_Buffer.resize(m_Buffer.size() + 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() + 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() + 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() + 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() + 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,5 +175,3 @@ public:
|
|||||||
std::ostream& operator<<(std::ostream& os, const DataBuffer& buffer);
|
std::ostream& operator<<(std::ostream& os, const DataBuffer& buffer);
|
||||||
|
|
||||||
} // ns td
|
} // ns td
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
15
include/misc/DiscordRPC.h
Normal file
15
include/misc/DiscordRPC.h
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
void InitDiscordRPC();
|
||||||
|
void UpdateDiscordRPC();
|
||||||
|
void ShutdownDiscordRPC();
|
||||||
|
|
||||||
|
void UpdateDiscordPresence(const std::string& state, const std::string& details, bool resetTimer = false);
|
||||||
|
|
||||||
|
} // namespace utils
|
||||||
|
} // namespace td
|
||||||
@@ -7,63 +7,63 @@ constexpr float PI = 3.14159274101257324219;
|
|||||||
|
|
||||||
/* Sine functions */
|
/* Sine functions */
|
||||||
|
|
||||||
float easeInSine(float x);
|
float EaseInSine(float x);
|
||||||
float easeOutSine(float x);
|
float EaseOutSine(float x);
|
||||||
float easeInOutSine(float x);
|
float EaseInOutSine(float x);
|
||||||
|
|
||||||
/* Cubic functions */
|
/* Cubic functions */
|
||||||
|
|
||||||
float easeInCubic(float x);
|
float EaseInCubic(float x);
|
||||||
float easeOutCubic(float x);
|
float EaseOutCubic(float x);
|
||||||
float easeInOutCubic(float x);
|
float EaseInOutCubic(float x);
|
||||||
|
|
||||||
/* Quint functions */
|
/* Quint functions */
|
||||||
|
|
||||||
float easeInQuint(float x);
|
float EaseInQuint(float x);
|
||||||
float easeOutQuint(float x);
|
float EaseOutQuint(float x);
|
||||||
float easeInOutQuint(float x);
|
float EaseInOutQuint(float x);
|
||||||
|
|
||||||
/* Circ functions */
|
/* Circ functions */
|
||||||
|
|
||||||
float easeInCirc(float x);
|
float EaseInCirc(float x);
|
||||||
float easeOutCirc(float x);
|
float EaseOutCirc(float x);
|
||||||
float easeInOutCirc(float x);
|
float EaseInOutCirc(float x);
|
||||||
|
|
||||||
/* Elastic functions */
|
/* Elastic functions */
|
||||||
|
|
||||||
float easeInElastic(float x);
|
float EaseInElastic(float x);
|
||||||
float easeOutElastic(float x);
|
float EaseOutElastic(float x);
|
||||||
float easeInOutElastic(float x);
|
float EaseInOutElastic(float x);
|
||||||
|
|
||||||
/* Quad functions */
|
/* Quad functions */
|
||||||
|
|
||||||
float easeInQuad(float x);
|
float EaseInQuad(float x);
|
||||||
float easeOutQuad(float x);
|
float EaseOutQuad(float x);
|
||||||
float easeInOutQuad(float x);
|
float EaseInOutQuad(float x);
|
||||||
|
|
||||||
/* Quart functions */
|
/* Quart functions */
|
||||||
|
|
||||||
float easeInQuart(float x);
|
float EaseInQuart(float x);
|
||||||
float easeOutQuart(float x);
|
float EaseOutQuart(float x);
|
||||||
float easeInOutQuart(float x);
|
float EaseInOutQuart(float x);
|
||||||
|
|
||||||
/* Expo functions */
|
/* Expo functions */
|
||||||
|
|
||||||
float easeInExpo(float x);
|
float EaseInExpo(float x);
|
||||||
float easeOutExpo(float x);
|
float EaseOutExpo(float x);
|
||||||
float easeInOutExpo(float x);
|
float EaseInOutExpo(float x);
|
||||||
|
|
||||||
/* Back functions */
|
/* Back functions */
|
||||||
|
|
||||||
float easeInBack(float x);
|
float EaseInBack(float x);
|
||||||
float easeOutBack(float x);
|
float EaseOutBack(float x);
|
||||||
float easeInOutBack(float x);
|
float EaseInOutBack(float x);
|
||||||
|
|
||||||
/* Bounce functions */
|
/* Bounce functions */
|
||||||
|
|
||||||
float easeInBounce(float x);
|
float EaseInBounce(float x);
|
||||||
float easeOutBounce(float x);
|
float EaseOutBounce(float x);
|
||||||
float easeInOutBounce(float x);
|
float EaseInOutBounce(float x);
|
||||||
|
|
||||||
} // namespace utils
|
} // namespace utils
|
||||||
} // namespace td
|
} // namespace td
|
||||||
|
|||||||
23
include/misc/Format.h
Normal file
23
include/misc/Format.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
std::string format(const std::string& format, Args... args) {
|
||||||
|
int size = snprintf(nullptr, 0, format.c_str(), args...) + 1; // Extra space for '\0'
|
||||||
|
if (size <= 0) {
|
||||||
|
throw std::runtime_error("Error during formatting.");
|
||||||
|
}
|
||||||
|
std::unique_ptr<char[]> buf(new char[size]);
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace utils
|
||||||
|
} // namespace td
|
||||||
|
|
||||||
13
include/misc/Log.h
Normal file
13
include/misc/Log.h
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
void LOG(const std::string& msg);
|
||||||
|
void LOGD(const std::string& msg);
|
||||||
|
void LOGE(const std::string& err);
|
||||||
|
|
||||||
|
} // namespace utils
|
||||||
|
} // namespace td
|
||||||
@@ -13,20 +13,20 @@ 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...)();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ enum class Architecture {
|
|||||||
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__)
|
||||||
@@ -31,7 +31,7 @@ inline Os getSystemOs() {
|
|||||||
#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)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ namespace td {
|
|||||||
namespace utils {
|
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);
|
||||||
@@ -14,7 +14,7 @@ NumberType getRandomInt(NumberType min, NumberType max) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
|||||||
@@ -13,14 +13,14 @@ 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;
|
||||||
@@ -32,31 +32,34 @@ private:
|
|||||||
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 setWidth(float width) { m_Width = width; }
|
void SetSize(Point size) { SetSize(size.GetX(), size.GetY()); }
|
||||||
void setHeight(float height) { m_Height = height; }
|
Point GetSize() { return { m_Width, m_Height }; }
|
||||||
|
|
||||||
bool collidesWith(const Point& point) const;
|
void SetWidth(float width) { m_Width = width; }
|
||||||
bool collidesWith(const Rectangle& rect) const;
|
void SetHeight(float height) { m_Height = height; }
|
||||||
bool collidesWith(const Circle& circle) const;
|
|
||||||
|
bool CollidesWith(const Point& point) const;
|
||||||
|
bool CollidesWith(const Rectangle& rect) 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 {
|
||||||
@@ -67,25 +70,25 @@ 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
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
namespace td {
|
namespace td {
|
||||||
namespace utils {
|
namespace utils {
|
||||||
|
|
||||||
std::uint64_t getTime();
|
std::uint64_t GetTime();
|
||||||
|
|
||||||
|
|
||||||
typedef std::function<void()> TimerExecFunction;
|
typedef std::function<void()> TimerExecFunction;
|
||||||
@@ -17,23 +17,23 @@ 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
|
||||||
@@ -45,15 +45,15 @@ 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)
|
// 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
|
||||||
@@ -62,14 +62,14 @@ 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
|
||||||
|
|||||||
@@ -13,17 +13,18 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class TCPSocket : public Socket {
|
|||||||
private:
|
private:
|
||||||
IPAddress m_RemoteIP;
|
IPAddress m_RemoteIP;
|
||||||
uint16_t m_Port;
|
uint16_t m_Port;
|
||||||
sockaddr_in m_RemoteAddr;
|
sockaddr m_RemoteAddr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TCPSocket();
|
TCPSocket();
|
||||||
|
|||||||
@@ -20,7 +20,9 @@ public:
|
|||||||
|
|
||||||
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);
|
||||||
DataBuffer Receive(std::size_t amount);
|
|
||||||
|
virtual DataBuffer Receive(std::size_t amount);
|
||||||
|
virtual std::size_t Receive(DataBuffer& buffer, std::size_t amount);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // ns network
|
} // ns network
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ namespace td {
|
|||||||
namespace protocol {
|
namespace protocol {
|
||||||
namespace PacketFactory {
|
namespace PacketFactory {
|
||||||
|
|
||||||
PacketPtr createPacket(PacketType type, DataBuffer& buffer);
|
PacketPtr CreatePacket(PacketType type, DataBuffer& buffer);
|
||||||
|
|
||||||
}
|
}
|
||||||
} // namespace protocol
|
} // namespace protocol
|
||||||
|
|||||||
@@ -16,28 +16,32 @@ public:
|
|||||||
|
|
||||||
PacketDispatcher* GetDispatcher() { return m_Dispatcher; }
|
PacketDispatcher* GetDispatcher() { return m_Dispatcher; }
|
||||||
|
|
||||||
virtual void HandlePacket(const PlayerLoginPacket* packet) {}
|
virtual void HandlePacket(const ConnexionInfoPacket* packet) {}
|
||||||
virtual void HandlePacket(const WorldBeginDataPacket* packet) {}
|
virtual void HandlePacket(const DisconnectPacket* packet) {}
|
||||||
virtual void HandlePacket(const WorldDataPacket* packet) {}
|
|
||||||
virtual void HandlePacket(const KeepAlivePacket* packet) {}
|
virtual void HandlePacket(const KeepAlivePacket* packet) {}
|
||||||
virtual void HandlePacket(const UpdateMoneyPacket* packet) {}
|
virtual void HandlePacket(const PlaceTowerPacket* packet) {}
|
||||||
virtual void HandlePacket(const UpdateExpPacket* packet) {}
|
virtual void HandlePacket(const PlayerBuyItemPacket* packet) {}
|
||||||
virtual void HandlePacket(const UpdateLobbyTimePacket* packet) {}
|
virtual void HandlePacket(const PlayerBuyMobUpgradePacket* packet) {}
|
||||||
virtual void HandlePacket(const UpdateGameStatePacket* packet) {}
|
|
||||||
virtual void HandlePacket(const PlayerListPacket* 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 ConnexionInfoPacket* packet) {}
|
virtual void HandlePacket(const PlayerListPacket* packet) {}
|
||||||
|
virtual void HandlePacket(const PlayerLoginPacket* packet) {}
|
||||||
|
virtual void HandlePacket(const RemoveTowerPacket* packet) {}
|
||||||
virtual void HandlePacket(const SelectTeamPacket* packet) {}
|
virtual void HandlePacket(const SelectTeamPacket* packet) {}
|
||||||
virtual void HandlePacket(const UpdatePlayerTeamPacket* packet) {}
|
virtual void HandlePacket(const SendMobsPacket* packet) {}
|
||||||
virtual void HandlePacket(const DisconnectPacket* 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 PlaceTowerPacket* packet) {}
|
virtual void HandlePacket(const UpdateCastleLifePacket* packet) {}
|
||||||
virtual void HandlePacket(const WorldAddTowerPacket* packet) {}
|
virtual void HandlePacket(const UpdateExpPacket* packet) {}
|
||||||
virtual void HandlePacket(const WorldRemoveTowerPacket* packet) {}
|
virtual void HandlePacket(const UpdateGameStatePacket* packet) {}
|
||||||
virtual void HandlePacket(const SendMobsPacket* packet) {}
|
virtual void HandlePacket(const UpdateLobbyTimePacket* packet) {}
|
||||||
|
virtual void HandlePacket(const UpdateMobStatesPacket* packet) {}
|
||||||
|
virtual void HandlePacket(const UpdateMoneyPacket* 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 WorldBeginDataPacket* packet) {}
|
||||||
|
virtual void HandlePacket(const WorldDataPacket* packet) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace protocol
|
} // namespace protocol
|
||||||
|
|||||||
@@ -33,18 +33,25 @@ enum class PacketType : std::uint8_t {
|
|||||||
UpdatePlayerTeam,
|
UpdatePlayerTeam,
|
||||||
ServerTps,
|
ServerTps,
|
||||||
WorldAddTower,
|
WorldAddTower,
|
||||||
WorldRemoveTower,
|
UpdateMobStates,
|
||||||
|
UpdateCastleLife,
|
||||||
|
|
||||||
// client <--> server
|
// client <--> server
|
||||||
KeepAlive,
|
KeepAlive,
|
||||||
Disconnect,
|
Disconnect,
|
||||||
UpgradeTower,
|
UpgradeTower,
|
||||||
|
RemoveTower,
|
||||||
|
PlayerBuyItem,
|
||||||
|
PlayerBuyMobUpgrade,
|
||||||
|
|
||||||
|
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;
|
||||||
|
Color m_Background;
|
||||||
|
|
||||||
game::SpawnColorPalette m_SpawnColorPalette;
|
game::SpawnColorPalette m_SpawnColorPalette;
|
||||||
|
|
||||||
@@ -65,12 +72,14 @@ public:
|
|||||||
Packet() {}
|
Packet() {}
|
||||||
virtual ~Packet() {}
|
virtual ~Packet() {}
|
||||||
|
|
||||||
virtual DataBuffer Serialize() 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;
|
||||||
|
|
||||||
virtual PacketType getType() const = 0;
|
void WritePacketID(DataBuffer& data, bool packetID) const;
|
||||||
std::uint8_t getID() const { return (std::uint8_t)getType(); }
|
|
||||||
|
virtual PacketType GetType() const = 0;
|
||||||
|
std::uint8_t GetID() const { return static_cast<std::uint8_t>(GetType()); }
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::unique_ptr<Packet> PacketPtr;
|
typedef std::unique_ptr<Packet> PacketPtr;
|
||||||
@@ -83,13 +92,13 @@ public:
|
|||||||
KeepAlivePacket(std::uint64_t aliveID) : m_AliveID(aliveID) {}
|
KeepAlivePacket(std::uint64_t aliveID) : m_AliveID(aliveID) {}
|
||||||
virtual ~KeepAlivePacket() {}
|
virtual ~KeepAlivePacket() {}
|
||||||
|
|
||||||
virtual DataBuffer Serialize() 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 {
|
||||||
@@ -100,13 +109,13 @@ public:
|
|||||||
PlayerLoginPacket(std::string playerName) : m_PlayerName(playerName) {}
|
PlayerLoginPacket(std::string playerName) : m_PlayerName(playerName) {}
|
||||||
virtual ~PlayerLoginPacket() {}
|
virtual ~PlayerLoginPacket() {}
|
||||||
|
|
||||||
virtual DataBuffer Serialize() 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 {
|
||||||
@@ -119,27 +128,27 @@ public:
|
|||||||
}
|
}
|
||||||
virtual ~WorldBeginDataPacket() {}
|
virtual ~WorldBeginDataPacket() {}
|
||||||
|
|
||||||
virtual DataBuffer Serialize() 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 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; }
|
||||||
|
|
||||||
DataBuffer SerializeCustom() const; // allow serialisation with invalid World member
|
|
||||||
void setWorldHeader(const WorldHeader& header) { m_Header = header; }
|
void setWorldHeader(const WorldHeader& header) { m_Header = header; }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -153,16 +162,16 @@ public:
|
|||||||
WorldDataPacket(const game::World* world) : m_World(world) {}
|
WorldDataPacket(const game::World* world) : m_World(world) {}
|
||||||
virtual ~WorldDataPacket() {}
|
virtual ~WorldDataPacket() {}
|
||||||
|
|
||||||
virtual DataBuffer Serialize() 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 {
|
||||||
@@ -173,13 +182,13 @@ public:
|
|||||||
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() 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 {
|
||||||
@@ -190,11 +199,13 @@ public:
|
|||||||
UpdateExpPacket(std::uint32_t newAmount) : m_NewAmount(newAmount) {}
|
UpdateExpPacket(std::uint32_t newAmount) : m_NewAmount(newAmount) {}
|
||||||
virtual ~UpdateExpPacket() {}
|
virtual ~UpdateExpPacket() {}
|
||||||
|
|
||||||
virtual DataBuffer Serialize() const;
|
std::uint32_t GetExp() const { return m_NewAmount; }
|
||||||
|
|
||||||
|
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 {
|
||||||
@@ -205,13 +216,13 @@ public:
|
|||||||
UpdateLobbyTimePacket(std::uint32_t remainingTime) : m_RemainingTime(remainingTime) {}
|
UpdateLobbyTimePacket(std::uint32_t remainingTime) : m_RemainingTime(remainingTime) {}
|
||||||
virtual ~UpdateLobbyTimePacket() {}
|
virtual ~UpdateLobbyTimePacket() {}
|
||||||
|
|
||||||
virtual DataBuffer Serialize() 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 {
|
||||||
@@ -222,13 +233,13 @@ public:
|
|||||||
UpdateGameStatePacket(game::GameState gameState) : m_GameState(gameState) {}
|
UpdateGameStatePacket(game::GameState gameState) : m_GameState(gameState) {}
|
||||||
virtual ~UpdateGameStatePacket() {}
|
virtual ~UpdateGameStatePacket() {}
|
||||||
|
|
||||||
virtual DataBuffer Serialize() 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 {
|
||||||
@@ -244,13 +255,13 @@ public:
|
|||||||
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() 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 {
|
||||||
@@ -262,14 +273,14 @@ public:
|
|||||||
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() 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 {
|
||||||
@@ -280,13 +291,13 @@ public:
|
|||||||
PlayerLeavePacket(std::uint8_t playerID) : m_PlayerID(playerID) {}
|
PlayerLeavePacket(std::uint8_t playerID) : m_PlayerID(playerID) {}
|
||||||
virtual ~PlayerLeavePacket() {}
|
virtual ~PlayerLeavePacket() {}
|
||||||
|
|
||||||
virtual DataBuffer Serialize() 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 {
|
||||||
@@ -297,13 +308,13 @@ public:
|
|||||||
ConnexionInfoPacket(std::uint8_t connectionID) : m_ConnectionID(connectionID) {}
|
ConnexionInfoPacket(std::uint8_t connectionID) : m_ConnectionID(connectionID) {}
|
||||||
virtual ~ConnexionInfoPacket() {}
|
virtual ~ConnexionInfoPacket() {}
|
||||||
|
|
||||||
virtual DataBuffer Serialize() 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 {
|
||||||
@@ -314,13 +325,13 @@ public:
|
|||||||
SelectTeamPacket(game::TeamColor selectedTeam) : m_SelectedTeam(selectedTeam) {}
|
SelectTeamPacket(game::TeamColor selectedTeam) : m_SelectedTeam(selectedTeam) {}
|
||||||
virtual ~SelectTeamPacket() {}
|
virtual ~SelectTeamPacket() {}
|
||||||
|
|
||||||
virtual DataBuffer Serialize() 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 {
|
||||||
@@ -332,14 +343,14 @@ public:
|
|||||||
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() 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 {
|
||||||
@@ -350,37 +361,39 @@ public:
|
|||||||
DisconnectPacket(std::string reason) : m_Reason(reason) {}
|
DisconnectPacket(std::string reason) : m_Reason(reason) {}
|
||||||
virtual ~DisconnectPacket() {}
|
virtual ~DisconnectPacket() {}
|
||||||
|
|
||||||
virtual DataBuffer Serialize() 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;
|
||||||
|
float m_MSPT;
|
||||||
std::uint64_t m_PacketSendTime; // used to calculate ping
|
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() 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;
|
game::MobType mobType : 4;
|
||||||
game::MobLevel mobLevel;
|
game::MobLevel mobLevel : 4;
|
||||||
std::uint8_t mobCount; // the max is 12
|
std::uint8_t mobCount; // the max is 12
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -392,13 +405,13 @@ public:
|
|||||||
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() 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 {
|
||||||
@@ -413,22 +426,23 @@ 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() 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 {
|
||||||
@@ -438,18 +452,19 @@ private:
|
|||||||
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() 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 {
|
||||||
@@ -461,37 +476,38 @@ private:
|
|||||||
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() 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 WorldRemoveTowerPacket : public Packet {
|
class RemoveTowerPacket : public Packet {
|
||||||
private:
|
private:
|
||||||
game::TowerID m_TowerID;
|
game::TowerID m_TowerID;
|
||||||
public:
|
public:
|
||||||
WorldRemoveTowerPacket() {}
|
RemoveTowerPacket() {}
|
||||||
WorldRemoveTowerPacket(game::TowerID id) : m_TowerID(id) {}
|
RemoveTowerPacket(game::TowerID id) : m_TowerID(id) {}
|
||||||
virtual ~WorldRemoveTowerPacket() {}
|
virtual ~RemoveTowerPacket() {}
|
||||||
|
|
||||||
virtual DataBuffer Serialize() 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::WorldRemoveTower; }
|
virtual PacketType GetType() const { return PacketType::RemoveTower; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class UpgradeTowerPacket : public Packet {
|
class UpgradeTowerPacket : public Packet {
|
||||||
@@ -503,15 +519,121 @@ public:
|
|||||||
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() 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 {
|
||||||
}
|
using Point = utils::shape::Point;
|
||||||
|
private:
|
||||||
|
game::MobID m_MobID;
|
||||||
|
Point m_MobPosition;
|
||||||
|
float m_MobLife;
|
||||||
|
game::Direction m_MobDirection;
|
||||||
|
public:
|
||||||
|
MobState() {}
|
||||||
|
MobState(game::MobID id, const Point& position, float life, game::Direction direction) :
|
||||||
|
m_MobID(id), m_MobPosition(position), m_MobLife(life), m_MobDirection(direction) {
|
||||||
|
}
|
||||||
|
|
||||||
|
game::MobID GetMobId() const { return m_MobID; }
|
||||||
|
Point GetMobPosition() const { return m_MobPosition; }
|
||||||
|
float GetMobLife() const { return m_MobLife; }
|
||||||
|
game::Direction GetMobDirection() const { return m_MobDirection; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class UpdateMobStatesPacket : public Packet {
|
||||||
|
private:
|
||||||
|
std::vector<MobState> m_MobStates;
|
||||||
|
public:
|
||||||
|
UpdateMobStatesPacket() {}
|
||||||
|
virtual ~UpdateMobStatesPacket() {}
|
||||||
|
|
||||||
|
virtual DataBuffer Serialize(bool packetID = true) const;
|
||||||
|
virtual void Deserialize(DataBuffer& data);
|
||||||
|
virtual void Dispatch(PacketHandler* handler) const;
|
||||||
|
|
||||||
|
void addMobState(MobState mobState) { m_MobStates.push_back(mobState); }
|
||||||
|
|
||||||
|
const std::vector<MobState>& GetMobStates() const { return m_MobStates; }
|
||||||
|
|
||||||
|
virtual PacketType GetType() const { return PacketType::UpdateMobStates; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class UpdateCastleLifePacket : public Packet {
|
||||||
|
private:
|
||||||
|
std::uint16_t m_CastleLife;
|
||||||
|
game::TeamColor m_Team;
|
||||||
|
public:
|
||||||
|
UpdateCastleLifePacket() {}
|
||||||
|
UpdateCastleLifePacket(std::uint16_t life, game::TeamColor team) : m_CastleLife(life), m_Team(team) {}
|
||||||
|
virtual ~UpdateCastleLifePacket() {}
|
||||||
|
|
||||||
|
virtual DataBuffer Serialize(bool packetID = true) const;
|
||||||
|
virtual void Deserialize(DataBuffer& data);
|
||||||
|
virtual void Dispatch(PacketHandler* handler) const;
|
||||||
|
|
||||||
|
std::uint16_t GetCastleLife() const { return m_CastleLife; }
|
||||||
|
game::TeamColor GetTeamColor() const { return m_Team; }
|
||||||
|
|
||||||
|
virtual PacketType GetType() const { return PacketType::UpdateCastleLife; }
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class ItemType : std::uint8_t {
|
||||||
|
// Upgrades
|
||||||
|
ClickerUpgrade,
|
||||||
|
GoldPerSecUpgrade,
|
||||||
|
|
||||||
|
// Items
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Packet used by the client to buy items or upgrades
|
||||||
|
Packet used by the server to confirm transaction */
|
||||||
|
class PlayerBuyItemPacket : public Packet {
|
||||||
|
private:
|
||||||
|
ItemType m_ItemType;
|
||||||
|
std::uint8_t m_Count;
|
||||||
|
public:
|
||||||
|
PlayerBuyItemPacket() {}
|
||||||
|
PlayerBuyItemPacket(ItemType itemType, std::uint8_t count) : m_ItemType(itemType), m_Count(count) {}
|
||||||
|
virtual ~PlayerBuyItemPacket() {}
|
||||||
|
|
||||||
|
virtual DataBuffer Serialize(bool packetID = true) const;
|
||||||
|
virtual void Deserialize(DataBuffer& data);
|
||||||
|
virtual void Dispatch(PacketHandler* handler) const;
|
||||||
|
|
||||||
|
ItemType GetItemType() const { return m_ItemType; }
|
||||||
|
std::uint8_t GetCount() const { return m_Count; }
|
||||||
|
|
||||||
|
virtual PacketType GetType() const { return PacketType::PlayerBuyItem; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Packet used by the client to buy mob upgrades
|
||||||
|
Packet used by the server to confirm transaction */
|
||||||
|
class PlayerBuyMobUpgradePacket : public Packet {
|
||||||
|
private:
|
||||||
|
game::MobType m_MobType;
|
||||||
|
std::uint8_t m_MobLevel;
|
||||||
|
public:
|
||||||
|
PlayerBuyMobUpgradePacket() {}
|
||||||
|
PlayerBuyMobUpgradePacket(game::MobType mobType, std::uint8_t level) : m_MobType(mobType), m_MobLevel(level) {}
|
||||||
|
virtual ~PlayerBuyMobUpgradePacket() {}
|
||||||
|
|
||||||
|
virtual DataBuffer Serialize(bool packetID = true) const;
|
||||||
|
virtual void Deserialize(DataBuffer& data);
|
||||||
|
virtual void Dispatch(PacketHandler* handler) const;
|
||||||
|
|
||||||
|
game::MobType GetMobType() const { return m_MobType; }
|
||||||
|
std::uint8_t GetLevel() const { return m_MobLevel; }
|
||||||
|
|
||||||
|
virtual PacketType GetType() const { return PacketType::PlayerBuyMobUpgrade; }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace protocol
|
||||||
|
} // namespace td
|
||||||
@@ -1,8 +1,62 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifdef __ANDROID__
|
#if !defined(TD_IMPL_OPENGL_ES2) \
|
||||||
#include <GLES3/gl3.h>
|
&& !defined(TD_IMPL_OPENGL_ES3) \
|
||||||
|
&& !defined(TD_IMPL_OPENGL_LOADER_GL3W) \
|
||||||
|
&& !defined(TD_IMPL_OPENGL_LOADER_GLEW) \
|
||||||
|
&& !defined(TD_IMPL_OPENGL_LOADER_GLAD) \
|
||||||
|
&& !defined(TD_IMPL_OPENGL_LOADER_GLBINDING2) \
|
||||||
|
&& !defined(TD_IMPL_OPENGL_LOADER_GLBINDING3) \
|
||||||
|
&& !defined(TD_IMPL_OPENGL_LOADER_CUSTOM) \
|
||||||
|
&& !defined(__ANDROID__)
|
||||||
|
|
||||||
|
#if defined(__has_include)
|
||||||
|
|
||||||
|
#if __has_include(<GL/glew.h>)
|
||||||
|
#define TD_IMPL_OPENGL_LOADER_GLEW
|
||||||
|
#elif __has_include(<glad/glad.h>)
|
||||||
|
#define TD_IMPL_OPENGL_LOADER_GLAD
|
||||||
|
#elif __has_include(<GL/gl3w.h>)
|
||||||
|
#define TD_IMPL_OPENGL_LOADER_GL3W
|
||||||
|
#elif __has_include(<glbinding/glbinding.h>)
|
||||||
|
#define TD_IMPL_OPENGL_LOADER_GLBINDING3
|
||||||
|
#elif __has_include(<glbinding/Binding.h>)
|
||||||
|
#define TD_IMPL_OPENGL_LOADER_GLBINDING2
|
||||||
#else
|
#else
|
||||||
#include "glbinding/gl/gl.h"
|
#error "Cannot detect OpenGL loader!"
|
||||||
using namespace gl;
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "Cannot detect loader with include detection !"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Include correct files
|
||||||
|
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
#include <GLES3/gl3.h>
|
||||||
|
#elif defined(TD_IMPL_OPENGL_LOADER_GL3W)
|
||||||
|
#include <GL/gl3w.h> // Needs to be initialized with gl3wInit() in user's code
|
||||||
|
#elif defined(TD_IMPL_OPENGL_LOADER_GLEW)
|
||||||
|
#include <GL/glew.h> // Needs to be initialized with glewInit() in user's code.
|
||||||
|
#elif defined(TD_IMPL_OPENGL_LOADER_GLAD)
|
||||||
|
#include <glad/glad.h> // Needs to be initialized with gladLoadGL() in user's code.
|
||||||
|
#elif defined(TD_IMPL_OPENGL_LOADER_GLBINDING2)
|
||||||
|
#ifndef GLFW_INCLUDE_NONE
|
||||||
|
#define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors.
|
||||||
|
#endif
|
||||||
|
#include <glbinding/Binding.h> // Needs to be initialized with glbinding::Binding::initialize() in user's code.
|
||||||
|
#include <glbinding/gl/gl.h>
|
||||||
|
using namespace gl;
|
||||||
|
#elif defined(TD_IMPL_OPENGL_LOADER_GLBINDING3)
|
||||||
|
#ifndef GLFW_INCLUDE_NONE
|
||||||
|
#define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors.
|
||||||
|
#endif
|
||||||
|
#include <glbinding/glbinding.h>// Needs to be initialized with glbinding::initialize() in user's code.
|
||||||
|
#include <glbinding/gl/gl.h>
|
||||||
|
using namespace gl;
|
||||||
|
#else
|
||||||
|
#include TD_IMPL_OPENGL_LOADER_CUSTOM
|
||||||
#endif
|
#endif
|
||||||
@@ -1,14 +1,6 @@
|
|||||||
/*
|
#pragma once
|
||||||
* Renderer.h
|
|
||||||
*
|
|
||||||
* Created on: 4 nov. 2020
|
|
||||||
* Author: simon
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef RENDER_RENDERER_H_
|
#include "Defines.h"
|
||||||
#define RENDER_RENDERER_H_
|
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include "loader/GLLoader.h"
|
#include "loader/GLLoader.h"
|
||||||
#include "render/shaders/WorldShader.h"
|
#include "render/shaders/WorldShader.h"
|
||||||
@@ -23,40 +15,43 @@ public:
|
|||||||
|
|
||||||
struct Model {
|
struct Model {
|
||||||
GL::VertexArray* vao;
|
GL::VertexArray* vao;
|
||||||
glm::vec2 positon;
|
Vec2f positon;
|
||||||
|
Vec3f color = { 1, 1, 1 };
|
||||||
};
|
};
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<WorldShader> m_WorldShader;
|
std::unique_ptr<shader::WorldShader> m_WorldShader;
|
||||||
std::unique_ptr<EntityShader> m_EntityShader;
|
std::unique_ptr<shader::EntityShader> m_EntityShader;
|
||||||
|
|
||||||
|
Vec3f m_BackgroundColor;
|
||||||
|
|
||||||
bool m_IsometricView = true;
|
bool m_IsometricView = true;
|
||||||
float m_IsometricShade = m_IsometricView;
|
float m_IsometricShade = m_IsometricView;
|
||||||
glm::vec2 m_CamPos{};
|
Vec2f m_CamPos{};
|
||||||
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 SetZoom(float zoom);
|
||||||
void setCamMovement(const glm::vec2& mov);
|
void SetCamMovement(const Vec2f& mov);
|
||||||
void setCamPos(const glm::vec2& newPos);
|
void SetCamPos(const Vec2f& newPos);
|
||||||
void setIsometricView(bool isometric); // false = 2D true = Isometric
|
void SetIsometricView(bool isometric); // false = 2D true = Isometric
|
||||||
|
|
||||||
glm::vec2 getCursorWorldPos(const glm::vec2& cursorPos, float aspectRatio, float zoom, float windowWidth, float windowHeight);
|
void SetBackgroundColor(const Vec3f& color) { m_BackgroundColor = color; }
|
||||||
|
|
||||||
|
Vec2f GetCursorWorldPos(const Vec2f& cursorPos, float aspectRatio, float zoom, float windowWidth, float windowHeight);
|
||||||
private:
|
private:
|
||||||
void updateIsometricView();
|
void UpdateIsometricView();
|
||||||
void updateIsometricFade();
|
void UpdateIsometricFade();
|
||||||
void initShader();
|
void InitShaders();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace render
|
} // namespace render
|
||||||
} // namespace td
|
} // namespace td
|
||||||
|
|
||||||
#endif /* RENDER_RENDERER_H_ */
|
|
||||||
|
|||||||
@@ -12,22 +12,26 @@ namespace render {
|
|||||||
class VertexCache {
|
class VertexCache {
|
||||||
|
|
||||||
typedef std::vector<float> Vector;
|
typedef std::vector<float> Vector;
|
||||||
typedef std::pair<Vector::iterator, Vector::iterator> ElementsIndex;
|
|
||||||
typedef std::pair<ElementsIndex, ElementsIndex> DataIndex;
|
struct DataIndex {
|
||||||
|
Vector position;
|
||||||
|
Vector color;
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Vector m_Positions;
|
std::size_t m_VertexCount;
|
||||||
Vector m_Colors;
|
|
||||||
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:
|
||||||
void addData(std::uint64_t index, std::vector<float> positions, std::vector<float> colors);
|
VertexCache() : m_VertexCount(0) {}
|
||||||
void removeData(std::uint64_t index);
|
|
||||||
void clear();
|
|
||||||
void updateVertexArray();
|
|
||||||
|
|
||||||
const GL::VertexArray& getVertexArray() const { return *m_VertexArray; }
|
void AddData(std::uint64_t index, std::vector<float> positions, std::vector<float> colors);
|
||||||
bool isEmpty() const { return m_VertexArray == nullptr; }
|
void RemoveData(std::uint64_t index);
|
||||||
|
void Clear();
|
||||||
|
void UpdateVertexArray();
|
||||||
|
|
||||||
|
const GL::VertexArray& GetVertexArray() const { return *m_VertexArray; }
|
||||||
|
bool IsEmpty() const { return m_VertexArray == nullptr; }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace render
|
} // namespace render
|
||||||
|
|||||||
@@ -6,12 +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/imgui/imgui.h"
|
#include "render/gui/imgui/imgui.h"
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
|
||||||
|
|
||||||
namespace td {
|
namespace td {
|
||||||
|
|
||||||
namespace client {
|
namespace client {
|
||||||
@@ -23,56 +23,63 @@ class ClientGame;
|
|||||||
|
|
||||||
namespace render {
|
namespace render {
|
||||||
|
|
||||||
class WorldRenderer {
|
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::TowerUpgradePopup> m_TowerUpgradePopup;
|
||||||
std::unique_ptr<gui::MobTooltip> m_MobTooltip;
|
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();
|
||||||
|
|
||||||
void addTower(game::TowerPtr tower);
|
static ImVec4 GetImGuiTeamColor(game::TeamColor color);
|
||||||
void removeTower(game::TowerPtr tower);
|
|
||||||
|
|
||||||
static ImVec4 getImGuiTeamColor(game::TeamColor color);
|
void Update();
|
||||||
|
void Render();
|
||||||
|
|
||||||
void update();
|
void SetCamPos(float camX, float camY);
|
||||||
void render();
|
|
||||||
|
|
||||||
void setCamPos(float camX, float camY);
|
void MoveCam(float relativeX, float relativeY, float aspectRatio);
|
||||||
|
void ChangeZoom(float zoom);
|
||||||
|
|
||||||
void moveCam(float relativeX, float relativeY, float aspectRatio);
|
// WorldListener
|
||||||
void changeZoom(float zoom);
|
|
||||||
|
virtual void OnTowerAdd(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 detectClick();
|
void DetectClick();
|
||||||
void detectMobHovering() const;
|
void DetectMobHovering() const;
|
||||||
glm::vec2 getCursorWorldPos() const;
|
void DetectCastleHovering() const;
|
||||||
glm::vec2 getClickWorldPos() const;
|
void RenderTooltips() const;
|
||||||
|
void RemoveTower();
|
||||||
|
Vec2f GetCursorWorldPos() const;
|
||||||
|
Vec2f GetClickWorldPos() const;
|
||||||
|
|
||||||
void updateCursorPos();
|
void UpdateCursorPos();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace render
|
} // namespace render
|
||||||
|
|||||||
28
include/render/gui/CastleTooltip.h
Normal file
28
include/render/gui/CastleTooltip.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "GuiWidget.h"
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
|
||||||
|
namespace game {
|
||||||
|
|
||||||
|
class TeamCastle;
|
||||||
|
|
||||||
|
} // namespace game
|
||||||
|
|
||||||
|
namespace gui {
|
||||||
|
|
||||||
|
class CastleTooltip : public GuiWidget {
|
||||||
|
private:
|
||||||
|
const game::TeamCastle* m_Castle;
|
||||||
|
public:
|
||||||
|
CastleTooltip(client::Client* client);
|
||||||
|
|
||||||
|
virtual void Render();
|
||||||
|
|
||||||
|
void SetCastle(const game::TeamCastle* castle) { m_Castle = castle; }
|
||||||
|
bool IsShown() { return m_Castle != nullptr; }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace gui
|
||||||
|
} // namespace td
|
||||||
@@ -13,7 +13,7 @@ private:
|
|||||||
public:
|
public:
|
||||||
FrameMenu(client::Client* client);
|
FrameMenu(client::Client* client);
|
||||||
|
|
||||||
virtual void render();
|
virtual void Render();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace gui
|
} // namespace gui
|
||||||
|
|||||||
@@ -11,13 +11,13 @@ private:
|
|||||||
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
|
||||||
|
|||||||
@@ -10,15 +10,17 @@ namespace gui {
|
|||||||
|
|
||||||
class GuiManager {
|
class GuiManager {
|
||||||
private:
|
private:
|
||||||
std::vector<std::shared_ptr<GuiWidget>> m_Widgets;
|
std::vector<std::unique_ptr<GuiWidget>> m_Widgets;
|
||||||
public:
|
public:
|
||||||
void renderWidgets() {
|
GuiManager() {}
|
||||||
for (auto widget : m_Widgets) {
|
|
||||||
widget->render();
|
void RenderWidgets() {
|
||||||
|
for (auto& widget : m_Widgets) {
|
||||||
|
widget->Render();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void addWidgets(const std::shared_ptr<GuiWidget>& widget) {
|
void AddWidget(std::unique_ptr<GuiWidget>&& widget) {
|
||||||
m_Widgets.push_back(std::move(widget));
|
m_Widgets.push_back(std::move(widget));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ protected:
|
|||||||
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
|
||||||
|
|||||||
9
include/render/gui/LifeProgress.h
Normal file
9
include/render/gui/LifeProgress.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace gui {
|
||||||
|
|
||||||
|
extern void RenderLifeProgress(float progress);
|
||||||
|
|
||||||
|
} // namespace gui
|
||||||
|
} // namespace td
|
||||||
@@ -26,11 +26,11 @@ 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
|
||||||
|
|||||||
@@ -18,9 +18,10 @@ private:
|
|||||||
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; }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace gui
|
} // namespace gui
|
||||||
|
|||||||
@@ -12,14 +12,18 @@ class SummonMenu : public GuiWidget {
|
|||||||
private:
|
private:
|
||||||
bool m_MenuOpened;
|
bool m_MenuOpened;
|
||||||
int m_ImageWidth = 100;
|
int m_ImageWidth = 100;
|
||||||
|
float m_Cooldown;
|
||||||
|
float m_LastCooldown;
|
||||||
static constexpr int m_MobTypeCount = static_cast<std::size_t>(td::game::MobType::MOB_COUNT);
|
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;
|
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
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#include "render/gui/GuiManager.h"
|
||||||
|
|
||||||
struct SDL_Window;
|
struct SDL_Window;
|
||||||
typedef void* SDL_GLContext;
|
typedef void* SDL_GLContext;
|
||||||
|
|
||||||
@@ -20,15 +22,6 @@ class Client;
|
|||||||
|
|
||||||
} // namespace client
|
} // namespace client
|
||||||
|
|
||||||
namespace gui {
|
|
||||||
|
|
||||||
class MainMenu;
|
|
||||||
class GameMenu;
|
|
||||||
class FrameMenu;
|
|
||||||
class UpdateMenu;
|
|
||||||
|
|
||||||
} // namespace gui
|
|
||||||
|
|
||||||
namespace render {
|
namespace render {
|
||||||
|
|
||||||
class Renderer;
|
class Renderer;
|
||||||
@@ -38,21 +31,18 @@ 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;
|
||||||
std::unique_ptr<td::client::Client> m_Client;
|
std::unique_ptr<td::client::Client> m_Client;
|
||||||
std::unique_ptr<td::gui::MainMenu> m_MainMenu;
|
|
||||||
std::unique_ptr<td::gui::GameMenu> m_GameMenu;
|
|
||||||
std::unique_ptr<td::gui::FrameMenu> m_FrameMenu;
|
|
||||||
std::unique_ptr<td::gui::UpdateMenu> m_UpdateMenu;
|
|
||||||
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
|
||||||
|
|||||||
@@ -2,20 +2,20 @@
|
|||||||
|
|
||||||
#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;
|
||||||
|
|||||||
32
include/render/gui/TowerUpgradePopup.h
Normal file
32
include/render/gui/TowerUpgradePopup.h
Normal 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
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -107,8 +107,20 @@ namespace ImGui
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef __ANDROID__
|
#include "render/GL.h"
|
||||||
#define IMGUI_IMPL_OPENGL_ES3
|
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
#define IMGUI_IMPL_OPENGL_LOADER_ES3
|
||||||
|
#elif defined(TD_IMPL_OPENGL_LOADER_GL3W)
|
||||||
|
#define IMGUI_IMPL_OPENGL_LOADER_GL3W
|
||||||
|
#elif defined(TD_IMPL_OPENGL_LOADER_GLEW)
|
||||||
|
#define IMGUI_IMPL_OPENGL_LOADER_GLEW
|
||||||
|
#elif defined(TD_IMPL_OPENGL_LOADER_GLAD)
|
||||||
|
#define IMGUI_IMPL_OPENGL_LOADER_GLAD
|
||||||
|
#elif defined(TD_IMPL_OPENGL_LOADER_GLBINDING2)
|
||||||
|
#define IMGUI_IMPL_OPENGL_LOADER_GLBINDING2
|
||||||
|
#elif defined(TD_IMPL_OPENGL_LOADER_GLBINDING3)
|
||||||
|
#define IMGUI_IMPL_OPENGL_LOADER_GLBINDING3
|
||||||
#else
|
#else
|
||||||
#define IMGUI_IMPL_OPENGL_LOADER_GLBINDING2
|
#define IMGUI_IMPL_OPENGL_LOADER_CUSTOM
|
||||||
#endif
|
#endif
|
||||||
@@ -17,8 +17,9 @@
|
|||||||
namespace GL {
|
namespace GL {
|
||||||
|
|
||||||
struct VertexAttribPointer {
|
struct VertexAttribPointer {
|
||||||
unsigned int m_Index, m_Size;
|
unsigned int m_Index;
|
||||||
int m_Offset;
|
unsigned int m_Size;
|
||||||
|
unsigned int m_Offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
class VertexBuffer {
|
class VertexBuffer {
|
||||||
@@ -27,6 +28,7 @@ private:
|
|||||||
std::vector<VertexAttribPointer> m_VertexAttribs;
|
std::vector<VertexAttribPointer> m_VertexAttribs;
|
||||||
public:
|
public:
|
||||||
REMOVE_COPY(VertexBuffer);
|
REMOVE_COPY(VertexBuffer);
|
||||||
|
|
||||||
VertexBuffer(VertexBuffer&& other) {
|
VertexBuffer(VertexBuffer&& other) {
|
||||||
m_VertexAttribs = std::move(other.m_VertexAttribs);
|
m_VertexAttribs = std::move(other.m_VertexAttribs);
|
||||||
m_ID = other.m_ID;
|
m_ID = other.m_ID;
|
||||||
@@ -34,12 +36,14 @@ public:
|
|||||||
other.m_ID = 0;
|
other.m_ID = 0;
|
||||||
other.m_DataStride = 0;
|
other.m_DataStride = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
VertexBuffer(const std::vector<float>& data, unsigned int stride);
|
VertexBuffer(const std::vector<float>& data, unsigned int stride);
|
||||||
~VertexBuffer();
|
~VertexBuffer();
|
||||||
void bind() const;
|
|
||||||
void unbind() const;
|
void Bind() const;
|
||||||
void addVertexAttribPointer(unsigned int index, unsigned int coordinateSize, unsigned int offset);
|
void Unbind() const;
|
||||||
void bindVertexAttribs() const;
|
void AddVertexAttribPointer(unsigned int index, unsigned int coordinateSize, unsigned int offset);
|
||||||
|
void BindVertexAttribs() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class VertexArray {
|
class VertexArray {
|
||||||
@@ -48,6 +52,7 @@ private:
|
|||||||
std::vector<VertexBuffer> m_VertexBuffers; //use to destroy vbos when become unused
|
std::vector<VertexBuffer> m_VertexBuffers; //use to destroy vbos when become unused
|
||||||
public:
|
public:
|
||||||
REMOVE_COPY(VertexArray);
|
REMOVE_COPY(VertexArray);
|
||||||
|
|
||||||
VertexArray(VertexArray&& other) {
|
VertexArray(VertexArray&& other) {
|
||||||
m_ID = other.m_ID;
|
m_ID = other.m_ID;
|
||||||
m_VertexCount = other.m_VertexCount;
|
m_VertexCount = other.m_VertexCount;
|
||||||
@@ -55,12 +60,14 @@ public:
|
|||||||
other.m_VertexCount = 0;
|
other.m_VertexCount = 0;
|
||||||
other.m_ID = 0;
|
other.m_ID = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
VertexArray(unsigned int vertexCount);
|
VertexArray(unsigned int vertexCount);
|
||||||
~VertexArray();
|
~VertexArray();
|
||||||
unsigned int getVertexCount() const { return m_VertexCount; }
|
|
||||||
void bindVertexBuffer(VertexBuffer& vbo);
|
unsigned int GetVertexCount() const { return m_VertexCount; }
|
||||||
void bind() const;
|
void BindVertexBuffer(VertexBuffer& vbo);
|
||||||
void unbind() const;
|
void Bind() const;
|
||||||
|
void Unbind() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,9 @@
|
|||||||
#define RENDER_LOADER_TEXTURELOADER_H_
|
#define RENDER_LOADER_TEXTURELOADER_H_
|
||||||
|
|
||||||
namespace TextureLoader {
|
namespace TextureLoader {
|
||||||
const unsigned int loadGLTexture(const char* fileName);
|
|
||||||
|
unsigned int LoadGLTexture(const char* fileName);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ struct RenderData {
|
|||||||
std::vector<float> colors;
|
std::vector<float> colors;
|
||||||
};
|
};
|
||||||
|
|
||||||
GL::VertexArray loadMobModel();
|
GL::VertexArray LoadMobModel();
|
||||||
GL::VertexArray loadWorldModel(const td::game::World* world);
|
GL::VertexArray LoadWorldModel(const td::game::World* world);
|
||||||
GL::VertexArray loadTileSelectModel();
|
GL::VertexArray LoadTileSelectModel();
|
||||||
RenderData loadTowerModel(game::TowerPtr tower);
|
RenderData LoadTowerModel(game::TowerPtr tower);
|
||||||
|
|
||||||
} // namespace WorldLoader
|
} // namespace WorldLoader
|
||||||
|
|
||||||
|
|||||||
@@ -2,17 +2,31 @@
|
|||||||
|
|
||||||
#include "ShaderProgram.h"
|
#include "ShaderProgram.h"
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace shader {
|
||||||
|
|
||||||
class EntityShader : public ShaderProgram {
|
class EntityShader : public ShaderProgram {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned int location_cam = 0, location_zoom = 0, location_aspect_ratio = 0, location_translation = 0, location_viewtype = 0;
|
unsigned int m_LocationCam = 0;
|
||||||
|
unsigned int m_LocationZoom = 0;
|
||||||
|
unsigned int m_LocationAspectRatio = 0;
|
||||||
|
unsigned int m_LocationTranslation = 0;
|
||||||
|
unsigned int m_LocationViewtype = 0;
|
||||||
|
unsigned int m_LocationColorEffect = 0;
|
||||||
protected:
|
protected:
|
||||||
void getAllUniformLocation();
|
virtual void GetAllUniformLocation();
|
||||||
public:
|
public:
|
||||||
EntityShader();
|
EntityShader();
|
||||||
void loadShader();
|
|
||||||
void setCamPos(const glm::vec2& camPos);
|
void LoadShader();
|
||||||
void setZoom(float zoom);
|
void SetCamPos(const Vec2f& camPos);
|
||||||
void setAspectRatio(float aspectRatio);
|
void SetZoom(float zoom);
|
||||||
void setModelPos(const glm::vec2& modelPos);
|
void SetAspectRatio(float aspectRatio);
|
||||||
void setIsometricView(float isometric);
|
void SetModelPos(const Vec2f& modelPos);
|
||||||
|
void SetIsometricView(float isometric);
|
||||||
|
void SetColorEffect(const Vec3f& color);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace shader
|
||||||
|
} // namespace td
|
||||||
|
|||||||
@@ -1,44 +1,42 @@
|
|||||||
/*
|
#pragma once
|
||||||
* ShaderProgram.h
|
|
||||||
*
|
|
||||||
* Created on: 31 janv. 2020
|
|
||||||
* Author: simon
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef RENDER_SHADERS_SHADERPROGRAM_H_
|
|
||||||
#define RENDER_SHADERS_SHADERPROGRAM_H_
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <glm/glm.hpp>
|
#include "Defines.h"
|
||||||
#include "render/GL.h"
|
#include "render/GL.h"
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace shader {
|
||||||
|
|
||||||
class ShaderProgram {
|
class ShaderProgram {
|
||||||
public:
|
public:
|
||||||
ShaderProgram();
|
ShaderProgram();
|
||||||
virtual ~ShaderProgram();
|
virtual ~ShaderProgram();
|
||||||
void start() const;
|
|
||||||
void stop() const;
|
void Start() const;
|
||||||
void loadProgramFile(const std::string& vertexFile, const std::string& fragmentFile);
|
void Stop() const;
|
||||||
void loadProgram(const std::string& vertexSource, const std::string& fragmentSource);
|
|
||||||
|
void LoadProgramFile(const std::string& vertexFile, const std::string& fragmentFile);
|
||||||
|
void LoadProgram(const std::string& vertexSource, const std::string& fragmentSource);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void getAllUniformLocation() = 0;
|
virtual void GetAllUniformLocation() = 0;
|
||||||
int getUniformLocation(const std::string& uniformName)const;
|
int GetUniformLocation(const std::string& uniformName) const;
|
||||||
void loadFloat(const int location, const float value)const;
|
|
||||||
void loadInt(const int& location, const int& value)const;
|
void LoadFloat(unsigned int location, float value) const;
|
||||||
void loadVector(const int& location, const glm::vec2& vector)const;
|
void LoadInt(unsigned int location, int value) const;
|
||||||
void loadVector(const int& location, const glm::vec3& vector)const;
|
void LoadVector(unsigned int location, const Vec2f& vector) const;
|
||||||
void loadVector(const int& location, const glm::vec4& vector)const;
|
void LoadVector(unsigned int location, const Vec3f& vector) const;
|
||||||
void loadBoolean(const int& location, const bool& value)const;
|
void LoadBoolean(unsigned int location, bool value) const;
|
||||||
void loadMatrix(const int& location, const glm::mat4& matrix);
|
void CleanUp() const;
|
||||||
void cleanUp() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned int programID;
|
unsigned int m_ProgramID;
|
||||||
unsigned int vertexShaderID;
|
unsigned int m_VertexShaderID;
|
||||||
unsigned int fragmentShaderID;
|
unsigned int m_FragmentShaderID;
|
||||||
int loadShaderFromFile(const std::string& file, GLenum type);
|
|
||||||
int loadShader(const std::string& source, GLenum type);
|
unsigned int LoadShaderFromFile(const std::string& file, GLenum type);
|
||||||
|
unsigned int LoadShader(const std::string& source, GLenum type);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* RENDER_SHADERS_SHADERPROGRAM_H_ */
|
} // namespace shader
|
||||||
|
} // namespace td
|
||||||
@@ -1,27 +1,23 @@
|
|||||||
/*
|
#pragma once
|
||||||
* GameShader.h
|
|
||||||
*
|
|
||||||
* Created on: 4 nov. 2020
|
|
||||||
* Author: simon
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef RENDER_SHADERS_GAMESHADER_H_
|
|
||||||
#define RENDER_SHADERS_GAMESHADER_H_
|
|
||||||
|
|
||||||
#include "ShaderProgram.h"
|
#include "ShaderProgram.h"
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace shader {
|
||||||
|
|
||||||
class WorldShader : public ShaderProgram {
|
class WorldShader : public ShaderProgram {
|
||||||
private:
|
private:
|
||||||
unsigned int location_cam = 0, location_zoom = 0, location_aspect_ratio = 0, location_viewtype = 0;
|
unsigned int m_LocationCam = 0, m_LocationZoom = 0, m_LocationAspectRatio = 0, m_LocationViewtype = 0;
|
||||||
protected:
|
protected:
|
||||||
void getAllUniformLocation();
|
void GetAllUniformLocation();
|
||||||
public:
|
public:
|
||||||
WorldShader();
|
WorldShader();
|
||||||
void loadShader();
|
void LoadShader();
|
||||||
void setCamPos(const glm::vec2& camPos);
|
void SetCamPos(const Vec2f& camPos);
|
||||||
void setZoom(float zoom);
|
void SetZoom(float zoom);
|
||||||
void setAspectRatio(float aspectRatio);
|
void SetAspectRatio(float aspectRatio);
|
||||||
void setIsometricView(float isometric);
|
void SetIsometricView(float isometric);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* RENDER_SHADERS_GAMESHADER_H_ */
|
} // namespace shader
|
||||||
|
} // namespace td
|
||||||
|
|||||||
@@ -2,9 +2,7 @@
|
|||||||
|
|
||||||
#include "misc/DataBuffer.h"
|
#include "misc/DataBuffer.h"
|
||||||
|
|
||||||
#include <ctime>
|
#define TD_VERSION "alpha-0.3.0"
|
||||||
|
|
||||||
#define TD_VERSION "alpha-0.0.3"
|
|
||||||
|
|
||||||
namespace td {
|
namespace td {
|
||||||
namespace utils {
|
namespace utils {
|
||||||
@@ -20,26 +18,26 @@ private:
|
|||||||
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
|
||||||
|
|||||||
@@ -11,19 +11,19 @@
|
|||||||
|
|
||||||
namespace Display {
|
namespace Display {
|
||||||
|
|
||||||
bool create();
|
bool Create();
|
||||||
void render();
|
void Render();
|
||||||
void update();
|
void Update();
|
||||||
void destroy();
|
void Destroy();
|
||||||
void pollEvents();
|
void PollEvents();
|
||||||
|
|
||||||
bool isCloseRequested();
|
bool IsCloseRequested();
|
||||||
|
|
||||||
bool isMouseDown(int button);
|
bool IsMouseDown(int button);
|
||||||
|
|
||||||
float getAspectRatio();
|
float GetAspectRatio();
|
||||||
int getWindowWidth();
|
int GetWindowWidth();
|
||||||
int getWindowHeight();
|
int GetWindowHeight();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
40
libs/discordrpc/backoff.h
Normal file
40
libs/discordrpc/backoff.h
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <random>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
struct Backoff {
|
||||||
|
int64_t minAmount;
|
||||||
|
int64_t maxAmount;
|
||||||
|
int64_t current;
|
||||||
|
int fails;
|
||||||
|
std::mt19937_64 randGenerator;
|
||||||
|
std::uniform_real_distribution<> randDistribution;
|
||||||
|
|
||||||
|
double rand01() { return randDistribution(randGenerator); }
|
||||||
|
|
||||||
|
Backoff(int64_t min, int64_t max)
|
||||||
|
: minAmount(min)
|
||||||
|
, maxAmount(max)
|
||||||
|
, current(min)
|
||||||
|
, fails(0)
|
||||||
|
, randGenerator((uint64_t)time(0))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset()
|
||||||
|
{
|
||||||
|
fails = 0;
|
||||||
|
current = minAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t nextDelay()
|
||||||
|
{
|
||||||
|
++fails;
|
||||||
|
int64_t delay = (int64_t)((double)current * 2.0 * rand01());
|
||||||
|
current = std::min(current + delay, maxAmount);
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
};
|
||||||
19
libs/discordrpc/connection.h
Normal file
19
libs/discordrpc/connection.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// This is to wrap the platform specific kinds of connect/read/write.
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
// not really connectiony, but need per-platform
|
||||||
|
int GetProcessId();
|
||||||
|
|
||||||
|
struct BaseConnection {
|
||||||
|
static BaseConnection* Create();
|
||||||
|
static void Destroy(BaseConnection*&);
|
||||||
|
bool isOpen{false};
|
||||||
|
bool Open();
|
||||||
|
bool Close();
|
||||||
|
bool Write(const void* data, size_t length);
|
||||||
|
bool Read(void* data, size_t length);
|
||||||
|
};
|
||||||
129
libs/discordrpc/connection_unix.cpp
Normal file
129
libs/discordrpc/connection_unix.cpp
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
#ifdef __unix__
|
||||||
|
|
||||||
|
#include "connection.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
int GetProcessId()
|
||||||
|
{
|
||||||
|
return ::getpid();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BaseConnectionUnix : public BaseConnection {
|
||||||
|
int sock{-1};
|
||||||
|
};
|
||||||
|
|
||||||
|
static BaseConnectionUnix Connection;
|
||||||
|
static sockaddr_un PipeAddr{};
|
||||||
|
#ifdef MSG_NOSIGNAL
|
||||||
|
static int MsgFlags = MSG_NOSIGNAL;
|
||||||
|
#else
|
||||||
|
static int MsgFlags = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const char* GetTempPath()
|
||||||
|
{
|
||||||
|
const char* temp = getenv("XDG_RUNTIME_DIR");
|
||||||
|
temp = temp ? temp : getenv("TMPDIR");
|
||||||
|
temp = temp ? temp : getenv("TMP");
|
||||||
|
temp = temp ? temp : getenv("TEMP");
|
||||||
|
temp = temp ? temp : "/tmp";
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*static*/ BaseConnection* BaseConnection::Create()
|
||||||
|
{
|
||||||
|
PipeAddr.sun_family = AF_UNIX;
|
||||||
|
return &Connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*static*/ void BaseConnection::Destroy(BaseConnection*& c)
|
||||||
|
{
|
||||||
|
auto self = reinterpret_cast<BaseConnectionUnix*>(c);
|
||||||
|
self->Close();
|
||||||
|
c = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BaseConnection::Open()
|
||||||
|
{
|
||||||
|
const char* tempPath = GetTempPath();
|
||||||
|
auto self = reinterpret_cast<BaseConnectionUnix*>(this);
|
||||||
|
self->sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
if (self->sock == -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
fcntl(self->sock, F_SETFL, O_NONBLOCK);
|
||||||
|
#ifdef SO_NOSIGPIPE
|
||||||
|
int optval = 1;
|
||||||
|
setsockopt(self->sock, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (int pipeNum = 0; pipeNum < 10; ++pipeNum) {
|
||||||
|
snprintf(
|
||||||
|
PipeAddr.sun_path, sizeof(PipeAddr.sun_path), "%s/discord-ipc-%d", tempPath, pipeNum);
|
||||||
|
int err = connect(self->sock, (const sockaddr*)&PipeAddr, sizeof(PipeAddr));
|
||||||
|
if (err == 0) {
|
||||||
|
self->isOpen = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self->Close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BaseConnection::Close()
|
||||||
|
{
|
||||||
|
auto self = reinterpret_cast<BaseConnectionUnix*>(this);
|
||||||
|
if (self->sock == -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
close(self->sock);
|
||||||
|
self->sock = -1;
|
||||||
|
self->isOpen = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BaseConnection::Write(const void* data, size_t length)
|
||||||
|
{
|
||||||
|
auto self = reinterpret_cast<BaseConnectionUnix*>(this);
|
||||||
|
|
||||||
|
if (self->sock == -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t sentBytes = send(self->sock, data, length, MsgFlags);
|
||||||
|
if (sentBytes < 0) {
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
return sentBytes == (ssize_t)length;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BaseConnection::Read(void* data, size_t length)
|
||||||
|
{
|
||||||
|
auto self = reinterpret_cast<BaseConnectionUnix*>(this);
|
||||||
|
|
||||||
|
if (self->sock == -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = (int)recv(self->sock, data, length, MsgFlags);
|
||||||
|
if (res < 0) {
|
||||||
|
if (errno == EAGAIN) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
else if (res == 0) {
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
return res == (int)length;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
132
libs/discordrpc/connection_win.cpp
Normal file
132
libs/discordrpc/connection_win.cpp
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
|
||||||
|
#include "connection.h"
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#define NOMCX
|
||||||
|
#define NOSERVICE
|
||||||
|
#define NOIME
|
||||||
|
#include <assert.h>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
int GetProcessId()
|
||||||
|
{
|
||||||
|
return (int)::GetCurrentProcessId();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BaseConnectionWin : public BaseConnection {
|
||||||
|
HANDLE pipe{INVALID_HANDLE_VALUE};
|
||||||
|
};
|
||||||
|
|
||||||
|
static BaseConnectionWin Connection;
|
||||||
|
|
||||||
|
/*static*/ BaseConnection* BaseConnection::Create()
|
||||||
|
{
|
||||||
|
return &Connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*static*/ void BaseConnection::Destroy(BaseConnection*& c)
|
||||||
|
{
|
||||||
|
auto self = reinterpret_cast<BaseConnectionWin*>(c);
|
||||||
|
self->Close();
|
||||||
|
c = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BaseConnection::Open()
|
||||||
|
{
|
||||||
|
wchar_t pipeName[]{L"\\\\?\\pipe\\discord-ipc-0"};
|
||||||
|
const size_t pipeDigit = sizeof(pipeName) / sizeof(wchar_t) - 2;
|
||||||
|
pipeName[pipeDigit] = L'0';
|
||||||
|
auto self = reinterpret_cast<BaseConnectionWin*>(this);
|
||||||
|
for (;;) {
|
||||||
|
self->pipe = ::CreateFileW(
|
||||||
|
pipeName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||||
|
if (self->pipe != INVALID_HANDLE_VALUE) {
|
||||||
|
self->isOpen = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto lastError = GetLastError();
|
||||||
|
if (lastError == ERROR_FILE_NOT_FOUND) {
|
||||||
|
if (pipeName[pipeDigit] < L'9') {
|
||||||
|
pipeName[pipeDigit]++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (lastError == ERROR_PIPE_BUSY) {
|
||||||
|
if (!WaitNamedPipeW(pipeName, 10000)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BaseConnection::Close()
|
||||||
|
{
|
||||||
|
auto self = reinterpret_cast<BaseConnectionWin*>(this);
|
||||||
|
::CloseHandle(self->pipe);
|
||||||
|
self->pipe = INVALID_HANDLE_VALUE;
|
||||||
|
self->isOpen = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BaseConnection::Write(const void* data, size_t length)
|
||||||
|
{
|
||||||
|
if (length == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
auto self = reinterpret_cast<BaseConnectionWin*>(this);
|
||||||
|
assert(self);
|
||||||
|
if (!self) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (self->pipe == INVALID_HANDLE_VALUE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
assert(data);
|
||||||
|
if (!data) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const DWORD bytesLength = (DWORD)length;
|
||||||
|
DWORD bytesWritten = 0;
|
||||||
|
return ::WriteFile(self->pipe, data, bytesLength, &bytesWritten, nullptr) == TRUE &&
|
||||||
|
bytesWritten == bytesLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BaseConnection::Read(void* data, size_t length)
|
||||||
|
{
|
||||||
|
assert(data);
|
||||||
|
if (!data) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto self = reinterpret_cast<BaseConnectionWin*>(this);
|
||||||
|
assert(self);
|
||||||
|
if (!self) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (self->pipe == INVALID_HANDLE_VALUE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
DWORD bytesAvailable = 0;
|
||||||
|
if (::PeekNamedPipe(self->pipe, nullptr, 0, nullptr, &bytesAvailable, nullptr)) {
|
||||||
|
if (bytesAvailable >= length) {
|
||||||
|
DWORD bytesToRead = (DWORD)length;
|
||||||
|
DWORD bytesRead = 0;
|
||||||
|
if (::ReadFile(self->pipe, data, bytesToRead, &bytesRead, nullptr) == TRUE) {
|
||||||
|
assert(bytesToRead == bytesRead);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
26
libs/discordrpc/discord_register.h
Normal file
26
libs/discordrpc/discord_register.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if defined(DISCORD_DYNAMIC_LIB)
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#if defined(DISCORD_BUILDING_SDK)
|
||||||
|
#define DISCORD_EXPORT __declspec(dllexport)
|
||||||
|
#else
|
||||||
|
#define DISCORD_EXPORT __declspec(dllimport)
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define DISCORD_EXPORT __attribute__((visibility("default")))
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define DISCORD_EXPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DISCORD_EXPORT void Discord_Register(const char* applicationId, const char* command);
|
||||||
|
DISCORD_EXPORT void Discord_RegisterSteamGame(const char* applicationId, const char* steamId);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
106
libs/discordrpc/discord_register_linux.cpp
Normal file
106
libs/discordrpc/discord_register_linux.cpp
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
#ifdef __unix__
|
||||||
|
|
||||||
|
#include "discord_rpc.h"
|
||||||
|
#include "discord_register.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
static bool Mkdir(const char* path)
|
||||||
|
{
|
||||||
|
int result = mkdir(path, 0755);
|
||||||
|
if (result == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (errno == EEXIST) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we want to register games so we can run them from Discord client as discord-<appid>://
|
||||||
|
extern "C" DISCORD_EXPORT void Discord_Register(const char* applicationId, const char* command)
|
||||||
|
{
|
||||||
|
// Add a desktop file and update some mime handlers so that xdg-open does the right thing.
|
||||||
|
|
||||||
|
const char* home = getenv("HOME");
|
||||||
|
if (!home) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char exePath[1024];
|
||||||
|
if (!command || !command[0]) {
|
||||||
|
ssize_t size = readlink("/proc/self/exe", exePath, sizeof(exePath));
|
||||||
|
if (size <= 0 || size >= (ssize_t)sizeof(exePath)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
exePath[size] = '\0';
|
||||||
|
command = exePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* desktopFileFormat = "[Desktop Entry]\n"
|
||||||
|
"Name=Game %s\n"
|
||||||
|
"Exec=%s %%u\n" // note: it really wants that %u in there
|
||||||
|
"Type=Application\n"
|
||||||
|
"NoDisplay=true\n"
|
||||||
|
"Categories=Discord;Games;\n"
|
||||||
|
"MimeType=x-scheme-handler/discord-%s;\n";
|
||||||
|
char desktopFile[2048];
|
||||||
|
int fileLen = snprintf(
|
||||||
|
desktopFile, sizeof(desktopFile), desktopFileFormat, applicationId, command, applicationId);
|
||||||
|
if (fileLen <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char desktopFilename[256];
|
||||||
|
snprintf(desktopFilename, sizeof(desktopFilename), "/discord-%s.desktop", applicationId);
|
||||||
|
|
||||||
|
char desktopFilePath[1024];
|
||||||
|
snprintf(desktopFilePath, sizeof(desktopFilePath), "%s/.local", home);
|
||||||
|
if (!Mkdir(desktopFilePath)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
strcat(desktopFilePath, "/share");
|
||||||
|
if (!Mkdir(desktopFilePath)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
strcat(desktopFilePath, "/applications");
|
||||||
|
if (!Mkdir(desktopFilePath)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
strcat(desktopFilePath, desktopFilename);
|
||||||
|
|
||||||
|
FILE* fp = fopen(desktopFilePath, "w");
|
||||||
|
if (fp) {
|
||||||
|
fwrite(desktopFile, 1, fileLen, fp);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char xdgMimeCommand[1024];
|
||||||
|
snprintf(xdgMimeCommand,
|
||||||
|
sizeof(xdgMimeCommand),
|
||||||
|
"xdg-mime default discord-%s.desktop x-scheme-handler/discord-%s",
|
||||||
|
applicationId,
|
||||||
|
applicationId);
|
||||||
|
if (system(xdgMimeCommand) < 0) {
|
||||||
|
fprintf(stderr, "Failed to register mime handler\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" DISCORD_EXPORT void Discord_RegisterSteamGame(const char* applicationId,
|
||||||
|
const char* steamId)
|
||||||
|
{
|
||||||
|
char command[256];
|
||||||
|
sprintf(command, "xdg-open steam://rungameid/%s", steamId);
|
||||||
|
Discord_Register(applicationId, command);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
190
libs/discordrpc/discord_register_win.cpp
Normal file
190
libs/discordrpc/discord_register_win.cpp
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
|
||||||
|
#include "discord_rpc.h"
|
||||||
|
#include "discord_register.h"
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#define NOMCX
|
||||||
|
#define NOSERVICE
|
||||||
|
#define NOIME
|
||||||
|
#include <windows.h>
|
||||||
|
#include <psapi.h>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updated fixes for MinGW and WinXP
|
||||||
|
* This block is written the way it does not involve changing the rest of the code
|
||||||
|
* Checked to be compiling
|
||||||
|
* 1) strsafe.h belongs to Windows SDK and cannot be added to MinGW
|
||||||
|
* #include guarded, functions redirected to <string.h> substitutes
|
||||||
|
* 2) RegSetKeyValueW and LSTATUS are not declared in <winreg.h>
|
||||||
|
* The entire function is rewritten
|
||||||
|
*/
|
||||||
|
#ifdef __MINGW32__
|
||||||
|
#include <wchar.h>
|
||||||
|
/// strsafe.h fixes
|
||||||
|
static HRESULT StringCbPrintfW(LPWSTR pszDest, size_t cbDest, LPCWSTR pszFormat, ...)
|
||||||
|
{
|
||||||
|
HRESULT ret;
|
||||||
|
va_list va;
|
||||||
|
va_start(va, pszFormat);
|
||||||
|
cbDest /= 2; // Size is divided by 2 to convert from bytes to wide characters - causes segfault
|
||||||
|
// othervise
|
||||||
|
ret = vsnwprintf(pszDest, cbDest, pszFormat, va);
|
||||||
|
pszDest[cbDest - 1] = 0; // Terminate the string in case a buffer overflow; -1 will be returned
|
||||||
|
va_end(va);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#include <cwchar>
|
||||||
|
#include <strsafe.h>
|
||||||
|
#endif // __MINGW32__
|
||||||
|
|
||||||
|
/// winreg.h fixes
|
||||||
|
#ifndef LSTATUS
|
||||||
|
#define LSTATUS LONG
|
||||||
|
#endif
|
||||||
|
#ifdef RegSetKeyValueW
|
||||||
|
#undefine RegSetKeyValueW
|
||||||
|
#endif
|
||||||
|
#define RegSetKeyValueW regset
|
||||||
|
static LSTATUS regset(HKEY hkey,
|
||||||
|
LPCWSTR subkey,
|
||||||
|
LPCWSTR name,
|
||||||
|
DWORD type,
|
||||||
|
const void* data,
|
||||||
|
DWORD len)
|
||||||
|
{
|
||||||
|
HKEY htkey = hkey, hsubkey = nullptr;
|
||||||
|
LSTATUS ret;
|
||||||
|
if (subkey && subkey[0]) {
|
||||||
|
if ((ret = RegCreateKeyExW(hkey, subkey, 0, 0, 0, KEY_ALL_ACCESS, 0, &hsubkey, 0)) !=
|
||||||
|
ERROR_SUCCESS)
|
||||||
|
return ret;
|
||||||
|
htkey = hsubkey;
|
||||||
|
}
|
||||||
|
ret = RegSetValueExW(htkey, name, 0, type, (const BYTE*)data, len);
|
||||||
|
if (hsubkey && hsubkey != hkey)
|
||||||
|
RegCloseKey(hsubkey);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Discord_RegisterW(const wchar_t* applicationId, const wchar_t* command)
|
||||||
|
{
|
||||||
|
// https://msdn.microsoft.com/en-us/library/aa767914(v=vs.85).aspx
|
||||||
|
// we want to register games so we can run them as discord-<appid>://
|
||||||
|
// Update the HKEY_CURRENT_USER, because it doesn't seem to require special permissions.
|
||||||
|
|
||||||
|
wchar_t exeFilePath[MAX_PATH];
|
||||||
|
DWORD exeLen = GetModuleFileNameW(nullptr, exeFilePath, MAX_PATH);
|
||||||
|
wchar_t openCommand[1024];
|
||||||
|
|
||||||
|
if (command && command[0]) {
|
||||||
|
StringCbPrintfW(openCommand, sizeof(openCommand), L"%s", command);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// StringCbCopyW(openCommand, sizeof(openCommand), exeFilePath);
|
||||||
|
StringCbPrintfW(openCommand, sizeof(openCommand), L"%s", exeFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t protocolName[64];
|
||||||
|
StringCbPrintfW(protocolName, sizeof(protocolName), L"discord-%s", applicationId);
|
||||||
|
wchar_t protocolDescription[128];
|
||||||
|
StringCbPrintfW(
|
||||||
|
protocolDescription, sizeof(protocolDescription), L"URL:Run game %s protocol", applicationId);
|
||||||
|
wchar_t urlProtocol = 0;
|
||||||
|
|
||||||
|
wchar_t keyName[256];
|
||||||
|
StringCbPrintfW(keyName, sizeof(keyName), L"Software\\Classes\\%s", protocolName);
|
||||||
|
HKEY key;
|
||||||
|
auto status =
|
||||||
|
RegCreateKeyExW(HKEY_CURRENT_USER, keyName, 0, nullptr, 0, KEY_WRITE, nullptr, &key, nullptr);
|
||||||
|
if (status != ERROR_SUCCESS) {
|
||||||
|
fprintf(stderr, "Error creating key\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DWORD len;
|
||||||
|
LSTATUS result;
|
||||||
|
len = (DWORD)lstrlenW(protocolDescription) + 1;
|
||||||
|
result =
|
||||||
|
RegSetKeyValueW(key, nullptr, nullptr, REG_SZ, protocolDescription, len * sizeof(wchar_t));
|
||||||
|
if (FAILED(result)) {
|
||||||
|
fprintf(stderr, "Error writing description\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
len = (DWORD)lstrlenW(protocolDescription) + 1;
|
||||||
|
result = RegSetKeyValueW(key, nullptr, L"URL Protocol", REG_SZ, &urlProtocol, sizeof(wchar_t));
|
||||||
|
if (FAILED(result)) {
|
||||||
|
fprintf(stderr, "Error writing description\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
result = RegSetKeyValueW(
|
||||||
|
key, L"DefaultIcon", nullptr, REG_SZ, exeFilePath, (exeLen + 1) * sizeof(wchar_t));
|
||||||
|
if (FAILED(result)) {
|
||||||
|
fprintf(stderr, "Error writing icon\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
len = (DWORD)lstrlenW(openCommand) + 1;
|
||||||
|
result = RegSetKeyValueW(
|
||||||
|
key, L"shell\\open\\command", nullptr, REG_SZ, openCommand, len * sizeof(wchar_t));
|
||||||
|
if (FAILED(result)) {
|
||||||
|
fprintf(stderr, "Error writing command\n");
|
||||||
|
}
|
||||||
|
RegCloseKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" DISCORD_EXPORT void Discord_Register(const char* applicationId, const char* command)
|
||||||
|
{
|
||||||
|
wchar_t appId[32];
|
||||||
|
MultiByteToWideChar(CP_UTF8, 0, applicationId, -1, appId, 32);
|
||||||
|
|
||||||
|
wchar_t openCommand[1024];
|
||||||
|
const wchar_t* wcommand = nullptr;
|
||||||
|
if (command && command[0]) {
|
||||||
|
const auto commandBufferLen = sizeof(openCommand) / sizeof(*openCommand);
|
||||||
|
MultiByteToWideChar(CP_UTF8, 0, command, -1, openCommand, commandBufferLen);
|
||||||
|
wcommand = openCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
Discord_RegisterW(appId, wcommand);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" DISCORD_EXPORT void Discord_RegisterSteamGame(const char* applicationId,
|
||||||
|
const char* steamId)
|
||||||
|
{
|
||||||
|
wchar_t appId[32];
|
||||||
|
MultiByteToWideChar(CP_UTF8, 0, applicationId, -1, appId, 32);
|
||||||
|
|
||||||
|
wchar_t wSteamId[32];
|
||||||
|
MultiByteToWideChar(CP_UTF8, 0, steamId, -1, wSteamId, 32);
|
||||||
|
|
||||||
|
HKEY key;
|
||||||
|
auto status = RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Valve\\Steam", 0, KEY_READ, &key);
|
||||||
|
if (status != ERROR_SUCCESS) {
|
||||||
|
fprintf(stderr, "Error opening Steam key\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t steamPath[MAX_PATH];
|
||||||
|
DWORD pathBytes = sizeof(steamPath);
|
||||||
|
status = RegQueryValueExW(key, L"SteamExe", nullptr, nullptr, (BYTE*)steamPath, &pathBytes);
|
||||||
|
RegCloseKey(key);
|
||||||
|
if (status != ERROR_SUCCESS || pathBytes < 1) {
|
||||||
|
fprintf(stderr, "Error reading SteamExe key\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD pathChars = pathBytes / sizeof(wchar_t);
|
||||||
|
for (DWORD i = 0; i < pathChars; ++i) {
|
||||||
|
if (steamPath[i] == L'/') {
|
||||||
|
steamPath[i] = L'\\';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t command[1024];
|
||||||
|
StringCbPrintfW(command, sizeof(command), L"\"%s\" steam://rungameid/%s", steamPath, wSteamId);
|
||||||
|
|
||||||
|
Discord_RegisterW(appId, command);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
504
libs/discordrpc/discord_rpc.cpp
Normal file
504
libs/discordrpc/discord_rpc.cpp
Normal file
@@ -0,0 +1,504 @@
|
|||||||
|
#include "discord_rpc.h"
|
||||||
|
|
||||||
|
#include "backoff.h"
|
||||||
|
#include "discord_register.h"
|
||||||
|
#include "msg_queue.h"
|
||||||
|
#include "rpc_connection.h"
|
||||||
|
#include "serialization.h"
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <chrono>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
#ifndef DISCORD_DISABLE_IO_THREAD
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <thread>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
constexpr size_t MaxMessageSize{16 * 1024};
|
||||||
|
constexpr size_t MessageQueueSize{8};
|
||||||
|
constexpr size_t JoinQueueSize{8};
|
||||||
|
|
||||||
|
struct QueuedMessage {
|
||||||
|
size_t length;
|
||||||
|
char buffer[MaxMessageSize];
|
||||||
|
|
||||||
|
void Copy(const QueuedMessage& other)
|
||||||
|
{
|
||||||
|
length = other.length;
|
||||||
|
if (length) {
|
||||||
|
memcpy(buffer, other.buffer, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct User {
|
||||||
|
// snowflake (64bit int), turned into a ascii decimal string, at most 20 chars +1 null
|
||||||
|
// terminator = 21
|
||||||
|
char userId[32];
|
||||||
|
// 32 unicode glyphs is max name size => 4 bytes per glyph in the worst case, +1 for null
|
||||||
|
// terminator = 129
|
||||||
|
char username[344];
|
||||||
|
// 4 decimal digits + 1 null terminator = 5
|
||||||
|
char discriminator[8];
|
||||||
|
// optional 'a_' + md5 hex digest (32 bytes) + null terminator = 35
|
||||||
|
char avatar[128];
|
||||||
|
// Rounded way up because I'm paranoid about games breaking from future changes in these sizes
|
||||||
|
};
|
||||||
|
|
||||||
|
static RpcConnection* Connection{nullptr};
|
||||||
|
static DiscordEventHandlers QueuedHandlers{};
|
||||||
|
static DiscordEventHandlers Handlers{};
|
||||||
|
static std::atomic_bool WasJustConnected{false};
|
||||||
|
static std::atomic_bool WasJustDisconnected{false};
|
||||||
|
static std::atomic_bool GotErrorMessage{false};
|
||||||
|
static std::atomic_bool WasJoinGame{false};
|
||||||
|
static std::atomic_bool WasSpectateGame{false};
|
||||||
|
static std::atomic_bool UpdatePresence{false};
|
||||||
|
static char JoinGameSecret[256];
|
||||||
|
static char SpectateGameSecret[256];
|
||||||
|
static int LastErrorCode{0};
|
||||||
|
static char LastErrorMessage[256];
|
||||||
|
static int LastDisconnectErrorCode{0};
|
||||||
|
static char LastDisconnectErrorMessage[256];
|
||||||
|
static std::mutex PresenceMutex;
|
||||||
|
static std::mutex HandlerMutex;
|
||||||
|
static QueuedMessage QueuedPresence{};
|
||||||
|
static MsgQueue<QueuedMessage, MessageQueueSize> SendQueue;
|
||||||
|
static MsgQueue<User, JoinQueueSize> JoinAskQueue;
|
||||||
|
static User connectedUser;
|
||||||
|
|
||||||
|
// We want to auto connect, and retry on failure, but not as fast as possible. This does expoential
|
||||||
|
// backoff from 0.5 seconds to 1 minute
|
||||||
|
static Backoff ReconnectTimeMs(500, 60 * 1000);
|
||||||
|
static auto NextConnect = std::chrono::system_clock::now();
|
||||||
|
static int Pid{0};
|
||||||
|
static int Nonce{1};
|
||||||
|
|
||||||
|
#ifndef DISCORD_DISABLE_IO_THREAD
|
||||||
|
static void Discord_UpdateConnection(void);
|
||||||
|
class IoThreadHolder {
|
||||||
|
private:
|
||||||
|
std::atomic_bool keepRunning{true};
|
||||||
|
std::mutex waitForIOMutex;
|
||||||
|
std::condition_variable waitForIOActivity;
|
||||||
|
std::thread ioThread;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void Start()
|
||||||
|
{
|
||||||
|
keepRunning.store(true);
|
||||||
|
ioThread = std::thread([&]() {
|
||||||
|
const std::chrono::duration<int64_t, std::milli> maxWait{500LL};
|
||||||
|
Discord_UpdateConnection();
|
||||||
|
while (keepRunning.load()) {
|
||||||
|
std::unique_lock<std::mutex> lock(waitForIOMutex);
|
||||||
|
waitForIOActivity.wait_for(lock, maxWait);
|
||||||
|
Discord_UpdateConnection();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Notify() { waitForIOActivity.notify_all(); }
|
||||||
|
|
||||||
|
void Stop()
|
||||||
|
{
|
||||||
|
keepRunning.exchange(false);
|
||||||
|
Notify();
|
||||||
|
if (ioThread.joinable()) {
|
||||||
|
ioThread.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~IoThreadHolder() { Stop(); }
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
class IoThreadHolder {
|
||||||
|
public:
|
||||||
|
void Start() {}
|
||||||
|
void Stop() {}
|
||||||
|
void Notify() {}
|
||||||
|
};
|
||||||
|
#endif // DISCORD_DISABLE_IO_THREAD
|
||||||
|
static IoThreadHolder* IoThread{nullptr};
|
||||||
|
|
||||||
|
static void UpdateReconnectTime()
|
||||||
|
{
|
||||||
|
NextConnect = std::chrono::system_clock::now() +
|
||||||
|
std::chrono::duration<int64_t, std::milli>{ReconnectTimeMs.nextDelay()};
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DISCORD_DISABLE_IO_THREAD
|
||||||
|
extern "C" DISCORD_EXPORT void Discord_UpdateConnection(void)
|
||||||
|
#else
|
||||||
|
static void Discord_UpdateConnection(void)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if (!Connection) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Connection->IsOpen()) {
|
||||||
|
if (std::chrono::system_clock::now() >= NextConnect) {
|
||||||
|
UpdateReconnectTime();
|
||||||
|
Connection->Open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// reads
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
JsonDocument message;
|
||||||
|
|
||||||
|
if (!Connection->Read(message)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* evtName = GetStrMember(&message, "evt");
|
||||||
|
const char* nonce = GetStrMember(&message, "nonce");
|
||||||
|
|
||||||
|
if (nonce) {
|
||||||
|
// in responses only -- should use to match up response when needed.
|
||||||
|
|
||||||
|
if (evtName && strcmp(evtName, "ERROR") == 0) {
|
||||||
|
auto data = GetObjMember(&message, "data");
|
||||||
|
LastErrorCode = GetIntMember(data, "code");
|
||||||
|
StringCopy(LastErrorMessage, GetStrMember(data, "message", ""));
|
||||||
|
GotErrorMessage.store(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// should have evt == name of event, optional data
|
||||||
|
if (evtName == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto data = GetObjMember(&message, "data");
|
||||||
|
|
||||||
|
if (strcmp(evtName, "ACTIVITY_JOIN") == 0) {
|
||||||
|
auto secret = GetStrMember(data, "secret");
|
||||||
|
if (secret) {
|
||||||
|
StringCopy(JoinGameSecret, secret);
|
||||||
|
WasJoinGame.store(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp(evtName, "ACTIVITY_SPECTATE") == 0) {
|
||||||
|
auto secret = GetStrMember(data, "secret");
|
||||||
|
if (secret) {
|
||||||
|
StringCopy(SpectateGameSecret, secret);
|
||||||
|
WasSpectateGame.store(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp(evtName, "ACTIVITY_JOIN_REQUEST") == 0) {
|
||||||
|
auto user = GetObjMember(data, "user");
|
||||||
|
auto userId = GetStrMember(user, "id");
|
||||||
|
auto username = GetStrMember(user, "username");
|
||||||
|
auto avatar = GetStrMember(user, "avatar");
|
||||||
|
auto joinReq = JoinAskQueue.GetNextAddMessage();
|
||||||
|
if (userId && username && joinReq) {
|
||||||
|
StringCopy(joinReq->userId, userId);
|
||||||
|
StringCopy(joinReq->username, username);
|
||||||
|
auto discriminator = GetStrMember(user, "discriminator");
|
||||||
|
if (discriminator) {
|
||||||
|
StringCopy(joinReq->discriminator, discriminator);
|
||||||
|
}
|
||||||
|
if (avatar) {
|
||||||
|
StringCopy(joinReq->avatar, avatar);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
joinReq->avatar[0] = 0;
|
||||||
|
}
|
||||||
|
JoinAskQueue.CommitAdd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// writes
|
||||||
|
if (UpdatePresence.exchange(false) && QueuedPresence.length) {
|
||||||
|
QueuedMessage local;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> guard(PresenceMutex);
|
||||||
|
local.Copy(QueuedPresence);
|
||||||
|
}
|
||||||
|
if (!Connection->Write(local.buffer, local.length)) {
|
||||||
|
// if we fail to send, requeue
|
||||||
|
std::lock_guard<std::mutex> guard(PresenceMutex);
|
||||||
|
QueuedPresence.Copy(local);
|
||||||
|
UpdatePresence.exchange(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (SendQueue.HavePendingSends()) {
|
||||||
|
auto qmessage = SendQueue.GetNextSendMessage();
|
||||||
|
Connection->Write(qmessage->buffer, qmessage->length);
|
||||||
|
SendQueue.CommitSend();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SignalIOActivity()
|
||||||
|
{
|
||||||
|
if (IoThread != nullptr) {
|
||||||
|
IoThread->Notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool RegisterForEvent(const char* evtName)
|
||||||
|
{
|
||||||
|
auto qmessage = SendQueue.GetNextAddMessage();
|
||||||
|
if (qmessage) {
|
||||||
|
qmessage->length =
|
||||||
|
JsonWriteSubscribeCommand(qmessage->buffer, sizeof(qmessage->buffer), Nonce++, evtName);
|
||||||
|
SendQueue.CommitAdd();
|
||||||
|
SignalIOActivity();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool DeregisterForEvent(const char* evtName)
|
||||||
|
{
|
||||||
|
auto qmessage = SendQueue.GetNextAddMessage();
|
||||||
|
if (qmessage) {
|
||||||
|
qmessage->length =
|
||||||
|
JsonWriteUnsubscribeCommand(qmessage->buffer, sizeof(qmessage->buffer), Nonce++, evtName);
|
||||||
|
SendQueue.CommitAdd();
|
||||||
|
SignalIOActivity();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" DISCORD_EXPORT void Discord_Initialize(const char* applicationId,
|
||||||
|
DiscordEventHandlers* handlers,
|
||||||
|
int autoRegister,
|
||||||
|
const char* optionalSteamId)
|
||||||
|
{
|
||||||
|
IoThread = new (std::nothrow) IoThreadHolder();
|
||||||
|
if (IoThread == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (autoRegister) {
|
||||||
|
if (optionalSteamId && optionalSteamId[0]) {
|
||||||
|
Discord_RegisterSteamGame(applicationId, optionalSteamId);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Discord_Register(applicationId, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Pid = GetProcessId();
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> guard(HandlerMutex);
|
||||||
|
|
||||||
|
if (handlers) {
|
||||||
|
QueuedHandlers = *handlers;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
QueuedHandlers = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Handlers = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Connection) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Connection = RpcConnection::Create(applicationId);
|
||||||
|
Connection->onConnect = [](JsonDocument& readyMessage) {
|
||||||
|
Discord_UpdateHandlers(&QueuedHandlers);
|
||||||
|
if (QueuedPresence.length > 0) {
|
||||||
|
UpdatePresence.exchange(true);
|
||||||
|
SignalIOActivity();
|
||||||
|
}
|
||||||
|
auto data = GetObjMember(&readyMessage, "data");
|
||||||
|
auto user = GetObjMember(data, "user");
|
||||||
|
auto userId = GetStrMember(user, "id");
|
||||||
|
auto username = GetStrMember(user, "username");
|
||||||
|
auto avatar = GetStrMember(user, "avatar");
|
||||||
|
if (userId && username) {
|
||||||
|
StringCopy(connectedUser.userId, userId);
|
||||||
|
StringCopy(connectedUser.username, username);
|
||||||
|
auto discriminator = GetStrMember(user, "discriminator");
|
||||||
|
if (discriminator) {
|
||||||
|
StringCopy(connectedUser.discriminator, discriminator);
|
||||||
|
}
|
||||||
|
if (avatar) {
|
||||||
|
StringCopy(connectedUser.avatar, avatar);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
connectedUser.avatar[0] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WasJustConnected.exchange(true);
|
||||||
|
ReconnectTimeMs.reset();
|
||||||
|
};
|
||||||
|
Connection->onDisconnect = [](int err, const char* message) {
|
||||||
|
LastDisconnectErrorCode = err;
|
||||||
|
StringCopy(LastDisconnectErrorMessage, message);
|
||||||
|
WasJustDisconnected.exchange(true);
|
||||||
|
UpdateReconnectTime();
|
||||||
|
};
|
||||||
|
|
||||||
|
IoThread->Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" DISCORD_EXPORT void Discord_Shutdown(void)
|
||||||
|
{
|
||||||
|
if (!Connection) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Connection->onConnect = nullptr;
|
||||||
|
Connection->onDisconnect = nullptr;
|
||||||
|
Handlers = {};
|
||||||
|
QueuedPresence.length = 0;
|
||||||
|
UpdatePresence.exchange(false);
|
||||||
|
if (IoThread != nullptr) {
|
||||||
|
IoThread->Stop();
|
||||||
|
delete IoThread;
|
||||||
|
IoThread = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
RpcConnection::Destroy(Connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" DISCORD_EXPORT void Discord_UpdatePresence(const DiscordRichPresence* presence)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> guard(PresenceMutex);
|
||||||
|
QueuedPresence.length = JsonWriteRichPresenceObj(
|
||||||
|
QueuedPresence.buffer, sizeof(QueuedPresence.buffer), Nonce++, Pid, presence);
|
||||||
|
UpdatePresence.exchange(true);
|
||||||
|
}
|
||||||
|
SignalIOActivity();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" DISCORD_EXPORT void Discord_ClearPresence(void)
|
||||||
|
{
|
||||||
|
Discord_UpdatePresence(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" DISCORD_EXPORT void Discord_Respond(const char* userId, /* DISCORD_REPLY_ */ int reply)
|
||||||
|
{
|
||||||
|
// if we are not connected, let's not batch up stale messages for later
|
||||||
|
if (!Connection || !Connection->IsOpen()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto qmessage = SendQueue.GetNextAddMessage();
|
||||||
|
if (qmessage) {
|
||||||
|
qmessage->length =
|
||||||
|
JsonWriteJoinReply(qmessage->buffer, sizeof(qmessage->buffer), userId, reply, Nonce++);
|
||||||
|
SendQueue.CommitAdd();
|
||||||
|
SignalIOActivity();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" DISCORD_EXPORT void Discord_RunCallbacks(void)
|
||||||
|
{
|
||||||
|
// Note on some weirdness: internally we might connect, get other signals, disconnect any number
|
||||||
|
// of times inbetween calls here. Externally, we want the sequence to seem sane, so any other
|
||||||
|
// signals are book-ended by calls to ready and disconnect.
|
||||||
|
|
||||||
|
if (!Connection) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wasDisconnected = WasJustDisconnected.exchange(false);
|
||||||
|
bool isConnected = Connection->IsOpen();
|
||||||
|
|
||||||
|
if (isConnected) {
|
||||||
|
// if we are connected, disconnect cb first
|
||||||
|
std::lock_guard<std::mutex> guard(HandlerMutex);
|
||||||
|
if (wasDisconnected && Handlers.disconnected) {
|
||||||
|
Handlers.disconnected(LastDisconnectErrorCode, LastDisconnectErrorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WasJustConnected.exchange(false)) {
|
||||||
|
std::lock_guard<std::mutex> guard(HandlerMutex);
|
||||||
|
if (Handlers.ready) {
|
||||||
|
DiscordUser du{connectedUser.userId,
|
||||||
|
connectedUser.username,
|
||||||
|
connectedUser.discriminator,
|
||||||
|
connectedUser.avatar};
|
||||||
|
Handlers.ready(&du);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GotErrorMessage.exchange(false)) {
|
||||||
|
std::lock_guard<std::mutex> guard(HandlerMutex);
|
||||||
|
if (Handlers.errored) {
|
||||||
|
Handlers.errored(LastErrorCode, LastErrorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WasJoinGame.exchange(false)) {
|
||||||
|
std::lock_guard<std::mutex> guard(HandlerMutex);
|
||||||
|
if (Handlers.joinGame) {
|
||||||
|
Handlers.joinGame(JoinGameSecret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WasSpectateGame.exchange(false)) {
|
||||||
|
std::lock_guard<std::mutex> guard(HandlerMutex);
|
||||||
|
if (Handlers.spectateGame) {
|
||||||
|
Handlers.spectateGame(SpectateGameSecret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Right now this batches up any requests and sends them all in a burst; I could imagine a world
|
||||||
|
// where the implementer would rather sequentially accept/reject each one before the next invite
|
||||||
|
// is sent. I left it this way because I could also imagine wanting to process these all and
|
||||||
|
// maybe show them in one common dialog and/or start fetching the avatars in parallel, and if
|
||||||
|
// not it should be trivial for the implementer to make a queue themselves.
|
||||||
|
while (JoinAskQueue.HavePendingSends()) {
|
||||||
|
auto req = JoinAskQueue.GetNextSendMessage();
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> guard(HandlerMutex);
|
||||||
|
if (Handlers.joinRequest) {
|
||||||
|
DiscordUser du{req->userId, req->username, req->discriminator, req->avatar};
|
||||||
|
Handlers.joinRequest(&du);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
JoinAskQueue.CommitSend();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isConnected) {
|
||||||
|
// if we are not connected, disconnect message last
|
||||||
|
std::lock_guard<std::mutex> guard(HandlerMutex);
|
||||||
|
if (wasDisconnected && Handlers.disconnected) {
|
||||||
|
Handlers.disconnected(LastDisconnectErrorCode, LastDisconnectErrorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" DISCORD_EXPORT void Discord_UpdateHandlers(DiscordEventHandlers* newHandlers)
|
||||||
|
{
|
||||||
|
if (newHandlers) {
|
||||||
|
#define HANDLE_EVENT_REGISTRATION(handler_name, event) \
|
||||||
|
if (!Handlers.handler_name && newHandlers->handler_name) { \
|
||||||
|
RegisterForEvent(event); \
|
||||||
|
} \
|
||||||
|
else if (Handlers.handler_name && !newHandlers->handler_name) { \
|
||||||
|
DeregisterForEvent(event); \
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> guard(HandlerMutex);
|
||||||
|
HANDLE_EVENT_REGISTRATION(joinGame, "ACTIVITY_JOIN")
|
||||||
|
HANDLE_EVENT_REGISTRATION(spectateGame, "ACTIVITY_SPECTATE")
|
||||||
|
HANDLE_EVENT_REGISTRATION(joinRequest, "ACTIVITY_JOIN_REQUEST")
|
||||||
|
|
||||||
|
#undef HANDLE_EVENT_REGISTRATION
|
||||||
|
|
||||||
|
Handlers = *newHandlers;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
std::lock_guard<std::mutex> guard(HandlerMutex);
|
||||||
|
Handlers = {};
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
90
libs/discordrpc/discord_rpc.h
Normal file
90
libs/discordrpc/discord_rpc.h
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
|
#if defined(DISCORD_DYNAMIC_LIB)
|
||||||
|
# if defined(_WIN32)
|
||||||
|
# if defined(DISCORD_BUILDING_SDK)
|
||||||
|
# define DISCORD_EXPORT __declspec(dllexport)
|
||||||
|
# else
|
||||||
|
# define DISCORD_EXPORT __declspec(dllimport)
|
||||||
|
# endif
|
||||||
|
# else
|
||||||
|
# define DISCORD_EXPORT __attribute__((visibility("default")))
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define DISCORD_EXPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct DiscordRichPresence {
|
||||||
|
const char* state; /* max 128 bytes */
|
||||||
|
const char* details; /* max 128 bytes */
|
||||||
|
int64_t startTimestamp;
|
||||||
|
int64_t endTimestamp;
|
||||||
|
const char* largeImageKey; /* max 32 bytes */
|
||||||
|
const char* largeImageText; /* max 128 bytes */
|
||||||
|
const char* smallImageKey; /* max 32 bytes */
|
||||||
|
const char* smallImageText; /* max 128 bytes */
|
||||||
|
const char* partyId; /* max 128 bytes */
|
||||||
|
int partySize;
|
||||||
|
int partyMax;
|
||||||
|
int partyPrivacy;
|
||||||
|
const char* matchSecret; /* max 128 bytes */
|
||||||
|
const char* joinSecret; /* max 128 bytes */
|
||||||
|
const char* spectateSecret; /* max 128 bytes */
|
||||||
|
int8_t instance;
|
||||||
|
} DiscordRichPresence;
|
||||||
|
|
||||||
|
typedef struct DiscordUser {
|
||||||
|
const char* userId;
|
||||||
|
const char* username;
|
||||||
|
const char* discriminator;
|
||||||
|
const char* avatar;
|
||||||
|
} DiscordUser;
|
||||||
|
|
||||||
|
typedef struct DiscordEventHandlers {
|
||||||
|
void (*ready)(const DiscordUser* request);
|
||||||
|
void (*disconnected)(int errorCode, const char* message);
|
||||||
|
void (*errored)(int errorCode, const char* message);
|
||||||
|
void (*joinGame)(const char* joinSecret);
|
||||||
|
void (*spectateGame)(const char* spectateSecret);
|
||||||
|
void (*joinRequest)(const DiscordUser* request);
|
||||||
|
} DiscordEventHandlers;
|
||||||
|
|
||||||
|
#define DISCORD_REPLY_NO 0
|
||||||
|
#define DISCORD_REPLY_YES 1
|
||||||
|
#define DISCORD_REPLY_IGNORE 2
|
||||||
|
#define DISCORD_PARTY_PRIVATE 0
|
||||||
|
#define DISCORD_PARTY_PUBLIC 1
|
||||||
|
|
||||||
|
DISCORD_EXPORT void Discord_Initialize(const char* applicationId,
|
||||||
|
DiscordEventHandlers* handlers,
|
||||||
|
int autoRegister,
|
||||||
|
const char* optionalSteamId);
|
||||||
|
DISCORD_EXPORT void Discord_Shutdown(void);
|
||||||
|
|
||||||
|
/* checks for incoming messages, dispatches callbacks */
|
||||||
|
DISCORD_EXPORT void Discord_RunCallbacks(void);
|
||||||
|
|
||||||
|
/* If you disable the lib starting its own io thread, you'll need to call this from your own */
|
||||||
|
#ifdef DISCORD_DISABLE_IO_THREAD
|
||||||
|
DISCORD_EXPORT void Discord_UpdateConnection(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DISCORD_EXPORT void Discord_UpdatePresence(const DiscordRichPresence* presence);
|
||||||
|
DISCORD_EXPORT void Discord_ClearPresence(void);
|
||||||
|
|
||||||
|
DISCORD_EXPORT void Discord_Respond(const char* userid, /* DISCORD_REPLY_ */ int reply);
|
||||||
|
|
||||||
|
DISCORD_EXPORT void Discord_UpdateHandlers(DiscordEventHandlers* handlers);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
12
libs/discordrpc/dllmain.cpp
Normal file
12
libs/discordrpc/dllmain.cpp
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
// outsmart GCC's missing-declarations warning
|
||||||
|
BOOL WINAPI DllMain(HMODULE, DWORD, LPVOID);
|
||||||
|
BOOL WINAPI DllMain(HMODULE, DWORD, LPVOID)
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
36
libs/discordrpc/msg_queue.h
Normal file
36
libs/discordrpc/msg_queue.h
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
// A simple queue. No locks, but only works with a single thread as producer and a single thread as
|
||||||
|
// a consumer. Mutex up as needed.
|
||||||
|
|
||||||
|
template <typename ElementType, size_t QueueSize>
|
||||||
|
class MsgQueue {
|
||||||
|
ElementType queue_[QueueSize];
|
||||||
|
std::atomic_uint nextAdd_{0};
|
||||||
|
std::atomic_uint nextSend_{0};
|
||||||
|
std::atomic_uint pendingSends_{0};
|
||||||
|
|
||||||
|
public:
|
||||||
|
MsgQueue() {}
|
||||||
|
|
||||||
|
ElementType* GetNextAddMessage()
|
||||||
|
{
|
||||||
|
// if we are falling behind, bail
|
||||||
|
if (pendingSends_.load() >= QueueSize) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
auto index = (nextAdd_++) % QueueSize;
|
||||||
|
return &queue_[index];
|
||||||
|
}
|
||||||
|
void CommitAdd() { ++pendingSends_; }
|
||||||
|
|
||||||
|
bool HavePendingSends() const { return pendingSends_.load() != 0; }
|
||||||
|
ElementType* GetNextSendMessage()
|
||||||
|
{
|
||||||
|
auto index = (nextSend_++) % QueueSize;
|
||||||
|
return &queue_[index];
|
||||||
|
}
|
||||||
|
void CommitSend() { --pendingSends_; }
|
||||||
|
};
|
||||||
271
libs/discordrpc/rapidjson/allocators.h
Normal file
271
libs/discordrpc/rapidjson/allocators.h
Normal file
@@ -0,0 +1,271 @@
|
|||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_ALLOCATORS_H_
|
||||||
|
#define RAPIDJSON_ALLOCATORS_H_
|
||||||
|
|
||||||
|
#include "rapidjson.h"
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Allocator
|
||||||
|
|
||||||
|
/*! \class rapidjson::Allocator
|
||||||
|
\brief Concept for allocating, resizing and freeing memory block.
|
||||||
|
|
||||||
|
Note that Malloc() and Realloc() are non-static but Free() is static.
|
||||||
|
|
||||||
|
So if an allocator need to support Free(), it needs to put its pointer in
|
||||||
|
the header of memory block.
|
||||||
|
|
||||||
|
\code
|
||||||
|
concept Allocator {
|
||||||
|
static const bool kNeedFree; //!< Whether this allocator needs to call Free().
|
||||||
|
|
||||||
|
// Allocate a memory block.
|
||||||
|
// \param size of the memory block in bytes.
|
||||||
|
// \returns pointer to the memory block.
|
||||||
|
void* Malloc(size_t size);
|
||||||
|
|
||||||
|
// Resize a memory block.
|
||||||
|
// \param originalPtr The pointer to current memory block. Null pointer is permitted.
|
||||||
|
// \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)
|
||||||
|
// \param newSize the new size in bytes.
|
||||||
|
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
|
||||||
|
|
||||||
|
// Free a memory block.
|
||||||
|
// \param pointer to the memory block. Null pointer is permitted.
|
||||||
|
static void Free(void *ptr);
|
||||||
|
};
|
||||||
|
\endcode
|
||||||
|
*/
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// CrtAllocator
|
||||||
|
|
||||||
|
//! C-runtime library allocator.
|
||||||
|
/*! This class is just wrapper for standard C library memory routines.
|
||||||
|
\note implements Allocator concept
|
||||||
|
*/
|
||||||
|
class CrtAllocator {
|
||||||
|
public:
|
||||||
|
static const bool kNeedFree = true;
|
||||||
|
void* Malloc(size_t size) {
|
||||||
|
if (size) // behavior of malloc(0) is implementation defined.
|
||||||
|
return std::malloc(size);
|
||||||
|
else
|
||||||
|
return NULL; // standardize to returning NULL.
|
||||||
|
}
|
||||||
|
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
|
||||||
|
(void)originalSize;
|
||||||
|
if (newSize == 0) {
|
||||||
|
std::free(originalPtr);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return std::realloc(originalPtr, newSize);
|
||||||
|
}
|
||||||
|
static void Free(void *ptr) { std::free(ptr); }
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// MemoryPoolAllocator
|
||||||
|
|
||||||
|
//! Default memory allocator used by the parser and DOM.
|
||||||
|
/*! This allocator allocate memory blocks from pre-allocated memory chunks.
|
||||||
|
|
||||||
|
It does not free memory blocks. And Realloc() only allocate new memory.
|
||||||
|
|
||||||
|
The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.
|
||||||
|
|
||||||
|
User may also supply a buffer as the first chunk.
|
||||||
|
|
||||||
|
If the user-buffer is full then additional chunks are allocated by BaseAllocator.
|
||||||
|
|
||||||
|
The user-buffer is not deallocated by this allocator.
|
||||||
|
|
||||||
|
\tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.
|
||||||
|
\note implements Allocator concept
|
||||||
|
*/
|
||||||
|
template <typename BaseAllocator = CrtAllocator>
|
||||||
|
class MemoryPoolAllocator {
|
||||||
|
public:
|
||||||
|
static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
|
||||||
|
|
||||||
|
//! Constructor with chunkSize.
|
||||||
|
/*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
|
||||||
|
\param baseAllocator The allocator for allocating memory chunks.
|
||||||
|
*/
|
||||||
|
MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
|
||||||
|
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Constructor with user-supplied buffer.
|
||||||
|
/*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.
|
||||||
|
|
||||||
|
The user buffer will not be deallocated when this allocator is destructed.
|
||||||
|
|
||||||
|
\param buffer User supplied buffer.
|
||||||
|
\param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).
|
||||||
|
\param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
|
||||||
|
\param baseAllocator The allocator for allocating memory chunks.
|
||||||
|
*/
|
||||||
|
MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
|
||||||
|
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
|
||||||
|
{
|
||||||
|
RAPIDJSON_ASSERT(buffer != 0);
|
||||||
|
RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
|
||||||
|
chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer);
|
||||||
|
chunkHead_->capacity = size - sizeof(ChunkHeader);
|
||||||
|
chunkHead_->size = 0;
|
||||||
|
chunkHead_->next = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Destructor.
|
||||||
|
/*! This deallocates all memory chunks, excluding the user-supplied buffer.
|
||||||
|
*/
|
||||||
|
~MemoryPoolAllocator() {
|
||||||
|
Clear();
|
||||||
|
RAPIDJSON_DELETE(ownBaseAllocator_);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Deallocates all memory chunks, excluding the user-supplied buffer.
|
||||||
|
void Clear() {
|
||||||
|
while (chunkHead_ && chunkHead_ != userBuffer_) {
|
||||||
|
ChunkHeader* next = chunkHead_->next;
|
||||||
|
baseAllocator_->Free(chunkHead_);
|
||||||
|
chunkHead_ = next;
|
||||||
|
}
|
||||||
|
if (chunkHead_ && chunkHead_ == userBuffer_)
|
||||||
|
chunkHead_->size = 0; // Clear user buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Computes the total capacity of allocated memory chunks.
|
||||||
|
/*! \return total capacity in bytes.
|
||||||
|
*/
|
||||||
|
size_t Capacity() const {
|
||||||
|
size_t capacity = 0;
|
||||||
|
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
|
||||||
|
capacity += c->capacity;
|
||||||
|
return capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Computes the memory blocks allocated.
|
||||||
|
/*! \return total used bytes.
|
||||||
|
*/
|
||||||
|
size_t Size() const {
|
||||||
|
size_t size = 0;
|
||||||
|
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
|
||||||
|
size += c->size;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Allocates a memory block. (concept Allocator)
|
||||||
|
void* Malloc(size_t size) {
|
||||||
|
if (!size)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
size = RAPIDJSON_ALIGN(size);
|
||||||
|
if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
|
||||||
|
if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
void *buffer = reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size;
|
||||||
|
chunkHead_->size += size;
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Resizes a memory block (concept Allocator)
|
||||||
|
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
|
||||||
|
if (originalPtr == 0)
|
||||||
|
return Malloc(newSize);
|
||||||
|
|
||||||
|
if (newSize == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
originalSize = RAPIDJSON_ALIGN(originalSize);
|
||||||
|
newSize = RAPIDJSON_ALIGN(newSize);
|
||||||
|
|
||||||
|
// Do not shrink if new size is smaller than original
|
||||||
|
if (originalSize >= newSize)
|
||||||
|
return originalPtr;
|
||||||
|
|
||||||
|
// Simply expand it if it is the last allocation and there is sufficient space
|
||||||
|
if (originalPtr == reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {
|
||||||
|
size_t increment = static_cast<size_t>(newSize - originalSize);
|
||||||
|
if (chunkHead_->size + increment <= chunkHead_->capacity) {
|
||||||
|
chunkHead_->size += increment;
|
||||||
|
return originalPtr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Realloc process: allocate and copy memory, do not free original buffer.
|
||||||
|
if (void* newBuffer = Malloc(newSize)) {
|
||||||
|
if (originalSize)
|
||||||
|
std::memcpy(newBuffer, originalPtr, originalSize);
|
||||||
|
return newBuffer;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Frees a memory block (concept Allocator)
|
||||||
|
static void Free(void *ptr) { (void)ptr; } // Do nothing
|
||||||
|
|
||||||
|
private:
|
||||||
|
//! Copy constructor is not permitted.
|
||||||
|
MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */;
|
||||||
|
//! Copy assignment operator is not permitted.
|
||||||
|
MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */;
|
||||||
|
|
||||||
|
//! Creates a new chunk.
|
||||||
|
/*! \param capacity Capacity of the chunk in bytes.
|
||||||
|
\return true if success.
|
||||||
|
*/
|
||||||
|
bool AddChunk(size_t capacity) {
|
||||||
|
if (!baseAllocator_)
|
||||||
|
ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator());
|
||||||
|
if (ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) {
|
||||||
|
chunk->capacity = capacity;
|
||||||
|
chunk->size = 0;
|
||||||
|
chunk->next = chunkHead_;
|
||||||
|
chunkHead_ = chunk;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity.
|
||||||
|
|
||||||
|
//! Chunk header for perpending to each chunk.
|
||||||
|
/*! Chunks are stored as a singly linked list.
|
||||||
|
*/
|
||||||
|
struct ChunkHeader {
|
||||||
|
size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
|
||||||
|
size_t size; //!< Current size of allocated memory in bytes.
|
||||||
|
ChunkHeader *next; //!< Next chunk in the linked list.
|
||||||
|
};
|
||||||
|
|
||||||
|
ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
|
||||||
|
size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated.
|
||||||
|
void *userBuffer_; //!< User supplied buffer.
|
||||||
|
BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.
|
||||||
|
BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object.
|
||||||
|
};
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_ENCODINGS_H_
|
||||||
2575
libs/discordrpc/rapidjson/document.h
Normal file
2575
libs/discordrpc/rapidjson/document.h
Normal file
File diff suppressed because it is too large
Load Diff
299
libs/discordrpc/rapidjson/encodedstream.h
Normal file
299
libs/discordrpc/rapidjson/encodedstream.h
Normal file
@@ -0,0 +1,299 @@
|
|||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_ENCODEDSTREAM_H_
|
||||||
|
#define RAPIDJSON_ENCODEDSTREAM_H_
|
||||||
|
|
||||||
|
#include "stream.h"
|
||||||
|
#include "memorystream.h"
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(effc++)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(padded)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
//! Input byte stream wrapper with a statically bound encoding.
|
||||||
|
/*!
|
||||||
|
\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
|
||||||
|
\tparam InputByteStream Type of input byte stream. For example, FileReadStream.
|
||||||
|
*/
|
||||||
|
template <typename Encoding, typename InputByteStream>
|
||||||
|
class EncodedInputStream {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
public:
|
||||||
|
typedef typename Encoding::Ch Ch;
|
||||||
|
|
||||||
|
EncodedInputStream(InputByteStream& is) : is_(is) {
|
||||||
|
current_ = Encoding::TakeBOM(is_);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ch Peek() const { return current_; }
|
||||||
|
Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; }
|
||||||
|
size_t Tell() const { return is_.Tell(); }
|
||||||
|
|
||||||
|
// Not implemented
|
||||||
|
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||||
|
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||||
|
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
EncodedInputStream(const EncodedInputStream&);
|
||||||
|
EncodedInputStream& operator=(const EncodedInputStream&);
|
||||||
|
|
||||||
|
InputByteStream& is_;
|
||||||
|
Ch current_;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Specialized for UTF8 MemoryStream.
|
||||||
|
template <>
|
||||||
|
class EncodedInputStream<UTF8<>, MemoryStream> {
|
||||||
|
public:
|
||||||
|
typedef UTF8<>::Ch Ch;
|
||||||
|
|
||||||
|
EncodedInputStream(MemoryStream& is) : is_(is) {
|
||||||
|
if (static_cast<unsigned char>(is_.Peek()) == 0xEFu) is_.Take();
|
||||||
|
if (static_cast<unsigned char>(is_.Peek()) == 0xBBu) is_.Take();
|
||||||
|
if (static_cast<unsigned char>(is_.Peek()) == 0xBFu) is_.Take();
|
||||||
|
}
|
||||||
|
Ch Peek() const { return is_.Peek(); }
|
||||||
|
Ch Take() { return is_.Take(); }
|
||||||
|
size_t Tell() const { return is_.Tell(); }
|
||||||
|
|
||||||
|
// Not implemented
|
||||||
|
void Put(Ch) {}
|
||||||
|
void Flush() {}
|
||||||
|
Ch* PutBegin() { return 0; }
|
||||||
|
size_t PutEnd(Ch*) { return 0; }
|
||||||
|
|
||||||
|
MemoryStream& is_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
EncodedInputStream(const EncodedInputStream&);
|
||||||
|
EncodedInputStream& operator=(const EncodedInputStream&);
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Output byte stream wrapper with statically bound encoding.
|
||||||
|
/*!
|
||||||
|
\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
|
||||||
|
\tparam OutputByteStream Type of input byte stream. For example, FileWriteStream.
|
||||||
|
*/
|
||||||
|
template <typename Encoding, typename OutputByteStream>
|
||||||
|
class EncodedOutputStream {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
public:
|
||||||
|
typedef typename Encoding::Ch Ch;
|
||||||
|
|
||||||
|
EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) {
|
||||||
|
if (putBOM)
|
||||||
|
Encoding::PutBOM(os_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Put(Ch c) { Encoding::Put(os_, c); }
|
||||||
|
void Flush() { os_.Flush(); }
|
||||||
|
|
||||||
|
// Not implemented
|
||||||
|
Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
|
||||||
|
Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
|
||||||
|
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
EncodedOutputStream(const EncodedOutputStream&);
|
||||||
|
EncodedOutputStream& operator=(const EncodedOutputStream&);
|
||||||
|
|
||||||
|
OutputByteStream& os_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
|
||||||
|
|
||||||
|
//! Input stream wrapper with dynamically bound encoding and automatic encoding detection.
|
||||||
|
/*!
|
||||||
|
\tparam CharType Type of character for reading.
|
||||||
|
\tparam InputByteStream type of input byte stream to be wrapped.
|
||||||
|
*/
|
||||||
|
template <typename CharType, typename InputByteStream>
|
||||||
|
class AutoUTFInputStream {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
public:
|
||||||
|
typedef CharType Ch;
|
||||||
|
|
||||||
|
//! Constructor.
|
||||||
|
/*!
|
||||||
|
\param is input stream to be wrapped.
|
||||||
|
\param type UTF encoding type if it is not detected from the stream.
|
||||||
|
*/
|
||||||
|
AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) {
|
||||||
|
RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
|
||||||
|
DetectType();
|
||||||
|
static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) };
|
||||||
|
takeFunc_ = f[type_];
|
||||||
|
current_ = takeFunc_(*is_);
|
||||||
|
}
|
||||||
|
|
||||||
|
UTFType GetType() const { return type_; }
|
||||||
|
bool HasBOM() const { return hasBOM_; }
|
||||||
|
|
||||||
|
Ch Peek() const { return current_; }
|
||||||
|
Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; }
|
||||||
|
size_t Tell() const { return is_->Tell(); }
|
||||||
|
|
||||||
|
// Not implemented
|
||||||
|
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||||
|
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||||
|
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
AutoUTFInputStream(const AutoUTFInputStream&);
|
||||||
|
AutoUTFInputStream& operator=(const AutoUTFInputStream&);
|
||||||
|
|
||||||
|
// Detect encoding type with BOM or RFC 4627
|
||||||
|
void DetectType() {
|
||||||
|
// BOM (Byte Order Mark):
|
||||||
|
// 00 00 FE FF UTF-32BE
|
||||||
|
// FF FE 00 00 UTF-32LE
|
||||||
|
// FE FF UTF-16BE
|
||||||
|
// FF FE UTF-16LE
|
||||||
|
// EF BB BF UTF-8
|
||||||
|
|
||||||
|
const unsigned char* c = reinterpret_cast<const unsigned char *>(is_->Peek4());
|
||||||
|
if (!c)
|
||||||
|
return;
|
||||||
|
|
||||||
|
unsigned bom = static_cast<unsigned>(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24));
|
||||||
|
hasBOM_ = false;
|
||||||
|
if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
|
||||||
|
else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
|
||||||
|
else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); }
|
||||||
|
else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); }
|
||||||
|
else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); }
|
||||||
|
|
||||||
|
// RFC 4627: Section 3
|
||||||
|
// "Since the first two characters of a JSON text will always be ASCII
|
||||||
|
// characters [RFC0020], it is possible to determine whether an octet
|
||||||
|
// stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
|
||||||
|
// at the pattern of nulls in the first four octets."
|
||||||
|
// 00 00 00 xx UTF-32BE
|
||||||
|
// 00 xx 00 xx UTF-16BE
|
||||||
|
// xx 00 00 00 UTF-32LE
|
||||||
|
// xx 00 xx 00 UTF-16LE
|
||||||
|
// xx xx xx xx UTF-8
|
||||||
|
|
||||||
|
if (!hasBOM_) {
|
||||||
|
unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);
|
||||||
|
switch (pattern) {
|
||||||
|
case 0x08: type_ = kUTF32BE; break;
|
||||||
|
case 0x0A: type_ = kUTF16BE; break;
|
||||||
|
case 0x01: type_ = kUTF32LE; break;
|
||||||
|
case 0x05: type_ = kUTF16LE; break;
|
||||||
|
case 0x0F: type_ = kUTF8; break;
|
||||||
|
default: break; // Use type defined by user.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
|
||||||
|
if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
|
||||||
|
if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef Ch (*TakeFunc)(InputByteStream& is);
|
||||||
|
InputByteStream* is_;
|
||||||
|
UTFType type_;
|
||||||
|
Ch current_;
|
||||||
|
TakeFunc takeFunc_;
|
||||||
|
bool hasBOM_;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Output stream wrapper with dynamically bound encoding and automatic encoding detection.
|
||||||
|
/*!
|
||||||
|
\tparam CharType Type of character for writing.
|
||||||
|
\tparam OutputByteStream type of output byte stream to be wrapped.
|
||||||
|
*/
|
||||||
|
template <typename CharType, typename OutputByteStream>
|
||||||
|
class AutoUTFOutputStream {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
public:
|
||||||
|
typedef CharType Ch;
|
||||||
|
|
||||||
|
//! Constructor.
|
||||||
|
/*!
|
||||||
|
\param os output stream to be wrapped.
|
||||||
|
\param type UTF encoding type.
|
||||||
|
\param putBOM Whether to write BOM at the beginning of the stream.
|
||||||
|
*/
|
||||||
|
AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) {
|
||||||
|
RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
|
||||||
|
|
||||||
|
// Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
|
||||||
|
if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
|
||||||
|
if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
|
||||||
|
|
||||||
|
static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) };
|
||||||
|
putFunc_ = f[type_];
|
||||||
|
|
||||||
|
if (putBOM)
|
||||||
|
PutBOM();
|
||||||
|
}
|
||||||
|
|
||||||
|
UTFType GetType() const { return type_; }
|
||||||
|
|
||||||
|
void Put(Ch c) { putFunc_(*os_, c); }
|
||||||
|
void Flush() { os_->Flush(); }
|
||||||
|
|
||||||
|
// Not implemented
|
||||||
|
Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
|
||||||
|
Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
|
||||||
|
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
AutoUTFOutputStream(const AutoUTFOutputStream&);
|
||||||
|
AutoUTFOutputStream& operator=(const AutoUTFOutputStream&);
|
||||||
|
|
||||||
|
void PutBOM() {
|
||||||
|
typedef void (*PutBOMFunc)(OutputByteStream&);
|
||||||
|
static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) };
|
||||||
|
f[type_](*os_);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef void (*PutFunc)(OutputByteStream&, Ch);
|
||||||
|
|
||||||
|
OutputByteStream* os_;
|
||||||
|
UTFType type_;
|
||||||
|
PutFunc putFunc_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#undef RAPIDJSON_ENCODINGS_FUNC
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_FILESTREAM_H_
|
||||||
716
libs/discordrpc/rapidjson/encodings.h
Normal file
716
libs/discordrpc/rapidjson/encodings.h
Normal file
@@ -0,0 +1,716 @@
|
|||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_ENCODINGS_H_
|
||||||
|
#define RAPIDJSON_ENCODINGS_H_
|
||||||
|
|
||||||
|
#include "rapidjson.h"
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data
|
||||||
|
RAPIDJSON_DIAG_OFF(4702) // unreachable code
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(effc++)
|
||||||
|
RAPIDJSON_DIAG_OFF(overflow)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Encoding
|
||||||
|
|
||||||
|
/*! \class rapidjson::Encoding
|
||||||
|
\brief Concept for encoding of Unicode characters.
|
||||||
|
|
||||||
|
\code
|
||||||
|
concept Encoding {
|
||||||
|
typename Ch; //! Type of character. A "character" is actually a code unit in unicode's definition.
|
||||||
|
|
||||||
|
enum { supportUnicode = 1 }; // or 0 if not supporting unicode
|
||||||
|
|
||||||
|
//! \brief Encode a Unicode codepoint to an output stream.
|
||||||
|
//! \param os Output stream.
|
||||||
|
//! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively.
|
||||||
|
template<typename OutputStream>
|
||||||
|
static void Encode(OutputStream& os, unsigned codepoint);
|
||||||
|
|
||||||
|
//! \brief Decode a Unicode codepoint from an input stream.
|
||||||
|
//! \param is Input stream.
|
||||||
|
//! \param codepoint Output of the unicode codepoint.
|
||||||
|
//! \return true if a valid codepoint can be decoded from the stream.
|
||||||
|
template <typename InputStream>
|
||||||
|
static bool Decode(InputStream& is, unsigned* codepoint);
|
||||||
|
|
||||||
|
//! \brief Validate one Unicode codepoint from an encoded stream.
|
||||||
|
//! \param is Input stream to obtain codepoint.
|
||||||
|
//! \param os Output for copying one codepoint.
|
||||||
|
//! \return true if it is valid.
|
||||||
|
//! \note This function just validating and copying the codepoint without actually decode it.
|
||||||
|
template <typename InputStream, typename OutputStream>
|
||||||
|
static bool Validate(InputStream& is, OutputStream& os);
|
||||||
|
|
||||||
|
// The following functions are deal with byte streams.
|
||||||
|
|
||||||
|
//! Take a character from input byte stream, skip BOM if exist.
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static CharType TakeBOM(InputByteStream& is);
|
||||||
|
|
||||||
|
//! Take a character from input byte stream.
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static Ch Take(InputByteStream& is);
|
||||||
|
|
||||||
|
//! Put BOM to output byte stream.
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void PutBOM(OutputByteStream& os);
|
||||||
|
|
||||||
|
//! Put a character to output byte stream.
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void Put(OutputByteStream& os, Ch c);
|
||||||
|
};
|
||||||
|
\endcode
|
||||||
|
*/
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// UTF8
|
||||||
|
|
||||||
|
//! UTF-8 encoding.
|
||||||
|
/*! http://en.wikipedia.org/wiki/UTF-8
|
||||||
|
http://tools.ietf.org/html/rfc3629
|
||||||
|
\tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char.
|
||||||
|
\note implements Encoding concept
|
||||||
|
*/
|
||||||
|
template<typename CharType = char>
|
||||||
|
struct UTF8 {
|
||||||
|
typedef CharType Ch;
|
||||||
|
|
||||||
|
enum { supportUnicode = 1 };
|
||||||
|
|
||||||
|
template<typename OutputStream>
|
||||||
|
static void Encode(OutputStream& os, unsigned codepoint) {
|
||||||
|
if (codepoint <= 0x7F)
|
||||||
|
os.Put(static_cast<Ch>(codepoint & 0xFF));
|
||||||
|
else if (codepoint <= 0x7FF) {
|
||||||
|
os.Put(static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
|
||||||
|
os.Put(static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
|
||||||
|
}
|
||||||
|
else if (codepoint <= 0xFFFF) {
|
||||||
|
os.Put(static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
|
||||||
|
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
|
||||||
|
os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||||
|
os.Put(static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
|
||||||
|
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
|
||||||
|
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
|
||||||
|
os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename OutputStream>
|
||||||
|
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
|
||||||
|
if (codepoint <= 0x7F)
|
||||||
|
PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));
|
||||||
|
else if (codepoint <= 0x7FF) {
|
||||||
|
PutUnsafe(os, static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
|
||||||
|
PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
|
||||||
|
}
|
||||||
|
else if (codepoint <= 0xFFFF) {
|
||||||
|
PutUnsafe(os, static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
|
||||||
|
PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
|
||||||
|
PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||||
|
PutUnsafe(os, static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
|
||||||
|
PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
|
||||||
|
PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
|
||||||
|
PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream>
|
||||||
|
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||||
|
#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast<unsigned char>(c) & 0x3Fu)
|
||||||
|
#define TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
|
||||||
|
#define TAIL() COPY(); TRANS(0x70)
|
||||||
|
typename InputStream::Ch c = is.Take();
|
||||||
|
if (!(c & 0x80)) {
|
||||||
|
*codepoint = static_cast<unsigned char>(c);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char type = GetRange(static_cast<unsigned char>(c));
|
||||||
|
if (type >= 32) {
|
||||||
|
*codepoint = 0;
|
||||||
|
} else {
|
||||||
|
*codepoint = (0xFF >> type) & static_cast<unsigned char>(c);
|
||||||
|
}
|
||||||
|
bool result = true;
|
||||||
|
switch (type) {
|
||||||
|
case 2: TAIL(); return result;
|
||||||
|
case 3: TAIL(); TAIL(); return result;
|
||||||
|
case 4: COPY(); TRANS(0x50); TAIL(); return result;
|
||||||
|
case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
|
||||||
|
case 6: TAIL(); TAIL(); TAIL(); return result;
|
||||||
|
case 10: COPY(); TRANS(0x20); TAIL(); return result;
|
||||||
|
case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
#undef COPY
|
||||||
|
#undef TRANS
|
||||||
|
#undef TAIL
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream, typename OutputStream>
|
||||||
|
static bool Validate(InputStream& is, OutputStream& os) {
|
||||||
|
#define COPY() os.Put(c = is.Take())
|
||||||
|
#define TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
|
||||||
|
#define TAIL() COPY(); TRANS(0x70)
|
||||||
|
Ch c;
|
||||||
|
COPY();
|
||||||
|
if (!(c & 0x80))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
bool result = true;
|
||||||
|
switch (GetRange(static_cast<unsigned char>(c))) {
|
||||||
|
case 2: TAIL(); return result;
|
||||||
|
case 3: TAIL(); TAIL(); return result;
|
||||||
|
case 4: COPY(); TRANS(0x50); TAIL(); return result;
|
||||||
|
case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
|
||||||
|
case 6: TAIL(); TAIL(); TAIL(); return result;
|
||||||
|
case 10: COPY(); TRANS(0x20); TAIL(); return result;
|
||||||
|
case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
#undef COPY
|
||||||
|
#undef TRANS
|
||||||
|
#undef TAIL
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned char GetRange(unsigned char c) {
|
||||||
|
// Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
|
||||||
|
// With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types.
|
||||||
|
static const unsigned char type[] = {
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
|
||||||
|
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
|
||||||
|
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
|
||||||
|
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
|
||||||
|
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
||||||
|
10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
|
||||||
|
};
|
||||||
|
return type[c];
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static CharType TakeBOM(InputByteStream& is) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
typename InputByteStream::Ch c = Take(is);
|
||||||
|
if (static_cast<unsigned char>(c) != 0xEFu) return c;
|
||||||
|
c = is.Take();
|
||||||
|
if (static_cast<unsigned char>(c) != 0xBBu) return c;
|
||||||
|
c = is.Take();
|
||||||
|
if (static_cast<unsigned char>(c) != 0xBFu) return c;
|
||||||
|
c = is.Take();
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static Ch Take(InputByteStream& is) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
return static_cast<Ch>(is.Take());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void PutBOM(OutputByteStream& os) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(0xEFu));
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(0xBBu));
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(0xBFu));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void Put(OutputByteStream& os, Ch c) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(c));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// UTF16
|
||||||
|
|
||||||
|
//! UTF-16 encoding.
|
||||||
|
/*! http://en.wikipedia.org/wiki/UTF-16
|
||||||
|
http://tools.ietf.org/html/rfc2781
|
||||||
|
\tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead.
|
||||||
|
\note implements Encoding concept
|
||||||
|
|
||||||
|
\note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
|
||||||
|
For streaming, use UTF16LE and UTF16BE, which handle endianness.
|
||||||
|
*/
|
||||||
|
template<typename CharType = wchar_t>
|
||||||
|
struct UTF16 {
|
||||||
|
typedef CharType Ch;
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2);
|
||||||
|
|
||||||
|
enum { supportUnicode = 1 };
|
||||||
|
|
||||||
|
template<typename OutputStream>
|
||||||
|
static void Encode(OutputStream& os, unsigned codepoint) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
|
||||||
|
if (codepoint <= 0xFFFF) {
|
||||||
|
RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
|
||||||
|
os.Put(static_cast<typename OutputStream::Ch>(codepoint));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||||
|
unsigned v = codepoint - 0x10000;
|
||||||
|
os.Put(static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
|
||||||
|
os.Put((v & 0x3FF) | 0xDC00);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename OutputStream>
|
||||||
|
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
|
||||||
|
if (codepoint <= 0xFFFF) {
|
||||||
|
RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
|
||||||
|
PutUnsafe(os, static_cast<typename OutputStream::Ch>(codepoint));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||||
|
unsigned v = codepoint - 0x10000;
|
||||||
|
PutUnsafe(os, static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
|
||||||
|
PutUnsafe(os, (v & 0x3FF) | 0xDC00);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream>
|
||||||
|
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
|
||||||
|
typename InputStream::Ch c = is.Take();
|
||||||
|
if (c < 0xD800 || c > 0xDFFF) {
|
||||||
|
*codepoint = static_cast<unsigned>(c);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (c <= 0xDBFF) {
|
||||||
|
*codepoint = (static_cast<unsigned>(c) & 0x3FF) << 10;
|
||||||
|
c = is.Take();
|
||||||
|
*codepoint |= (static_cast<unsigned>(c) & 0x3FF);
|
||||||
|
*codepoint += 0x10000;
|
||||||
|
return c >= 0xDC00 && c <= 0xDFFF;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream, typename OutputStream>
|
||||||
|
static bool Validate(InputStream& is, OutputStream& os) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
|
||||||
|
typename InputStream::Ch c;
|
||||||
|
os.Put(static_cast<typename OutputStream::Ch>(c = is.Take()));
|
||||||
|
if (c < 0xD800 || c > 0xDFFF)
|
||||||
|
return true;
|
||||||
|
else if (c <= 0xDBFF) {
|
||||||
|
os.Put(c = is.Take());
|
||||||
|
return c >= 0xDC00 && c <= 0xDFFF;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//! UTF-16 little endian encoding.
|
||||||
|
template<typename CharType = wchar_t>
|
||||||
|
struct UTF16LE : UTF16<CharType> {
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static CharType TakeBOM(InputByteStream& is) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
CharType c = Take(is);
|
||||||
|
return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static CharType Take(InputByteStream& is) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
unsigned c = static_cast<uint8_t>(is.Take());
|
||||||
|
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
|
||||||
|
return static_cast<CharType>(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void PutBOM(OutputByteStream& os) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void Put(OutputByteStream& os, CharType c) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//! UTF-16 big endian encoding.
|
||||||
|
template<typename CharType = wchar_t>
|
||||||
|
struct UTF16BE : UTF16<CharType> {
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static CharType TakeBOM(InputByteStream& is) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
CharType c = Take(is);
|
||||||
|
return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static CharType Take(InputByteStream& is) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
|
||||||
|
c |= static_cast<uint8_t>(is.Take());
|
||||||
|
return static_cast<CharType>(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void PutBOM(OutputByteStream& os) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void Put(OutputByteStream& os, CharType c) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// UTF32
|
||||||
|
|
||||||
|
//! UTF-32 encoding.
|
||||||
|
/*! http://en.wikipedia.org/wiki/UTF-32
|
||||||
|
\tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead.
|
||||||
|
\note implements Encoding concept
|
||||||
|
|
||||||
|
\note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
|
||||||
|
For streaming, use UTF32LE and UTF32BE, which handle endianness.
|
||||||
|
*/
|
||||||
|
template<typename CharType = unsigned>
|
||||||
|
struct UTF32 {
|
||||||
|
typedef CharType Ch;
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4);
|
||||||
|
|
||||||
|
enum { supportUnicode = 1 };
|
||||||
|
|
||||||
|
template<typename OutputStream>
|
||||||
|
static void Encode(OutputStream& os, unsigned codepoint) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
|
||||||
|
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||||
|
os.Put(codepoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename OutputStream>
|
||||||
|
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
|
||||||
|
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||||
|
PutUnsafe(os, codepoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream>
|
||||||
|
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
|
||||||
|
Ch c = is.Take();
|
||||||
|
*codepoint = c;
|
||||||
|
return c <= 0x10FFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream, typename OutputStream>
|
||||||
|
static bool Validate(InputStream& is, OutputStream& os) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
|
||||||
|
Ch c;
|
||||||
|
os.Put(c = is.Take());
|
||||||
|
return c <= 0x10FFFF;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//! UTF-32 little endian enocoding.
|
||||||
|
template<typename CharType = unsigned>
|
||||||
|
struct UTF32LE : UTF32<CharType> {
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static CharType TakeBOM(InputByteStream& is) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
CharType c = Take(is);
|
||||||
|
return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static CharType Take(InputByteStream& is) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
unsigned c = static_cast<uint8_t>(is.Take());
|
||||||
|
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
|
||||||
|
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;
|
||||||
|
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;
|
||||||
|
return static_cast<CharType>(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void PutBOM(OutputByteStream& os) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void Put(OutputByteStream& os, CharType c) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//! UTF-32 big endian encoding.
|
||||||
|
template<typename CharType = unsigned>
|
||||||
|
struct UTF32BE : UTF32<CharType> {
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static CharType TakeBOM(InputByteStream& is) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
CharType c = Take(is);
|
||||||
|
return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static CharType Take(InputByteStream& is) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;
|
||||||
|
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;
|
||||||
|
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
|
||||||
|
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take()));
|
||||||
|
return static_cast<CharType>(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void PutBOM(OutputByteStream& os) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void Put(OutputByteStream& os, CharType c) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// ASCII
|
||||||
|
|
||||||
|
//! ASCII encoding.
|
||||||
|
/*! http://en.wikipedia.org/wiki/ASCII
|
||||||
|
\tparam CharType Code unit for storing 7-bit ASCII data. Default is char.
|
||||||
|
\note implements Encoding concept
|
||||||
|
*/
|
||||||
|
template<typename CharType = char>
|
||||||
|
struct ASCII {
|
||||||
|
typedef CharType Ch;
|
||||||
|
|
||||||
|
enum { supportUnicode = 0 };
|
||||||
|
|
||||||
|
template<typename OutputStream>
|
||||||
|
static void Encode(OutputStream& os, unsigned codepoint) {
|
||||||
|
RAPIDJSON_ASSERT(codepoint <= 0x7F);
|
||||||
|
os.Put(static_cast<Ch>(codepoint & 0xFF));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename OutputStream>
|
||||||
|
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
|
||||||
|
RAPIDJSON_ASSERT(codepoint <= 0x7F);
|
||||||
|
PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream>
|
||||||
|
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||||
|
uint8_t c = static_cast<uint8_t>(is.Take());
|
||||||
|
*codepoint = c;
|
||||||
|
return c <= 0X7F;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream, typename OutputStream>
|
||||||
|
static bool Validate(InputStream& is, OutputStream& os) {
|
||||||
|
uint8_t c = static_cast<uint8_t>(is.Take());
|
||||||
|
os.Put(static_cast<typename OutputStream::Ch>(c));
|
||||||
|
return c <= 0x7F;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static CharType TakeBOM(InputByteStream& is) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
uint8_t c = static_cast<uint8_t>(Take(is));
|
||||||
|
return static_cast<Ch>(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static Ch Take(InputByteStream& is) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
return static_cast<Ch>(is.Take());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void PutBOM(OutputByteStream& os) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
(void)os;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void Put(OutputByteStream& os, Ch c) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(c));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// AutoUTF
|
||||||
|
|
||||||
|
//! Runtime-specified UTF encoding type of a stream.
|
||||||
|
enum UTFType {
|
||||||
|
kUTF8 = 0, //!< UTF-8.
|
||||||
|
kUTF16LE = 1, //!< UTF-16 little endian.
|
||||||
|
kUTF16BE = 2, //!< UTF-16 big endian.
|
||||||
|
kUTF32LE = 3, //!< UTF-32 little endian.
|
||||||
|
kUTF32BE = 4 //!< UTF-32 big endian.
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Dynamically select encoding according to stream's runtime-specified UTF encoding type.
|
||||||
|
/*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType().
|
||||||
|
*/
|
||||||
|
template<typename CharType>
|
||||||
|
struct AutoUTF {
|
||||||
|
typedef CharType Ch;
|
||||||
|
|
||||||
|
enum { supportUnicode = 1 };
|
||||||
|
|
||||||
|
#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
|
||||||
|
|
||||||
|
template<typename OutputStream>
|
||||||
|
RAPIDJSON_FORCEINLINE static void Encode(OutputStream& os, unsigned codepoint) {
|
||||||
|
typedef void (*EncodeFunc)(OutputStream&, unsigned);
|
||||||
|
static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) };
|
||||||
|
(*f[os.GetType()])(os, codepoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename OutputStream>
|
||||||
|
RAPIDJSON_FORCEINLINE static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
|
||||||
|
typedef void (*EncodeFunc)(OutputStream&, unsigned);
|
||||||
|
static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) };
|
||||||
|
(*f[os.GetType()])(os, codepoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream>
|
||||||
|
RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||||
|
typedef bool (*DecodeFunc)(InputStream&, unsigned*);
|
||||||
|
static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) };
|
||||||
|
return (*f[is.GetType()])(is, codepoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream, typename OutputStream>
|
||||||
|
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
|
||||||
|
typedef bool (*ValidateFunc)(InputStream&, OutputStream&);
|
||||||
|
static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) };
|
||||||
|
return (*f[is.GetType()])(is, os);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef RAPIDJSON_ENCODINGS_FUNC
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Transcoder
|
||||||
|
|
||||||
|
//! Encoding conversion.
|
||||||
|
template<typename SourceEncoding, typename TargetEncoding>
|
||||||
|
struct Transcoder {
|
||||||
|
//! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream.
|
||||||
|
template<typename InputStream, typename OutputStream>
|
||||||
|
RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
|
||||||
|
unsigned codepoint;
|
||||||
|
if (!SourceEncoding::Decode(is, &codepoint))
|
||||||
|
return false;
|
||||||
|
TargetEncoding::Encode(os, codepoint);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename InputStream, typename OutputStream>
|
||||||
|
RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
|
||||||
|
unsigned codepoint;
|
||||||
|
if (!SourceEncoding::Decode(is, &codepoint))
|
||||||
|
return false;
|
||||||
|
TargetEncoding::EncodeUnsafe(os, codepoint);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Validate one Unicode codepoint from an encoded stream.
|
||||||
|
template<typename InputStream, typename OutputStream>
|
||||||
|
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
|
||||||
|
return Transcode(is, os); // Since source/target encoding is different, must transcode.
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Forward declaration.
|
||||||
|
template<typename Stream>
|
||||||
|
inline void PutUnsafe(Stream& stream, typename Stream::Ch c);
|
||||||
|
|
||||||
|
//! Specialization of Transcoder with same source and target encoding.
|
||||||
|
template<typename Encoding>
|
||||||
|
struct Transcoder<Encoding, Encoding> {
|
||||||
|
template<typename InputStream, typename OutputStream>
|
||||||
|
RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
|
||||||
|
os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename InputStream, typename OutputStream>
|
||||||
|
RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
|
||||||
|
PutUnsafe(os, is.Take()); // Just copy one code unit. This semantic is different from primary template class.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename InputStream, typename OutputStream>
|
||||||
|
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
|
||||||
|
return Encoding::Validate(is, os); // source/target encoding are the same
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#if defined(__GNUC__) || defined(_MSC_VER)
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_ENCODINGS_H_
|
||||||
74
libs/discordrpc/rapidjson/error/en.h
Normal file
74
libs/discordrpc/rapidjson/error/en.h
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_ERROR_EN_H_
|
||||||
|
#define RAPIDJSON_ERROR_EN_H_
|
||||||
|
|
||||||
|
#include "error.h"
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(switch-enum)
|
||||||
|
RAPIDJSON_DIAG_OFF(covered-switch-default)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
//! Maps error code of parsing into error message.
|
||||||
|
/*!
|
||||||
|
\ingroup RAPIDJSON_ERRORS
|
||||||
|
\param parseErrorCode Error code obtained in parsing.
|
||||||
|
\return the error message.
|
||||||
|
\note User can make a copy of this function for localization.
|
||||||
|
Using switch-case is safer for future modification of error codes.
|
||||||
|
*/
|
||||||
|
inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) {
|
||||||
|
switch (parseErrorCode) {
|
||||||
|
case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error.");
|
||||||
|
|
||||||
|
case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty.");
|
||||||
|
case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values.");
|
||||||
|
|
||||||
|
case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value.");
|
||||||
|
|
||||||
|
case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member.");
|
||||||
|
case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member.");
|
||||||
|
case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member.");
|
||||||
|
|
||||||
|
case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element.");
|
||||||
|
|
||||||
|
case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string.");
|
||||||
|
case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid.");
|
||||||
|
case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string.");
|
||||||
|
case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string.");
|
||||||
|
case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string.");
|
||||||
|
|
||||||
|
case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double.");
|
||||||
|
case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number.");
|
||||||
|
case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number.");
|
||||||
|
|
||||||
|
case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error.");
|
||||||
|
case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error.");
|
||||||
|
|
||||||
|
default: return RAPIDJSON_ERROR_STRING("Unknown error.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_ERROR_EN_H_
|
||||||
155
libs/discordrpc/rapidjson/error/error.h
Normal file
155
libs/discordrpc/rapidjson/error/error.h
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_ERROR_ERROR_H_
|
||||||
|
#define RAPIDJSON_ERROR_ERROR_H_
|
||||||
|
|
||||||
|
#include "../rapidjson.h"
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(padded)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! \file error.h */
|
||||||
|
|
||||||
|
/*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAPIDJSON_ERROR_CHARTYPE
|
||||||
|
|
||||||
|
//! Character type of error messages.
|
||||||
|
/*! \ingroup RAPIDJSON_ERRORS
|
||||||
|
The default character type is \c char.
|
||||||
|
On Windows, user can define this macro as \c TCHAR for supporting both
|
||||||
|
unicode/non-unicode settings.
|
||||||
|
*/
|
||||||
|
#ifndef RAPIDJSON_ERROR_CHARTYPE
|
||||||
|
#define RAPIDJSON_ERROR_CHARTYPE char
|
||||||
|
#endif
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAPIDJSON_ERROR_STRING
|
||||||
|
|
||||||
|
//! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[].
|
||||||
|
/*! \ingroup RAPIDJSON_ERRORS
|
||||||
|
By default this conversion macro does nothing.
|
||||||
|
On Windows, user can define this macro as \c _T(x) for supporting both
|
||||||
|
unicode/non-unicode settings.
|
||||||
|
*/
|
||||||
|
#ifndef RAPIDJSON_ERROR_STRING
|
||||||
|
#define RAPIDJSON_ERROR_STRING(x) x
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// ParseErrorCode
|
||||||
|
|
||||||
|
//! Error code of parsing.
|
||||||
|
/*! \ingroup RAPIDJSON_ERRORS
|
||||||
|
\see GenericReader::Parse, GenericReader::GetParseErrorCode
|
||||||
|
*/
|
||||||
|
enum ParseErrorCode {
|
||||||
|
kParseErrorNone = 0, //!< No error.
|
||||||
|
|
||||||
|
kParseErrorDocumentEmpty, //!< The document is empty.
|
||||||
|
kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values.
|
||||||
|
|
||||||
|
kParseErrorValueInvalid, //!< Invalid value.
|
||||||
|
|
||||||
|
kParseErrorObjectMissName, //!< Missing a name for object member.
|
||||||
|
kParseErrorObjectMissColon, //!< Missing a colon after a name of object member.
|
||||||
|
kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member.
|
||||||
|
|
||||||
|
kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element.
|
||||||
|
|
||||||
|
kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string.
|
||||||
|
kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid.
|
||||||
|
kParseErrorStringEscapeInvalid, //!< Invalid escape character in string.
|
||||||
|
kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string.
|
||||||
|
kParseErrorStringInvalidEncoding, //!< Invalid encoding in string.
|
||||||
|
|
||||||
|
kParseErrorNumberTooBig, //!< Number too big to be stored in double.
|
||||||
|
kParseErrorNumberMissFraction, //!< Miss fraction part in number.
|
||||||
|
kParseErrorNumberMissExponent, //!< Miss exponent in number.
|
||||||
|
|
||||||
|
kParseErrorTermination, //!< Parsing was terminated.
|
||||||
|
kParseErrorUnspecificSyntaxError //!< Unspecific syntax error.
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Result of parsing (wraps ParseErrorCode)
|
||||||
|
/*!
|
||||||
|
\ingroup RAPIDJSON_ERRORS
|
||||||
|
\code
|
||||||
|
Document doc;
|
||||||
|
ParseResult ok = doc.Parse("[42]");
|
||||||
|
if (!ok) {
|
||||||
|
fprintf(stderr, "JSON parse error: %s (%u)",
|
||||||
|
GetParseError_En(ok.Code()), ok.Offset());
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
\see GenericReader::Parse, GenericDocument::Parse
|
||||||
|
*/
|
||||||
|
struct ParseResult {
|
||||||
|
public:
|
||||||
|
//! Default constructor, no error.
|
||||||
|
ParseResult() : code_(kParseErrorNone), offset_(0) {}
|
||||||
|
//! Constructor to set an error.
|
||||||
|
ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {}
|
||||||
|
|
||||||
|
//! Get the error code.
|
||||||
|
ParseErrorCode Code() const { return code_; }
|
||||||
|
//! Get the error offset, if \ref IsError(), 0 otherwise.
|
||||||
|
size_t Offset() const { return offset_; }
|
||||||
|
|
||||||
|
//! Conversion to \c bool, returns \c true, iff !\ref IsError().
|
||||||
|
operator bool() const { return !IsError(); }
|
||||||
|
//! Whether the result is an error.
|
||||||
|
bool IsError() const { return code_ != kParseErrorNone; }
|
||||||
|
|
||||||
|
bool operator==(const ParseResult& that) const { return code_ == that.code_; }
|
||||||
|
bool operator==(ParseErrorCode code) const { return code_ == code; }
|
||||||
|
friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; }
|
||||||
|
|
||||||
|
//! Reset error code.
|
||||||
|
void Clear() { Set(kParseErrorNone); }
|
||||||
|
//! Update error code and offset.
|
||||||
|
void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
ParseErrorCode code_;
|
||||||
|
size_t offset_;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Function pointer type of GetParseError().
|
||||||
|
/*! \ingroup RAPIDJSON_ERRORS
|
||||||
|
|
||||||
|
This is the prototype for \c GetParseError_X(), where \c X is a locale.
|
||||||
|
User can dynamically change locale in runtime, e.g.:
|
||||||
|
\code
|
||||||
|
GetParseErrorFunc GetParseError = GetParseError_En; // or whatever
|
||||||
|
const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode());
|
||||||
|
\endcode
|
||||||
|
*/
|
||||||
|
typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_ERROR_ERROR_H_
|
||||||
99
libs/discordrpc/rapidjson/filereadstream.h
Normal file
99
libs/discordrpc/rapidjson/filereadstream.h
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_FILEREADSTREAM_H_
|
||||||
|
#define RAPIDJSON_FILEREADSTREAM_H_
|
||||||
|
|
||||||
|
#include "stream.h"
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(padded)
|
||||||
|
RAPIDJSON_DIAG_OFF(unreachable-code)
|
||||||
|
RAPIDJSON_DIAG_OFF(missing-noreturn)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
//! File byte stream for input using fread().
|
||||||
|
/*!
|
||||||
|
\note implements Stream concept
|
||||||
|
*/
|
||||||
|
class FileReadStream {
|
||||||
|
public:
|
||||||
|
typedef char Ch; //!< Character type (byte).
|
||||||
|
|
||||||
|
//! Constructor.
|
||||||
|
/*!
|
||||||
|
\param fp File pointer opened for read.
|
||||||
|
\param buffer user-supplied buffer.
|
||||||
|
\param bufferSize size of buffer in bytes. Must >=4 bytes.
|
||||||
|
*/
|
||||||
|
FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) {
|
||||||
|
RAPIDJSON_ASSERT(fp_ != 0);
|
||||||
|
RAPIDJSON_ASSERT(bufferSize >= 4);
|
||||||
|
Read();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ch Peek() const { return *current_; }
|
||||||
|
Ch Take() { Ch c = *current_; Read(); return c; }
|
||||||
|
size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }
|
||||||
|
|
||||||
|
// Not implemented
|
||||||
|
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||||
|
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||||
|
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
|
||||||
|
// For encoding detection only.
|
||||||
|
const Ch* Peek4() const {
|
||||||
|
return (current_ + 4 <= bufferLast_) ? current_ : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Read() {
|
||||||
|
if (current_ < bufferLast_)
|
||||||
|
++current_;
|
||||||
|
else if (!eof_) {
|
||||||
|
count_ += readCount_;
|
||||||
|
readCount_ = fread(buffer_, 1, bufferSize_, fp_);
|
||||||
|
bufferLast_ = buffer_ + readCount_ - 1;
|
||||||
|
current_ = buffer_;
|
||||||
|
|
||||||
|
if (readCount_ < bufferSize_) {
|
||||||
|
buffer_[readCount_] = '\0';
|
||||||
|
++bufferLast_;
|
||||||
|
eof_ = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::FILE* fp_;
|
||||||
|
Ch *buffer_;
|
||||||
|
size_t bufferSize_;
|
||||||
|
Ch *bufferLast_;
|
||||||
|
Ch *current_;
|
||||||
|
size_t readCount_;
|
||||||
|
size_t count_; //!< Number of characters read
|
||||||
|
bool eof_;
|
||||||
|
};
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_FILESTREAM_H_
|
||||||
104
libs/discordrpc/rapidjson/filewritestream.h
Normal file
104
libs/discordrpc/rapidjson/filewritestream.h
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_FILEWRITESTREAM_H_
|
||||||
|
#define RAPIDJSON_FILEWRITESTREAM_H_
|
||||||
|
|
||||||
|
#include "stream.h"
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(unreachable-code)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
//! Wrapper of C file stream for input using fread().
|
||||||
|
/*!
|
||||||
|
\note implements Stream concept
|
||||||
|
*/
|
||||||
|
class FileWriteStream {
|
||||||
|
public:
|
||||||
|
typedef char Ch; //!< Character type. Only support char.
|
||||||
|
|
||||||
|
FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) {
|
||||||
|
RAPIDJSON_ASSERT(fp_ != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Put(char c) {
|
||||||
|
if (current_ >= bufferEnd_)
|
||||||
|
Flush();
|
||||||
|
|
||||||
|
*current_++ = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PutN(char c, size_t n) {
|
||||||
|
size_t avail = static_cast<size_t>(bufferEnd_ - current_);
|
||||||
|
while (n > avail) {
|
||||||
|
std::memset(current_, c, avail);
|
||||||
|
current_ += avail;
|
||||||
|
Flush();
|
||||||
|
n -= avail;
|
||||||
|
avail = static_cast<size_t>(bufferEnd_ - current_);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n > 0) {
|
||||||
|
std::memset(current_, c, n);
|
||||||
|
current_ += n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Flush() {
|
||||||
|
if (current_ != buffer_) {
|
||||||
|
size_t result = fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
|
||||||
|
if (result < static_cast<size_t>(current_ - buffer_)) {
|
||||||
|
// failure deliberately ignored at this time
|
||||||
|
// added to avoid warn_unused_result build errors
|
||||||
|
}
|
||||||
|
current_ = buffer_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not implemented
|
||||||
|
char Peek() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
char Take() { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Prohibit copy constructor & assignment operator.
|
||||||
|
FileWriteStream(const FileWriteStream&);
|
||||||
|
FileWriteStream& operator=(const FileWriteStream&);
|
||||||
|
|
||||||
|
std::FILE* fp_;
|
||||||
|
char *buffer_;
|
||||||
|
char *bufferEnd_;
|
||||||
|
char *current_;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Implement specialized version of PutN() with memset() for better performance.
|
||||||
|
template<>
|
||||||
|
inline void PutN(FileWriteStream& stream, char c, size_t n) {
|
||||||
|
stream.PutN(c, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_FILESTREAM_H_
|
||||||
151
libs/discordrpc/rapidjson/fwd.h
Normal file
151
libs/discordrpc/rapidjson/fwd.h
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_FWD_H_
|
||||||
|
#define RAPIDJSON_FWD_H_
|
||||||
|
|
||||||
|
#include "rapidjson.h"
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
// encodings.h
|
||||||
|
|
||||||
|
template<typename CharType> struct UTF8;
|
||||||
|
template<typename CharType> struct UTF16;
|
||||||
|
template<typename CharType> struct UTF16BE;
|
||||||
|
template<typename CharType> struct UTF16LE;
|
||||||
|
template<typename CharType> struct UTF32;
|
||||||
|
template<typename CharType> struct UTF32BE;
|
||||||
|
template<typename CharType> struct UTF32LE;
|
||||||
|
template<typename CharType> struct ASCII;
|
||||||
|
template<typename CharType> struct AutoUTF;
|
||||||
|
|
||||||
|
template<typename SourceEncoding, typename TargetEncoding>
|
||||||
|
struct Transcoder;
|
||||||
|
|
||||||
|
// allocators.h
|
||||||
|
|
||||||
|
class CrtAllocator;
|
||||||
|
|
||||||
|
template <typename BaseAllocator>
|
||||||
|
class MemoryPoolAllocator;
|
||||||
|
|
||||||
|
// stream.h
|
||||||
|
|
||||||
|
template <typename Encoding>
|
||||||
|
struct GenericStringStream;
|
||||||
|
|
||||||
|
typedef GenericStringStream<UTF8<char> > StringStream;
|
||||||
|
|
||||||
|
template <typename Encoding>
|
||||||
|
struct GenericInsituStringStream;
|
||||||
|
|
||||||
|
typedef GenericInsituStringStream<UTF8<char> > InsituStringStream;
|
||||||
|
|
||||||
|
// stringbuffer.h
|
||||||
|
|
||||||
|
template <typename Encoding, typename Allocator>
|
||||||
|
class GenericStringBuffer;
|
||||||
|
|
||||||
|
typedef GenericStringBuffer<UTF8<char>, CrtAllocator> StringBuffer;
|
||||||
|
|
||||||
|
// filereadstream.h
|
||||||
|
|
||||||
|
class FileReadStream;
|
||||||
|
|
||||||
|
// filewritestream.h
|
||||||
|
|
||||||
|
class FileWriteStream;
|
||||||
|
|
||||||
|
// memorybuffer.h
|
||||||
|
|
||||||
|
template <typename Allocator>
|
||||||
|
struct GenericMemoryBuffer;
|
||||||
|
|
||||||
|
typedef GenericMemoryBuffer<CrtAllocator> MemoryBuffer;
|
||||||
|
|
||||||
|
// memorystream.h
|
||||||
|
|
||||||
|
struct MemoryStream;
|
||||||
|
|
||||||
|
// reader.h
|
||||||
|
|
||||||
|
template<typename Encoding, typename Derived>
|
||||||
|
struct BaseReaderHandler;
|
||||||
|
|
||||||
|
template <typename SourceEncoding, typename TargetEncoding, typename StackAllocator>
|
||||||
|
class GenericReader;
|
||||||
|
|
||||||
|
typedef GenericReader<UTF8<char>, UTF8<char>, CrtAllocator> Reader;
|
||||||
|
|
||||||
|
// writer.h
|
||||||
|
|
||||||
|
template<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags>
|
||||||
|
class Writer;
|
||||||
|
|
||||||
|
// prettywriter.h
|
||||||
|
|
||||||
|
template<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags>
|
||||||
|
class PrettyWriter;
|
||||||
|
|
||||||
|
// document.h
|
||||||
|
|
||||||
|
template <typename Encoding, typename Allocator>
|
||||||
|
struct GenericMember;
|
||||||
|
|
||||||
|
template <bool Const, typename Encoding, typename Allocator>
|
||||||
|
class GenericMemberIterator;
|
||||||
|
|
||||||
|
template<typename CharType>
|
||||||
|
struct GenericStringRef;
|
||||||
|
|
||||||
|
template <typename Encoding, typename Allocator>
|
||||||
|
class GenericValue;
|
||||||
|
|
||||||
|
typedef GenericValue<UTF8<char>, MemoryPoolAllocator<CrtAllocator> > Value;
|
||||||
|
|
||||||
|
template <typename Encoding, typename Allocator, typename StackAllocator>
|
||||||
|
class GenericDocument;
|
||||||
|
|
||||||
|
typedef GenericDocument<UTF8<char>, MemoryPoolAllocator<CrtAllocator>, CrtAllocator> Document;
|
||||||
|
|
||||||
|
// pointer.h
|
||||||
|
|
||||||
|
template <typename ValueType, typename Allocator>
|
||||||
|
class GenericPointer;
|
||||||
|
|
||||||
|
typedef GenericPointer<Value, CrtAllocator> Pointer;
|
||||||
|
|
||||||
|
// schema.h
|
||||||
|
|
||||||
|
template <typename SchemaDocumentType>
|
||||||
|
class IGenericRemoteSchemaDocumentProvider;
|
||||||
|
|
||||||
|
template <typename ValueT, typename Allocator>
|
||||||
|
class GenericSchemaDocument;
|
||||||
|
|
||||||
|
typedef GenericSchemaDocument<Value, CrtAllocator> SchemaDocument;
|
||||||
|
typedef IGenericRemoteSchemaDocumentProvider<SchemaDocument> IRemoteSchemaDocumentProvider;
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename SchemaDocumentType,
|
||||||
|
typename OutputHandler,
|
||||||
|
typename StateAllocator>
|
||||||
|
class GenericSchemaValidator;
|
||||||
|
|
||||||
|
typedef GenericSchemaValidator<SchemaDocument, BaseReaderHandler<UTF8<char>, void>, CrtAllocator> SchemaValidator;
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_RAPIDJSONFWD_H_
|
||||||
290
libs/discordrpc/rapidjson/internal/biginteger.h
Normal file
290
libs/discordrpc/rapidjson/internal/biginteger.h
Normal file
@@ -0,0 +1,290 @@
|
|||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_BIGINTEGER_H_
|
||||||
|
#define RAPIDJSON_BIGINTEGER_H_
|
||||||
|
|
||||||
|
#include "../rapidjson.h"
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||||
|
#include <intrin.h> // for _umul128
|
||||||
|
#pragma intrinsic(_umul128)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
class BigInteger {
|
||||||
|
public:
|
||||||
|
typedef uint64_t Type;
|
||||||
|
|
||||||
|
BigInteger(const BigInteger& rhs) : count_(rhs.count_) {
|
||||||
|
std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit BigInteger(uint64_t u) : count_(1) {
|
||||||
|
digits_[0] = u;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger(const char* decimals, size_t length) : count_(1) {
|
||||||
|
RAPIDJSON_ASSERT(length > 0);
|
||||||
|
digits_[0] = 0;
|
||||||
|
size_t i = 0;
|
||||||
|
const size_t kMaxDigitPerIteration = 19; // 2^64 = 18446744073709551616 > 10^19
|
||||||
|
while (length >= kMaxDigitPerIteration) {
|
||||||
|
AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration);
|
||||||
|
length -= kMaxDigitPerIteration;
|
||||||
|
i += kMaxDigitPerIteration;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length > 0)
|
||||||
|
AppendDecimal64(decimals + i, decimals + i + length);
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger& operator=(const BigInteger &rhs)
|
||||||
|
{
|
||||||
|
if (this != &rhs) {
|
||||||
|
count_ = rhs.count_;
|
||||||
|
std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger& operator=(uint64_t u) {
|
||||||
|
digits_[0] = u;
|
||||||
|
count_ = 1;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger& operator+=(uint64_t u) {
|
||||||
|
Type backup = digits_[0];
|
||||||
|
digits_[0] += u;
|
||||||
|
for (size_t i = 0; i < count_ - 1; i++) {
|
||||||
|
if (digits_[i] >= backup)
|
||||||
|
return *this; // no carry
|
||||||
|
backup = digits_[i + 1];
|
||||||
|
digits_[i + 1] += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Last carry
|
||||||
|
if (digits_[count_ - 1] < backup)
|
||||||
|
PushBack(1);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger& operator*=(uint64_t u) {
|
||||||
|
if (u == 0) return *this = 0;
|
||||||
|
if (u == 1) return *this;
|
||||||
|
if (*this == 1) return *this = u;
|
||||||
|
|
||||||
|
uint64_t k = 0;
|
||||||
|
for (size_t i = 0; i < count_; i++) {
|
||||||
|
uint64_t hi;
|
||||||
|
digits_[i] = MulAdd64(digits_[i], u, k, &hi);
|
||||||
|
k = hi;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (k > 0)
|
||||||
|
PushBack(k);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger& operator*=(uint32_t u) {
|
||||||
|
if (u == 0) return *this = 0;
|
||||||
|
if (u == 1) return *this;
|
||||||
|
if (*this == 1) return *this = u;
|
||||||
|
|
||||||
|
uint64_t k = 0;
|
||||||
|
for (size_t i = 0; i < count_; i++) {
|
||||||
|
const uint64_t c = digits_[i] >> 32;
|
||||||
|
const uint64_t d = digits_[i] & 0xFFFFFFFF;
|
||||||
|
const uint64_t uc = u * c;
|
||||||
|
const uint64_t ud = u * d;
|
||||||
|
const uint64_t p0 = ud + k;
|
||||||
|
const uint64_t p1 = uc + (p0 >> 32);
|
||||||
|
digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32);
|
||||||
|
k = p1 >> 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (k > 0)
|
||||||
|
PushBack(k);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger& operator<<=(size_t shift) {
|
||||||
|
if (IsZero() || shift == 0) return *this;
|
||||||
|
|
||||||
|
size_t offset = shift / kTypeBit;
|
||||||
|
size_t interShift = shift % kTypeBit;
|
||||||
|
RAPIDJSON_ASSERT(count_ + offset <= kCapacity);
|
||||||
|
|
||||||
|
if (interShift == 0) {
|
||||||
|
std::memmove(&digits_[count_ - 1 + offset], &digits_[count_ - 1], count_ * sizeof(Type));
|
||||||
|
count_ += offset;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
digits_[count_] = 0;
|
||||||
|
for (size_t i = count_; i > 0; i--)
|
||||||
|
digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift));
|
||||||
|
digits_[offset] = digits_[0] << interShift;
|
||||||
|
count_ += offset;
|
||||||
|
if (digits_[count_])
|
||||||
|
count_++;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memset(digits_, 0, offset * sizeof(Type));
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const BigInteger& rhs) const {
|
||||||
|
return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const Type rhs) const {
|
||||||
|
return count_ == 1 && digits_[0] == rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger& MultiplyPow5(unsigned exp) {
|
||||||
|
static const uint32_t kPow5[12] = {
|
||||||
|
5,
|
||||||
|
5 * 5,
|
||||||
|
5 * 5 * 5,
|
||||||
|
5 * 5 * 5 * 5,
|
||||||
|
5 * 5 * 5 * 5 * 5,
|
||||||
|
5 * 5 * 5 * 5 * 5 * 5,
|
||||||
|
5 * 5 * 5 * 5 * 5 * 5 * 5,
|
||||||
|
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
|
||||||
|
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
|
||||||
|
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
|
||||||
|
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
|
||||||
|
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5
|
||||||
|
};
|
||||||
|
if (exp == 0) return *this;
|
||||||
|
for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27
|
||||||
|
for (; exp >= 13; exp -= 13) *this *= static_cast<uint32_t>(1220703125u); // 5^13
|
||||||
|
if (exp > 0) *this *= kPow5[exp - 1];
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute absolute difference of this and rhs.
|
||||||
|
// Assume this != rhs
|
||||||
|
bool Difference(const BigInteger& rhs, BigInteger* out) const {
|
||||||
|
int cmp = Compare(rhs);
|
||||||
|
RAPIDJSON_ASSERT(cmp != 0);
|
||||||
|
const BigInteger *a, *b; // Makes a > b
|
||||||
|
bool ret;
|
||||||
|
if (cmp < 0) { a = &rhs; b = this; ret = true; }
|
||||||
|
else { a = this; b = &rhs; ret = false; }
|
||||||
|
|
||||||
|
Type borrow = 0;
|
||||||
|
for (size_t i = 0; i < a->count_; i++) {
|
||||||
|
Type d = a->digits_[i] - borrow;
|
||||||
|
if (i < b->count_)
|
||||||
|
d -= b->digits_[i];
|
||||||
|
borrow = (d > a->digits_[i]) ? 1 : 0;
|
||||||
|
out->digits_[i] = d;
|
||||||
|
if (d != 0)
|
||||||
|
out->count_ = i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Compare(const BigInteger& rhs) const {
|
||||||
|
if (count_ != rhs.count_)
|
||||||
|
return count_ < rhs.count_ ? -1 : 1;
|
||||||
|
|
||||||
|
for (size_t i = count_; i-- > 0;)
|
||||||
|
if (digits_[i] != rhs.digits_[i])
|
||||||
|
return digits_[i] < rhs.digits_[i] ? -1 : 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t GetCount() const { return count_; }
|
||||||
|
Type GetDigit(size_t index) const { RAPIDJSON_ASSERT(index < count_); return digits_[index]; }
|
||||||
|
bool IsZero() const { return count_ == 1 && digits_[0] == 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void AppendDecimal64(const char* begin, const char* end) {
|
||||||
|
uint64_t u = ParseUint64(begin, end);
|
||||||
|
if (IsZero())
|
||||||
|
*this = u;
|
||||||
|
else {
|
||||||
|
unsigned exp = static_cast<unsigned>(end - begin);
|
||||||
|
(MultiplyPow5(exp) <<= exp) += u; // *this = *this * 10^exp + u
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PushBack(Type digit) {
|
||||||
|
RAPIDJSON_ASSERT(count_ < kCapacity);
|
||||||
|
digits_[count_++] = digit;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t ParseUint64(const char* begin, const char* end) {
|
||||||
|
uint64_t r = 0;
|
||||||
|
for (const char* p = begin; p != end; ++p) {
|
||||||
|
RAPIDJSON_ASSERT(*p >= '0' && *p <= '9');
|
||||||
|
r = r * 10u + static_cast<unsigned>(*p - '0');
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assume a * b + k < 2^128
|
||||||
|
static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh) {
|
||||||
|
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||||
|
uint64_t low = _umul128(a, b, outHigh) + k;
|
||||||
|
if (low < k)
|
||||||
|
(*outHigh)++;
|
||||||
|
return low;
|
||||||
|
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
|
||||||
|
__extension__ typedef unsigned __int128 uint128;
|
||||||
|
uint128 p = static_cast<uint128>(a) * static_cast<uint128>(b);
|
||||||
|
p += k;
|
||||||
|
*outHigh = static_cast<uint64_t>(p >> 64);
|
||||||
|
return static_cast<uint64_t>(p);
|
||||||
|
#else
|
||||||
|
const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32;
|
||||||
|
uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1;
|
||||||
|
x1 += (x0 >> 32); // can't give carry
|
||||||
|
x1 += x2;
|
||||||
|
if (x1 < x2)
|
||||||
|
x3 += (static_cast<uint64_t>(1) << 32);
|
||||||
|
uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF);
|
||||||
|
uint64_t hi = x3 + (x1 >> 32);
|
||||||
|
|
||||||
|
lo += k;
|
||||||
|
if (lo < k)
|
||||||
|
hi++;
|
||||||
|
*outHigh = hi;
|
||||||
|
return lo;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static const size_t kBitCount = 3328; // 64bit * 54 > 10^1000
|
||||||
|
static const size_t kCapacity = kBitCount / sizeof(Type);
|
||||||
|
static const size_t kTypeBit = sizeof(Type) * 8;
|
||||||
|
|
||||||
|
Type digits_[kCapacity];
|
||||||
|
size_t count_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_BIGINTEGER_H_
|
||||||
258
libs/discordrpc/rapidjson/internal/diyfp.h
Normal file
258
libs/discordrpc/rapidjson/internal/diyfp.h
Normal file
@@ -0,0 +1,258 @@
|
|||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
|
||||||
|
// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
|
||||||
|
// integers." ACM Sigplan Notices 45.6 (2010): 233-243.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_DIYFP_H_
|
||||||
|
#define RAPIDJSON_DIYFP_H_
|
||||||
|
|
||||||
|
#include "../rapidjson.h"
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||||
|
#include <intrin.h>
|
||||||
|
#pragma intrinsic(_BitScanReverse64)
|
||||||
|
#pragma intrinsic(_umul128)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(effc++)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(padded)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct DiyFp {
|
||||||
|
DiyFp() : f(), e() {}
|
||||||
|
|
||||||
|
DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {}
|
||||||
|
|
||||||
|
explicit DiyFp(double d) {
|
||||||
|
union {
|
||||||
|
double d;
|
||||||
|
uint64_t u64;
|
||||||
|
} u = { d };
|
||||||
|
|
||||||
|
int biased_e = static_cast<int>((u.u64 & kDpExponentMask) >> kDpSignificandSize);
|
||||||
|
uint64_t significand = (u.u64 & kDpSignificandMask);
|
||||||
|
if (biased_e != 0) {
|
||||||
|
f = significand + kDpHiddenBit;
|
||||||
|
e = biased_e - kDpExponentBias;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
f = significand;
|
||||||
|
e = kDpMinExponent + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DiyFp operator-(const DiyFp& rhs) const {
|
||||||
|
return DiyFp(f - rhs.f, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
DiyFp operator*(const DiyFp& rhs) const {
|
||||||
|
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||||
|
uint64_t h;
|
||||||
|
uint64_t l = _umul128(f, rhs.f, &h);
|
||||||
|
if (l & (uint64_t(1) << 63)) // rounding
|
||||||
|
h++;
|
||||||
|
return DiyFp(h, e + rhs.e + 64);
|
||||||
|
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
|
||||||
|
__extension__ typedef unsigned __int128 uint128;
|
||||||
|
uint128 p = static_cast<uint128>(f) * static_cast<uint128>(rhs.f);
|
||||||
|
uint64_t h = static_cast<uint64_t>(p >> 64);
|
||||||
|
uint64_t l = static_cast<uint64_t>(p);
|
||||||
|
if (l & (uint64_t(1) << 63)) // rounding
|
||||||
|
h++;
|
||||||
|
return DiyFp(h, e + rhs.e + 64);
|
||||||
|
#else
|
||||||
|
const uint64_t M32 = 0xFFFFFFFF;
|
||||||
|
const uint64_t a = f >> 32;
|
||||||
|
const uint64_t b = f & M32;
|
||||||
|
const uint64_t c = rhs.f >> 32;
|
||||||
|
const uint64_t d = rhs.f & M32;
|
||||||
|
const uint64_t ac = a * c;
|
||||||
|
const uint64_t bc = b * c;
|
||||||
|
const uint64_t ad = a * d;
|
||||||
|
const uint64_t bd = b * d;
|
||||||
|
uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32);
|
||||||
|
tmp += 1U << 31; /// mult_round
|
||||||
|
return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
DiyFp Normalize() const {
|
||||||
|
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||||
|
unsigned long index;
|
||||||
|
_BitScanReverse64(&index, f);
|
||||||
|
return DiyFp(f << (63 - index), e - (63 - index));
|
||||||
|
#elif defined(__GNUC__) && __GNUC__ >= 4
|
||||||
|
int s = __builtin_clzll(f);
|
||||||
|
return DiyFp(f << s, e - s);
|
||||||
|
#else
|
||||||
|
DiyFp res = *this;
|
||||||
|
while (!(res.f & (static_cast<uint64_t>(1) << 63))) {
|
||||||
|
res.f <<= 1;
|
||||||
|
res.e--;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
DiyFp NormalizeBoundary() const {
|
||||||
|
DiyFp res = *this;
|
||||||
|
while (!(res.f & (kDpHiddenBit << 1))) {
|
||||||
|
res.f <<= 1;
|
||||||
|
res.e--;
|
||||||
|
}
|
||||||
|
res.f <<= (kDiySignificandSize - kDpSignificandSize - 2);
|
||||||
|
res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const {
|
||||||
|
DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary();
|
||||||
|
DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1);
|
||||||
|
mi.f <<= mi.e - pl.e;
|
||||||
|
mi.e = pl.e;
|
||||||
|
*plus = pl;
|
||||||
|
*minus = mi;
|
||||||
|
}
|
||||||
|
|
||||||
|
double ToDouble() const {
|
||||||
|
union {
|
||||||
|
double d;
|
||||||
|
uint64_t u64;
|
||||||
|
}u;
|
||||||
|
const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 :
|
||||||
|
static_cast<uint64_t>(e + kDpExponentBias);
|
||||||
|
u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize);
|
||||||
|
return u.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const int kDiySignificandSize = 64;
|
||||||
|
static const int kDpSignificandSize = 52;
|
||||||
|
static const int kDpExponentBias = 0x3FF + kDpSignificandSize;
|
||||||
|
static const int kDpMaxExponent = 0x7FF - kDpExponentBias;
|
||||||
|
static const int kDpMinExponent = -kDpExponentBias;
|
||||||
|
static const int kDpDenormalExponent = -kDpExponentBias + 1;
|
||||||
|
static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
|
||||||
|
static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
|
||||||
|
static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
|
||||||
|
|
||||||
|
uint64_t f;
|
||||||
|
int e;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline DiyFp GetCachedPowerByIndex(size_t index) {
|
||||||
|
// 10^-348, 10^-340, ..., 10^340
|
||||||
|
static const uint64_t kCachedPowers_F[] = {
|
||||||
|
RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76),
|
||||||
|
RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea),
|
||||||
|
RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df),
|
||||||
|
RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f),
|
||||||
|
RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c),
|
||||||
|
RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5),
|
||||||
|
RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d),
|
||||||
|
RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637),
|
||||||
|
RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7),
|
||||||
|
RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5),
|
||||||
|
RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b),
|
||||||
|
RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996),
|
||||||
|
RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6),
|
||||||
|
RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8),
|
||||||
|
RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053),
|
||||||
|
RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd),
|
||||||
|
RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94),
|
||||||
|
RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b),
|
||||||
|
RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac),
|
||||||
|
RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3),
|
||||||
|
RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb),
|
||||||
|
RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c),
|
||||||
|
RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000),
|
||||||
|
RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984),
|
||||||
|
RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70),
|
||||||
|
RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245),
|
||||||
|
RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8),
|
||||||
|
RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a),
|
||||||
|
RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea),
|
||||||
|
RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85),
|
||||||
|
RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2),
|
||||||
|
RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3),
|
||||||
|
RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25),
|
||||||
|
RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece),
|
||||||
|
RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5),
|
||||||
|
RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a),
|
||||||
|
RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c),
|
||||||
|
RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a),
|
||||||
|
RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129),
|
||||||
|
RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429),
|
||||||
|
RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d),
|
||||||
|
RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841),
|
||||||
|
RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9),
|
||||||
|
RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b)
|
||||||
|
};
|
||||||
|
static const int16_t kCachedPowers_E[] = {
|
||||||
|
-1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980,
|
||||||
|
-954, -927, -901, -874, -847, -821, -794, -768, -741, -715,
|
||||||
|
-688, -661, -635, -608, -582, -555, -529, -502, -475, -449,
|
||||||
|
-422, -396, -369, -343, -316, -289, -263, -236, -210, -183,
|
||||||
|
-157, -130, -103, -77, -50, -24, 3, 30, 56, 83,
|
||||||
|
109, 136, 162, 189, 216, 242, 269, 295, 322, 348,
|
||||||
|
375, 402, 428, 455, 481, 508, 534, 561, 588, 614,
|
||||||
|
641, 667, 694, 720, 747, 774, 800, 827, 853, 880,
|
||||||
|
907, 933, 960, 986, 1013, 1039, 1066
|
||||||
|
};
|
||||||
|
return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline DiyFp GetCachedPower(int e, int* K) {
|
||||||
|
|
||||||
|
//int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374;
|
||||||
|
double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive
|
||||||
|
int k = static_cast<int>(dk);
|
||||||
|
if (dk - k > 0.0)
|
||||||
|
k++;
|
||||||
|
|
||||||
|
unsigned index = static_cast<unsigned>((k >> 3) + 1);
|
||||||
|
*K = -(-348 + static_cast<int>(index << 3)); // decimal exponent no need lookup table
|
||||||
|
|
||||||
|
return GetCachedPowerByIndex(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline DiyFp GetCachedPower10(int exp, int *outExp) {
|
||||||
|
unsigned index = (static_cast<unsigned>(exp) + 348u) / 8u;
|
||||||
|
*outExp = -348 + static_cast<int>(index) * 8;
|
||||||
|
return GetCachedPowerByIndex(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
RAPIDJSON_DIAG_OFF(padded)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_DIYFP_H_
|
||||||
245
libs/discordrpc/rapidjson/internal/dtoa.h
Normal file
245
libs/discordrpc/rapidjson/internal/dtoa.h
Normal file
@@ -0,0 +1,245 @@
|
|||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
|
||||||
|
// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
|
||||||
|
// integers." ACM Sigplan Notices 45.6 (2010): 233-243.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_DTOA_
|
||||||
|
#define RAPIDJSON_DTOA_
|
||||||
|
|
||||||
|
#include "itoa.h" // GetDigitsLut()
|
||||||
|
#include "diyfp.h"
|
||||||
|
#include "ieee754.h"
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(effc++)
|
||||||
|
RAPIDJSON_DIAG_OFF(array-bounds) // some gcc versions generate wrong warnings https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124
|
||||||
|
#endif
|
||||||
|
|
||||||
|
inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) {
|
||||||
|
while (rest < wp_w && delta - rest >= ten_kappa &&
|
||||||
|
(rest + ten_kappa < wp_w || /// closer
|
||||||
|
wp_w - rest > rest + ten_kappa - wp_w)) {
|
||||||
|
buffer[len - 1]--;
|
||||||
|
rest += ten_kappa;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned CountDecimalDigit32(uint32_t n) {
|
||||||
|
// Simple pure C++ implementation was faster than __builtin_clz version in this situation.
|
||||||
|
if (n < 10) return 1;
|
||||||
|
if (n < 100) return 2;
|
||||||
|
if (n < 1000) return 3;
|
||||||
|
if (n < 10000) return 4;
|
||||||
|
if (n < 100000) return 5;
|
||||||
|
if (n < 1000000) return 6;
|
||||||
|
if (n < 10000000) return 7;
|
||||||
|
if (n < 100000000) return 8;
|
||||||
|
// Will not reach 10 digits in DigitGen()
|
||||||
|
//if (n < 1000000000) return 9;
|
||||||
|
//return 10;
|
||||||
|
return 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) {
|
||||||
|
static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
|
||||||
|
const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);
|
||||||
|
const DiyFp wp_w = Mp - W;
|
||||||
|
uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
|
||||||
|
uint64_t p2 = Mp.f & (one.f - 1);
|
||||||
|
unsigned kappa = CountDecimalDigit32(p1); // kappa in [0, 9]
|
||||||
|
*len = 0;
|
||||||
|
|
||||||
|
while (kappa > 0) {
|
||||||
|
uint32_t d = 0;
|
||||||
|
switch (kappa) {
|
||||||
|
case 9: d = p1 / 100000000; p1 %= 100000000; break;
|
||||||
|
case 8: d = p1 / 10000000; p1 %= 10000000; break;
|
||||||
|
case 7: d = p1 / 1000000; p1 %= 1000000; break;
|
||||||
|
case 6: d = p1 / 100000; p1 %= 100000; break;
|
||||||
|
case 5: d = p1 / 10000; p1 %= 10000; break;
|
||||||
|
case 4: d = p1 / 1000; p1 %= 1000; break;
|
||||||
|
case 3: d = p1 / 100; p1 %= 100; break;
|
||||||
|
case 2: d = p1 / 10; p1 %= 10; break;
|
||||||
|
case 1: d = p1; p1 = 0; break;
|
||||||
|
default:;
|
||||||
|
}
|
||||||
|
if (d || *len)
|
||||||
|
buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d));
|
||||||
|
kappa--;
|
||||||
|
uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2;
|
||||||
|
if (tmp <= delta) {
|
||||||
|
*K += kappa;
|
||||||
|
GrisuRound(buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// kappa = 0
|
||||||
|
for (;;) {
|
||||||
|
p2 *= 10;
|
||||||
|
delta *= 10;
|
||||||
|
char d = static_cast<char>(p2 >> -one.e);
|
||||||
|
if (d || *len)
|
||||||
|
buffer[(*len)++] = static_cast<char>('0' + d);
|
||||||
|
p2 &= one.f - 1;
|
||||||
|
kappa--;
|
||||||
|
if (p2 < delta) {
|
||||||
|
*K += kappa;
|
||||||
|
int index = -static_cast<int>(kappa);
|
||||||
|
GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[-static_cast<int>(kappa)] : 0));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Grisu2(double value, char* buffer, int* length, int* K) {
|
||||||
|
const DiyFp v(value);
|
||||||
|
DiyFp w_m, w_p;
|
||||||
|
v.NormalizedBoundaries(&w_m, &w_p);
|
||||||
|
|
||||||
|
const DiyFp c_mk = GetCachedPower(w_p.e, K);
|
||||||
|
const DiyFp W = v.Normalize() * c_mk;
|
||||||
|
DiyFp Wp = w_p * c_mk;
|
||||||
|
DiyFp Wm = w_m * c_mk;
|
||||||
|
Wm.f++;
|
||||||
|
Wp.f--;
|
||||||
|
DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char* WriteExponent(int K, char* buffer) {
|
||||||
|
if (K < 0) {
|
||||||
|
*buffer++ = '-';
|
||||||
|
K = -K;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (K >= 100) {
|
||||||
|
*buffer++ = static_cast<char>('0' + static_cast<char>(K / 100));
|
||||||
|
K %= 100;
|
||||||
|
const char* d = GetDigitsLut() + K * 2;
|
||||||
|
*buffer++ = d[0];
|
||||||
|
*buffer++ = d[1];
|
||||||
|
}
|
||||||
|
else if (K >= 10) {
|
||||||
|
const char* d = GetDigitsLut() + K * 2;
|
||||||
|
*buffer++ = d[0];
|
||||||
|
*buffer++ = d[1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*buffer++ = static_cast<char>('0' + static_cast<char>(K));
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) {
|
||||||
|
const int kk = length + k; // 10^(kk-1) <= v < 10^kk
|
||||||
|
|
||||||
|
if (0 <= k && kk <= 21) {
|
||||||
|
// 1234e7 -> 12340000000
|
||||||
|
for (int i = length; i < kk; i++)
|
||||||
|
buffer[i] = '0';
|
||||||
|
buffer[kk] = '.';
|
||||||
|
buffer[kk + 1] = '0';
|
||||||
|
return &buffer[kk + 2];
|
||||||
|
}
|
||||||
|
else if (0 < kk && kk <= 21) {
|
||||||
|
// 1234e-2 -> 12.34
|
||||||
|
std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk));
|
||||||
|
buffer[kk] = '.';
|
||||||
|
if (0 > k + maxDecimalPlaces) {
|
||||||
|
// When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1
|
||||||
|
// Remove extra trailing zeros (at least one) after truncation.
|
||||||
|
for (int i = kk + maxDecimalPlaces; i > kk + 1; i--)
|
||||||
|
if (buffer[i] != '0')
|
||||||
|
return &buffer[i + 1];
|
||||||
|
return &buffer[kk + 2]; // Reserve one zero
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return &buffer[length + 1];
|
||||||
|
}
|
||||||
|
else if (-6 < kk && kk <= 0) {
|
||||||
|
// 1234e-6 -> 0.001234
|
||||||
|
const int offset = 2 - kk;
|
||||||
|
std::memmove(&buffer[offset], &buffer[0], static_cast<size_t>(length));
|
||||||
|
buffer[0] = '0';
|
||||||
|
buffer[1] = '.';
|
||||||
|
for (int i = 2; i < offset; i++)
|
||||||
|
buffer[i] = '0';
|
||||||
|
if (length - kk > maxDecimalPlaces) {
|
||||||
|
// When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1
|
||||||
|
// Remove extra trailing zeros (at least one) after truncation.
|
||||||
|
for (int i = maxDecimalPlaces + 1; i > 2; i--)
|
||||||
|
if (buffer[i] != '0')
|
||||||
|
return &buffer[i + 1];
|
||||||
|
return &buffer[3]; // Reserve one zero
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return &buffer[length + offset];
|
||||||
|
}
|
||||||
|
else if (kk < -maxDecimalPlaces) {
|
||||||
|
// Truncate to zero
|
||||||
|
buffer[0] = '0';
|
||||||
|
buffer[1] = '.';
|
||||||
|
buffer[2] = '0';
|
||||||
|
return &buffer[3];
|
||||||
|
}
|
||||||
|
else if (length == 1) {
|
||||||
|
// 1e30
|
||||||
|
buffer[1] = 'e';
|
||||||
|
return WriteExponent(kk - 1, &buffer[2]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// 1234e30 -> 1.234e33
|
||||||
|
std::memmove(&buffer[2], &buffer[1], static_cast<size_t>(length - 1));
|
||||||
|
buffer[1] = '.';
|
||||||
|
buffer[length + 1] = 'e';
|
||||||
|
return WriteExponent(kk - 1, &buffer[0 + length + 2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) {
|
||||||
|
RAPIDJSON_ASSERT(maxDecimalPlaces >= 1);
|
||||||
|
Double d(value);
|
||||||
|
if (d.IsZero()) {
|
||||||
|
if (d.Sign())
|
||||||
|
*buffer++ = '-'; // -0.0, Issue #289
|
||||||
|
buffer[0] = '0';
|
||||||
|
buffer[1] = '.';
|
||||||
|
buffer[2] = '0';
|
||||||
|
return &buffer[3];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (value < 0) {
|
||||||
|
*buffer++ = '-';
|
||||||
|
value = -value;
|
||||||
|
}
|
||||||
|
int length, K;
|
||||||
|
Grisu2(value, buffer, &length, &K);
|
||||||
|
return Prettify(buffer, length, K, maxDecimalPlaces);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_DTOA_
|
||||||
78
libs/discordrpc/rapidjson/internal/ieee754.h
Normal file
78
libs/discordrpc/rapidjson/internal/ieee754.h
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_IEEE754_
|
||||||
|
#define RAPIDJSON_IEEE754_
|
||||||
|
|
||||||
|
#include "../rapidjson.h"
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
class Double {
|
||||||
|
public:
|
||||||
|
Double() {}
|
||||||
|
Double(double d) : d_(d) {}
|
||||||
|
Double(uint64_t u) : u_(u) {}
|
||||||
|
|
||||||
|
double Value() const { return d_; }
|
||||||
|
uint64_t Uint64Value() const { return u_; }
|
||||||
|
|
||||||
|
double NextPositiveDouble() const {
|
||||||
|
RAPIDJSON_ASSERT(!Sign());
|
||||||
|
return Double(u_ + 1).Value();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Sign() const { return (u_ & kSignMask) != 0; }
|
||||||
|
uint64_t Significand() const { return u_ & kSignificandMask; }
|
||||||
|
int Exponent() const { return static_cast<int>(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); }
|
||||||
|
|
||||||
|
bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; }
|
||||||
|
bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; }
|
||||||
|
bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; }
|
||||||
|
bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; }
|
||||||
|
bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; }
|
||||||
|
|
||||||
|
uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); }
|
||||||
|
int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; }
|
||||||
|
uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; }
|
||||||
|
|
||||||
|
static unsigned EffectiveSignificandSize(int order) {
|
||||||
|
if (order >= -1021)
|
||||||
|
return 53;
|
||||||
|
else if (order <= -1074)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return static_cast<unsigned>(order) + 1074;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const int kSignificandSize = 52;
|
||||||
|
static const int kExponentBias = 0x3FF;
|
||||||
|
static const int kDenormalExponent = 1 - kExponentBias;
|
||||||
|
static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000);
|
||||||
|
static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
|
||||||
|
static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
|
||||||
|
static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
|
||||||
|
|
||||||
|
union {
|
||||||
|
double d_;
|
||||||
|
uint64_t u_;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_IEEE754_
|
||||||
304
libs/discordrpc/rapidjson/internal/itoa.h
Normal file
304
libs/discordrpc/rapidjson/internal/itoa.h
Normal file
@@ -0,0 +1,304 @@
|
|||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_ITOA_
|
||||||
|
#define RAPIDJSON_ITOA_
|
||||||
|
|
||||||
|
#include "../rapidjson.h"
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
inline const char* GetDigitsLut() {
|
||||||
|
static const char cDigitsLut[200] = {
|
||||||
|
'0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9',
|
||||||
|
'1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9',
|
||||||
|
'2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9',
|
||||||
|
'3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9',
|
||||||
|
'4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9',
|
||||||
|
'5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9',
|
||||||
|
'6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9',
|
||||||
|
'7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9',
|
||||||
|
'8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9',
|
||||||
|
'9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9'
|
||||||
|
};
|
||||||
|
return cDigitsLut;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char* u32toa(uint32_t value, char* buffer) {
|
||||||
|
const char* cDigitsLut = GetDigitsLut();
|
||||||
|
|
||||||
|
if (value < 10000) {
|
||||||
|
const uint32_t d1 = (value / 100) << 1;
|
||||||
|
const uint32_t d2 = (value % 100) << 1;
|
||||||
|
|
||||||
|
if (value >= 1000)
|
||||||
|
*buffer++ = cDigitsLut[d1];
|
||||||
|
if (value >= 100)
|
||||||
|
*buffer++ = cDigitsLut[d1 + 1];
|
||||||
|
if (value >= 10)
|
||||||
|
*buffer++ = cDigitsLut[d2];
|
||||||
|
*buffer++ = cDigitsLut[d2 + 1];
|
||||||
|
}
|
||||||
|
else if (value < 100000000) {
|
||||||
|
// value = bbbbcccc
|
||||||
|
const uint32_t b = value / 10000;
|
||||||
|
const uint32_t c = value % 10000;
|
||||||
|
|
||||||
|
const uint32_t d1 = (b / 100) << 1;
|
||||||
|
const uint32_t d2 = (b % 100) << 1;
|
||||||
|
|
||||||
|
const uint32_t d3 = (c / 100) << 1;
|
||||||
|
const uint32_t d4 = (c % 100) << 1;
|
||||||
|
|
||||||
|
if (value >= 10000000)
|
||||||
|
*buffer++ = cDigitsLut[d1];
|
||||||
|
if (value >= 1000000)
|
||||||
|
*buffer++ = cDigitsLut[d1 + 1];
|
||||||
|
if (value >= 100000)
|
||||||
|
*buffer++ = cDigitsLut[d2];
|
||||||
|
*buffer++ = cDigitsLut[d2 + 1];
|
||||||
|
|
||||||
|
*buffer++ = cDigitsLut[d3];
|
||||||
|
*buffer++ = cDigitsLut[d3 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d4];
|
||||||
|
*buffer++ = cDigitsLut[d4 + 1];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// value = aabbbbcccc in decimal
|
||||||
|
|
||||||
|
const uint32_t a = value / 100000000; // 1 to 42
|
||||||
|
value %= 100000000;
|
||||||
|
|
||||||
|
if (a >= 10) {
|
||||||
|
const unsigned i = a << 1;
|
||||||
|
*buffer++ = cDigitsLut[i];
|
||||||
|
*buffer++ = cDigitsLut[i + 1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*buffer++ = static_cast<char>('0' + static_cast<char>(a));
|
||||||
|
|
||||||
|
const uint32_t b = value / 10000; // 0 to 9999
|
||||||
|
const uint32_t c = value % 10000; // 0 to 9999
|
||||||
|
|
||||||
|
const uint32_t d1 = (b / 100) << 1;
|
||||||
|
const uint32_t d2 = (b % 100) << 1;
|
||||||
|
|
||||||
|
const uint32_t d3 = (c / 100) << 1;
|
||||||
|
const uint32_t d4 = (c % 100) << 1;
|
||||||
|
|
||||||
|
*buffer++ = cDigitsLut[d1];
|
||||||
|
*buffer++ = cDigitsLut[d1 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d2];
|
||||||
|
*buffer++ = cDigitsLut[d2 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d3];
|
||||||
|
*buffer++ = cDigitsLut[d3 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d4];
|
||||||
|
*buffer++ = cDigitsLut[d4 + 1];
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char* i32toa(int32_t value, char* buffer) {
|
||||||
|
uint32_t u = static_cast<uint32_t>(value);
|
||||||
|
if (value < 0) {
|
||||||
|
*buffer++ = '-';
|
||||||
|
u = ~u + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return u32toa(u, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char* u64toa(uint64_t value, char* buffer) {
|
||||||
|
const char* cDigitsLut = GetDigitsLut();
|
||||||
|
const uint64_t kTen8 = 100000000;
|
||||||
|
const uint64_t kTen9 = kTen8 * 10;
|
||||||
|
const uint64_t kTen10 = kTen8 * 100;
|
||||||
|
const uint64_t kTen11 = kTen8 * 1000;
|
||||||
|
const uint64_t kTen12 = kTen8 * 10000;
|
||||||
|
const uint64_t kTen13 = kTen8 * 100000;
|
||||||
|
const uint64_t kTen14 = kTen8 * 1000000;
|
||||||
|
const uint64_t kTen15 = kTen8 * 10000000;
|
||||||
|
const uint64_t kTen16 = kTen8 * kTen8;
|
||||||
|
|
||||||
|
if (value < kTen8) {
|
||||||
|
uint32_t v = static_cast<uint32_t>(value);
|
||||||
|
if (v < 10000) {
|
||||||
|
const uint32_t d1 = (v / 100) << 1;
|
||||||
|
const uint32_t d2 = (v % 100) << 1;
|
||||||
|
|
||||||
|
if (v >= 1000)
|
||||||
|
*buffer++ = cDigitsLut[d1];
|
||||||
|
if (v >= 100)
|
||||||
|
*buffer++ = cDigitsLut[d1 + 1];
|
||||||
|
if (v >= 10)
|
||||||
|
*buffer++ = cDigitsLut[d2];
|
||||||
|
*buffer++ = cDigitsLut[d2 + 1];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// value = bbbbcccc
|
||||||
|
const uint32_t b = v / 10000;
|
||||||
|
const uint32_t c = v % 10000;
|
||||||
|
|
||||||
|
const uint32_t d1 = (b / 100) << 1;
|
||||||
|
const uint32_t d2 = (b % 100) << 1;
|
||||||
|
|
||||||
|
const uint32_t d3 = (c / 100) << 1;
|
||||||
|
const uint32_t d4 = (c % 100) << 1;
|
||||||
|
|
||||||
|
if (value >= 10000000)
|
||||||
|
*buffer++ = cDigitsLut[d1];
|
||||||
|
if (value >= 1000000)
|
||||||
|
*buffer++ = cDigitsLut[d1 + 1];
|
||||||
|
if (value >= 100000)
|
||||||
|
*buffer++ = cDigitsLut[d2];
|
||||||
|
*buffer++ = cDigitsLut[d2 + 1];
|
||||||
|
|
||||||
|
*buffer++ = cDigitsLut[d3];
|
||||||
|
*buffer++ = cDigitsLut[d3 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d4];
|
||||||
|
*buffer++ = cDigitsLut[d4 + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (value < kTen16) {
|
||||||
|
const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
|
||||||
|
const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
|
||||||
|
|
||||||
|
const uint32_t b0 = v0 / 10000;
|
||||||
|
const uint32_t c0 = v0 % 10000;
|
||||||
|
|
||||||
|
const uint32_t d1 = (b0 / 100) << 1;
|
||||||
|
const uint32_t d2 = (b0 % 100) << 1;
|
||||||
|
|
||||||
|
const uint32_t d3 = (c0 / 100) << 1;
|
||||||
|
const uint32_t d4 = (c0 % 100) << 1;
|
||||||
|
|
||||||
|
const uint32_t b1 = v1 / 10000;
|
||||||
|
const uint32_t c1 = v1 % 10000;
|
||||||
|
|
||||||
|
const uint32_t d5 = (b1 / 100) << 1;
|
||||||
|
const uint32_t d6 = (b1 % 100) << 1;
|
||||||
|
|
||||||
|
const uint32_t d7 = (c1 / 100) << 1;
|
||||||
|
const uint32_t d8 = (c1 % 100) << 1;
|
||||||
|
|
||||||
|
if (value >= kTen15)
|
||||||
|
*buffer++ = cDigitsLut[d1];
|
||||||
|
if (value >= kTen14)
|
||||||
|
*buffer++ = cDigitsLut[d1 + 1];
|
||||||
|
if (value >= kTen13)
|
||||||
|
*buffer++ = cDigitsLut[d2];
|
||||||
|
if (value >= kTen12)
|
||||||
|
*buffer++ = cDigitsLut[d2 + 1];
|
||||||
|
if (value >= kTen11)
|
||||||
|
*buffer++ = cDigitsLut[d3];
|
||||||
|
if (value >= kTen10)
|
||||||
|
*buffer++ = cDigitsLut[d3 + 1];
|
||||||
|
if (value >= kTen9)
|
||||||
|
*buffer++ = cDigitsLut[d4];
|
||||||
|
if (value >= kTen8)
|
||||||
|
*buffer++ = cDigitsLut[d4 + 1];
|
||||||
|
|
||||||
|
*buffer++ = cDigitsLut[d5];
|
||||||
|
*buffer++ = cDigitsLut[d5 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d6];
|
||||||
|
*buffer++ = cDigitsLut[d6 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d7];
|
||||||
|
*buffer++ = cDigitsLut[d7 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d8];
|
||||||
|
*buffer++ = cDigitsLut[d8 + 1];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const uint32_t a = static_cast<uint32_t>(value / kTen16); // 1 to 1844
|
||||||
|
value %= kTen16;
|
||||||
|
|
||||||
|
if (a < 10)
|
||||||
|
*buffer++ = static_cast<char>('0' + static_cast<char>(a));
|
||||||
|
else if (a < 100) {
|
||||||
|
const uint32_t i = a << 1;
|
||||||
|
*buffer++ = cDigitsLut[i];
|
||||||
|
*buffer++ = cDigitsLut[i + 1];
|
||||||
|
}
|
||||||
|
else if (a < 1000) {
|
||||||
|
*buffer++ = static_cast<char>('0' + static_cast<char>(a / 100));
|
||||||
|
|
||||||
|
const uint32_t i = (a % 100) << 1;
|
||||||
|
*buffer++ = cDigitsLut[i];
|
||||||
|
*buffer++ = cDigitsLut[i + 1];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const uint32_t i = (a / 100) << 1;
|
||||||
|
const uint32_t j = (a % 100) << 1;
|
||||||
|
*buffer++ = cDigitsLut[i];
|
||||||
|
*buffer++ = cDigitsLut[i + 1];
|
||||||
|
*buffer++ = cDigitsLut[j];
|
||||||
|
*buffer++ = cDigitsLut[j + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
|
||||||
|
const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
|
||||||
|
|
||||||
|
const uint32_t b0 = v0 / 10000;
|
||||||
|
const uint32_t c0 = v0 % 10000;
|
||||||
|
|
||||||
|
const uint32_t d1 = (b0 / 100) << 1;
|
||||||
|
const uint32_t d2 = (b0 % 100) << 1;
|
||||||
|
|
||||||
|
const uint32_t d3 = (c0 / 100) << 1;
|
||||||
|
const uint32_t d4 = (c0 % 100) << 1;
|
||||||
|
|
||||||
|
const uint32_t b1 = v1 / 10000;
|
||||||
|
const uint32_t c1 = v1 % 10000;
|
||||||
|
|
||||||
|
const uint32_t d5 = (b1 / 100) << 1;
|
||||||
|
const uint32_t d6 = (b1 % 100) << 1;
|
||||||
|
|
||||||
|
const uint32_t d7 = (c1 / 100) << 1;
|
||||||
|
const uint32_t d8 = (c1 % 100) << 1;
|
||||||
|
|
||||||
|
*buffer++ = cDigitsLut[d1];
|
||||||
|
*buffer++ = cDigitsLut[d1 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d2];
|
||||||
|
*buffer++ = cDigitsLut[d2 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d3];
|
||||||
|
*buffer++ = cDigitsLut[d3 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d4];
|
||||||
|
*buffer++ = cDigitsLut[d4 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d5];
|
||||||
|
*buffer++ = cDigitsLut[d5 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d6];
|
||||||
|
*buffer++ = cDigitsLut[d6 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d7];
|
||||||
|
*buffer++ = cDigitsLut[d7 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d8];
|
||||||
|
*buffer++ = cDigitsLut[d8 + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char* i64toa(int64_t value, char* buffer) {
|
||||||
|
uint64_t u = static_cast<uint64_t>(value);
|
||||||
|
if (value < 0) {
|
||||||
|
*buffer++ = '-';
|
||||||
|
u = ~u + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return u64toa(u, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_ITOA_
|
||||||
181
libs/discordrpc/rapidjson/internal/meta.h
Normal file
181
libs/discordrpc/rapidjson/internal/meta.h
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_INTERNAL_META_H_
|
||||||
|
#define RAPIDJSON_INTERNAL_META_H_
|
||||||
|
|
||||||
|
#include "../rapidjson.h"
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(effc++)
|
||||||
|
#endif
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(6334)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||||
|
#include <type_traits>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//@cond RAPIDJSON_INTERNAL
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching
|
||||||
|
template <typename T> struct Void { typedef void Type; };
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// BoolType, TrueType, FalseType
|
||||||
|
//
|
||||||
|
template <bool Cond> struct BoolType {
|
||||||
|
static const bool Value = Cond;
|
||||||
|
typedef BoolType Type;
|
||||||
|
};
|
||||||
|
typedef BoolType<true> TrueType;
|
||||||
|
typedef BoolType<false> FalseType;
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr
|
||||||
|
//
|
||||||
|
|
||||||
|
template <bool C> struct SelectIfImpl { template <typename T1, typename T2> struct Apply { typedef T1 Type; }; };
|
||||||
|
template <> struct SelectIfImpl<false> { template <typename T1, typename T2> struct Apply { typedef T2 Type; }; };
|
||||||
|
template <bool C, typename T1, typename T2> struct SelectIfCond : SelectIfImpl<C>::template Apply<T1,T2> {};
|
||||||
|
template <typename C, typename T1, typename T2> struct SelectIf : SelectIfCond<C::Value, T1, T2> {};
|
||||||
|
|
||||||
|
template <bool Cond1, bool Cond2> struct AndExprCond : FalseType {};
|
||||||
|
template <> struct AndExprCond<true, true> : TrueType {};
|
||||||
|
template <bool Cond1, bool Cond2> struct OrExprCond : TrueType {};
|
||||||
|
template <> struct OrExprCond<false, false> : FalseType {};
|
||||||
|
|
||||||
|
template <typename C> struct BoolExpr : SelectIf<C,TrueType,FalseType>::Type {};
|
||||||
|
template <typename C> struct NotExpr : SelectIf<C,FalseType,TrueType>::Type {};
|
||||||
|
template <typename C1, typename C2> struct AndExpr : AndExprCond<C1::Value, C2::Value>::Type {};
|
||||||
|
template <typename C1, typename C2> struct OrExpr : OrExprCond<C1::Value, C2::Value>::Type {};
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// AddConst, MaybeAddConst, RemoveConst
|
||||||
|
template <typename T> struct AddConst { typedef const T Type; };
|
||||||
|
template <bool Constify, typename T> struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};
|
||||||
|
template <typename T> struct RemoveConst { typedef T Type; };
|
||||||
|
template <typename T> struct RemoveConst<const T> { typedef T Type; };
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// IsSame, IsConst, IsMoreConst, IsPointer
|
||||||
|
//
|
||||||
|
template <typename T, typename U> struct IsSame : FalseType {};
|
||||||
|
template <typename T> struct IsSame<T, T> : TrueType {};
|
||||||
|
|
||||||
|
template <typename T> struct IsConst : FalseType {};
|
||||||
|
template <typename T> struct IsConst<const T> : TrueType {};
|
||||||
|
|
||||||
|
template <typename CT, typename T>
|
||||||
|
struct IsMoreConst
|
||||||
|
: AndExpr<IsSame<typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>,
|
||||||
|
BoolType<IsConst<CT>::Value >= IsConst<T>::Value> >::Type {};
|
||||||
|
|
||||||
|
template <typename T> struct IsPointer : FalseType {};
|
||||||
|
template <typename T> struct IsPointer<T*> : TrueType {};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// IsBaseOf
|
||||||
|
//
|
||||||
|
#if RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||||
|
|
||||||
|
template <typename B, typename D> struct IsBaseOf
|
||||||
|
: BoolType< ::std::is_base_of<B,D>::value> {};
|
||||||
|
|
||||||
|
#else // simplified version adopted from Boost
|
||||||
|
|
||||||
|
template<typename B, typename D> struct IsBaseOfImpl {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0);
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0);
|
||||||
|
|
||||||
|
typedef char (&Yes)[1];
|
||||||
|
typedef char (&No) [2];
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static Yes Check(const D*, T);
|
||||||
|
static No Check(const B*, int);
|
||||||
|
|
||||||
|
struct Host {
|
||||||
|
operator const B*() const;
|
||||||
|
operator const D*();
|
||||||
|
};
|
||||||
|
|
||||||
|
enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) };
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename B, typename D> struct IsBaseOf
|
||||||
|
: OrExpr<IsSame<B, D>, BoolExpr<IsBaseOfImpl<B, D> > >::Type {};
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// EnableIf / DisableIf
|
||||||
|
//
|
||||||
|
template <bool Condition, typename T = void> struct EnableIfCond { typedef T Type; };
|
||||||
|
template <typename T> struct EnableIfCond<false, T> { /* empty */ };
|
||||||
|
|
||||||
|
template <bool Condition, typename T = void> struct DisableIfCond { typedef T Type; };
|
||||||
|
template <typename T> struct DisableIfCond<true, T> { /* empty */ };
|
||||||
|
|
||||||
|
template <typename Condition, typename T = void>
|
||||||
|
struct EnableIf : EnableIfCond<Condition::Value, T> {};
|
||||||
|
|
||||||
|
template <typename Condition, typename T = void>
|
||||||
|
struct DisableIf : DisableIfCond<Condition::Value, T> {};
|
||||||
|
|
||||||
|
// SFINAE helpers
|
||||||
|
struct SfinaeTag {};
|
||||||
|
template <typename T> struct RemoveSfinaeTag;
|
||||||
|
template <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type; };
|
||||||
|
|
||||||
|
#define RAPIDJSON_REMOVEFPTR_(type) \
|
||||||
|
typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \
|
||||||
|
< ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type
|
||||||
|
|
||||||
|
#define RAPIDJSON_ENABLEIF(cond) \
|
||||||
|
typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
|
||||||
|
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
|
||||||
|
|
||||||
|
#define RAPIDJSON_DISABLEIF(cond) \
|
||||||
|
typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
|
||||||
|
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
|
||||||
|
|
||||||
|
#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \
|
||||||
|
typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
|
||||||
|
<RAPIDJSON_REMOVEFPTR_(cond), \
|
||||||
|
RAPIDJSON_REMOVEFPTR_(returntype)>::Type
|
||||||
|
|
||||||
|
#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \
|
||||||
|
typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
|
||||||
|
<RAPIDJSON_REMOVEFPTR_(cond), \
|
||||||
|
RAPIDJSON_REMOVEFPTR_(returntype)>::Type
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
//@endcond
|
||||||
|
|
||||||
|
#if defined(__GNUC__) || defined(_MSC_VER)
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_INTERNAL_META_H_
|
||||||
55
libs/discordrpc/rapidjson/internal/pow10.h
Normal file
55
libs/discordrpc/rapidjson/internal/pow10.h
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_POW10_
|
||||||
|
#define RAPIDJSON_POW10_
|
||||||
|
|
||||||
|
#include "../rapidjson.h"
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
//! Computes integer powers of 10 in double (10.0^n).
|
||||||
|
/*! This function uses lookup table for fast and accurate results.
|
||||||
|
\param n non-negative exponent. Must <= 308.
|
||||||
|
\return 10.0^n
|
||||||
|
*/
|
||||||
|
inline double Pow10(int n) {
|
||||||
|
static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes
|
||||||
|
1e+0,
|
||||||
|
1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20,
|
||||||
|
1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40,
|
||||||
|
1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60,
|
||||||
|
1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80,
|
||||||
|
1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100,
|
||||||
|
1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120,
|
||||||
|
1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140,
|
||||||
|
1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160,
|
||||||
|
1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180,
|
||||||
|
1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200,
|
||||||
|
1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220,
|
||||||
|
1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240,
|
||||||
|
1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260,
|
||||||
|
1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280,
|
||||||
|
1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300,
|
||||||
|
1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308
|
||||||
|
};
|
||||||
|
RAPIDJSON_ASSERT(n >= 0 && n <= 308);
|
||||||
|
return e[n];
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_POW10_
|
||||||
701
libs/discordrpc/rapidjson/internal/regex.h
Normal file
701
libs/discordrpc/rapidjson/internal/regex.h
Normal file
@@ -0,0 +1,701 @@
|
|||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_INTERNAL_REGEX_H_
|
||||||
|
#define RAPIDJSON_INTERNAL_REGEX_H_
|
||||||
|
|
||||||
|
#include "../allocators.h"
|
||||||
|
#include "../stream.h"
|
||||||
|
#include "stack.h"
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(padded)
|
||||||
|
RAPIDJSON_DIAG_OFF(switch-enum)
|
||||||
|
RAPIDJSON_DIAG_OFF(implicit-fallthrough)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(effc++)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_REGEX_VERBOSE
|
||||||
|
#define RAPIDJSON_REGEX_VERBOSE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// GenericRegex
|
||||||
|
|
||||||
|
static const SizeType kRegexInvalidState = ~SizeType(0); //!< Represents an invalid index in GenericRegex::State::out, out1
|
||||||
|
static const SizeType kRegexInvalidRange = ~SizeType(0);
|
||||||
|
|
||||||
|
//! Regular expression engine with subset of ECMAscript grammar.
|
||||||
|
/*!
|
||||||
|
Supported regular expression syntax:
|
||||||
|
- \c ab Concatenation
|
||||||
|
- \c a|b Alternation
|
||||||
|
- \c a? Zero or one
|
||||||
|
- \c a* Zero or more
|
||||||
|
- \c a+ One or more
|
||||||
|
- \c a{3} Exactly 3 times
|
||||||
|
- \c a{3,} At least 3 times
|
||||||
|
- \c a{3,5} 3 to 5 times
|
||||||
|
- \c (ab) Grouping
|
||||||
|
- \c ^a At the beginning
|
||||||
|
- \c a$ At the end
|
||||||
|
- \c . Any character
|
||||||
|
- \c [abc] Character classes
|
||||||
|
- \c [a-c] Character class range
|
||||||
|
- \c [a-z0-9_] Character class combination
|
||||||
|
- \c [^abc] Negated character classes
|
||||||
|
- \c [^a-c] Negated character class range
|
||||||
|
- \c [\b] Backspace (U+0008)
|
||||||
|
- \c \\| \\\\ ... Escape characters
|
||||||
|
- \c \\f Form feed (U+000C)
|
||||||
|
- \c \\n Line feed (U+000A)
|
||||||
|
- \c \\r Carriage return (U+000D)
|
||||||
|
- \c \\t Tab (U+0009)
|
||||||
|
- \c \\v Vertical tab (U+000B)
|
||||||
|
|
||||||
|
\note This is a Thompson NFA engine, implemented with reference to
|
||||||
|
Cox, Russ. "Regular Expression Matching Can Be Simple And Fast (but is slow in Java, Perl, PHP, Python, Ruby,...).",
|
||||||
|
https://swtch.com/~rsc/regexp/regexp1.html
|
||||||
|
*/
|
||||||
|
template <typename Encoding, typename Allocator = CrtAllocator>
|
||||||
|
class GenericRegex {
|
||||||
|
public:
|
||||||
|
typedef typename Encoding::Ch Ch;
|
||||||
|
|
||||||
|
GenericRegex(const Ch* source, Allocator* allocator = 0) :
|
||||||
|
states_(allocator, 256), ranges_(allocator, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(),
|
||||||
|
stateSet_(), state0_(allocator, 0), state1_(allocator, 0), anchorBegin_(), anchorEnd_()
|
||||||
|
{
|
||||||
|
GenericStringStream<Encoding> ss(source);
|
||||||
|
DecodedStream<GenericStringStream<Encoding> > ds(ss);
|
||||||
|
Parse(ds);
|
||||||
|
}
|
||||||
|
|
||||||
|
~GenericRegex() {
|
||||||
|
Allocator::Free(stateSet_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsValid() const {
|
||||||
|
return root_ != kRegexInvalidState;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream>
|
||||||
|
bool Match(InputStream& is) const {
|
||||||
|
return SearchWithAnchoring(is, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Match(const Ch* s) const {
|
||||||
|
GenericStringStream<Encoding> is(s);
|
||||||
|
return Match(is);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream>
|
||||||
|
bool Search(InputStream& is) const {
|
||||||
|
return SearchWithAnchoring(is, anchorBegin_, anchorEnd_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Search(const Ch* s) const {
|
||||||
|
GenericStringStream<Encoding> is(s);
|
||||||
|
return Search(is);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum Operator {
|
||||||
|
kZeroOrOne,
|
||||||
|
kZeroOrMore,
|
||||||
|
kOneOrMore,
|
||||||
|
kConcatenation,
|
||||||
|
kAlternation,
|
||||||
|
kLeftParenthesis
|
||||||
|
};
|
||||||
|
|
||||||
|
static const unsigned kAnyCharacterClass = 0xFFFFFFFF; //!< For '.'
|
||||||
|
static const unsigned kRangeCharacterClass = 0xFFFFFFFE;
|
||||||
|
static const unsigned kRangeNegationFlag = 0x80000000;
|
||||||
|
|
||||||
|
struct Range {
|
||||||
|
unsigned start; //
|
||||||
|
unsigned end;
|
||||||
|
SizeType next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct State {
|
||||||
|
SizeType out; //!< Equals to kInvalid for matching state
|
||||||
|
SizeType out1; //!< Equals to non-kInvalid for split
|
||||||
|
SizeType rangeStart;
|
||||||
|
unsigned codepoint;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Frag {
|
||||||
|
Frag(SizeType s, SizeType o, SizeType m) : start(s), out(o), minIndex(m) {}
|
||||||
|
SizeType start;
|
||||||
|
SizeType out; //!< link-list of all output states
|
||||||
|
SizeType minIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename SourceStream>
|
||||||
|
class DecodedStream {
|
||||||
|
public:
|
||||||
|
DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); }
|
||||||
|
unsigned Peek() { return codepoint_; }
|
||||||
|
unsigned Take() {
|
||||||
|
unsigned c = codepoint_;
|
||||||
|
if (c) // No further decoding when '\0'
|
||||||
|
Decode();
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Decode() {
|
||||||
|
if (!Encoding::Decode(ss_, &codepoint_))
|
||||||
|
codepoint_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SourceStream& ss_;
|
||||||
|
unsigned codepoint_;
|
||||||
|
};
|
||||||
|
|
||||||
|
State& GetState(SizeType index) {
|
||||||
|
RAPIDJSON_ASSERT(index < stateCount_);
|
||||||
|
return states_.template Bottom<State>()[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
const State& GetState(SizeType index) const {
|
||||||
|
RAPIDJSON_ASSERT(index < stateCount_);
|
||||||
|
return states_.template Bottom<State>()[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
Range& GetRange(SizeType index) {
|
||||||
|
RAPIDJSON_ASSERT(index < rangeCount_);
|
||||||
|
return ranges_.template Bottom<Range>()[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
const Range& GetRange(SizeType index) const {
|
||||||
|
RAPIDJSON_ASSERT(index < rangeCount_);
|
||||||
|
return ranges_.template Bottom<Range>()[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream>
|
||||||
|
void Parse(DecodedStream<InputStream>& ds) {
|
||||||
|
Allocator allocator;
|
||||||
|
Stack<Allocator> operandStack(&allocator, 256); // Frag
|
||||||
|
Stack<Allocator> operatorStack(&allocator, 256); // Operator
|
||||||
|
Stack<Allocator> atomCountStack(&allocator, 256); // unsigned (Atom per parenthesis)
|
||||||
|
|
||||||
|
*atomCountStack.template Push<unsigned>() = 0;
|
||||||
|
|
||||||
|
unsigned codepoint;
|
||||||
|
while (ds.Peek() != 0) {
|
||||||
|
switch (codepoint = ds.Take()) {
|
||||||
|
case '^':
|
||||||
|
anchorBegin_ = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '$':
|
||||||
|
anchorEnd_ = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '|':
|
||||||
|
while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() < kAlternation)
|
||||||
|
if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
|
||||||
|
return;
|
||||||
|
*operatorStack.template Push<Operator>() = kAlternation;
|
||||||
|
*atomCountStack.template Top<unsigned>() = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '(':
|
||||||
|
*operatorStack.template Push<Operator>() = kLeftParenthesis;
|
||||||
|
*atomCountStack.template Push<unsigned>() = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ')':
|
||||||
|
while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() != kLeftParenthesis)
|
||||||
|
if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
|
||||||
|
return;
|
||||||
|
if (operatorStack.Empty())
|
||||||
|
return;
|
||||||
|
operatorStack.template Pop<Operator>(1);
|
||||||
|
atomCountStack.template Pop<unsigned>(1);
|
||||||
|
ImplicitConcatenation(atomCountStack, operatorStack);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '?':
|
||||||
|
if (!Eval(operandStack, kZeroOrOne))
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '*':
|
||||||
|
if (!Eval(operandStack, kZeroOrMore))
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '+':
|
||||||
|
if (!Eval(operandStack, kOneOrMore))
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '{':
|
||||||
|
{
|
||||||
|
unsigned n, m;
|
||||||
|
if (!ParseUnsigned(ds, &n))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ds.Peek() == ',') {
|
||||||
|
ds.Take();
|
||||||
|
if (ds.Peek() == '}')
|
||||||
|
m = kInfinityQuantifier;
|
||||||
|
else if (!ParseUnsigned(ds, &m) || m < n)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m = n;
|
||||||
|
|
||||||
|
if (!EvalQuantifier(operandStack, n, m) || ds.Peek() != '}')
|
||||||
|
return;
|
||||||
|
ds.Take();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '.':
|
||||||
|
PushOperand(operandStack, kAnyCharacterClass);
|
||||||
|
ImplicitConcatenation(atomCountStack, operatorStack);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '[':
|
||||||
|
{
|
||||||
|
SizeType range;
|
||||||
|
if (!ParseRange(ds, &range))
|
||||||
|
return;
|
||||||
|
SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, kRangeCharacterClass);
|
||||||
|
GetState(s).rangeStart = range;
|
||||||
|
*operandStack.template Push<Frag>() = Frag(s, s, s);
|
||||||
|
}
|
||||||
|
ImplicitConcatenation(atomCountStack, operatorStack);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\\': // Escape character
|
||||||
|
if (!CharacterEscape(ds, &codepoint))
|
||||||
|
return; // Unsupported escape character
|
||||||
|
// fall through to default
|
||||||
|
|
||||||
|
default: // Pattern character
|
||||||
|
PushOperand(operandStack, codepoint);
|
||||||
|
ImplicitConcatenation(atomCountStack, operatorStack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!operatorStack.Empty())
|
||||||
|
if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Link the operand to matching state.
|
||||||
|
if (operandStack.GetSize() == sizeof(Frag)) {
|
||||||
|
Frag* e = operandStack.template Pop<Frag>(1);
|
||||||
|
Patch(e->out, NewState(kRegexInvalidState, kRegexInvalidState, 0));
|
||||||
|
root_ = e->start;
|
||||||
|
|
||||||
|
#if RAPIDJSON_REGEX_VERBOSE
|
||||||
|
printf("root: %d\n", root_);
|
||||||
|
for (SizeType i = 0; i < stateCount_ ; i++) {
|
||||||
|
State& s = GetState(i);
|
||||||
|
printf("[%2d] out: %2d out1: %2d c: '%c'\n", i, s.out, s.out1, (char)s.codepoint);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preallocate buffer for SearchWithAnchoring()
|
||||||
|
RAPIDJSON_ASSERT(stateSet_ == 0);
|
||||||
|
if (stateCount_ > 0) {
|
||||||
|
stateSet_ = static_cast<unsigned*>(states_.GetAllocator().Malloc(GetStateSetSize()));
|
||||||
|
state0_.template Reserve<SizeType>(stateCount_);
|
||||||
|
state1_.template Reserve<SizeType>(stateCount_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) {
|
||||||
|
State* s = states_.template Push<State>();
|
||||||
|
s->out = out;
|
||||||
|
s->out1 = out1;
|
||||||
|
s->codepoint = codepoint;
|
||||||
|
s->rangeStart = kRegexInvalidRange;
|
||||||
|
return stateCount_++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PushOperand(Stack<Allocator>& operandStack, unsigned codepoint) {
|
||||||
|
SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, codepoint);
|
||||||
|
*operandStack.template Push<Frag>() = Frag(s, s, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImplicitConcatenation(Stack<Allocator>& atomCountStack, Stack<Allocator>& operatorStack) {
|
||||||
|
if (*atomCountStack.template Top<unsigned>())
|
||||||
|
*operatorStack.template Push<Operator>() = kConcatenation;
|
||||||
|
(*atomCountStack.template Top<unsigned>())++;
|
||||||
|
}
|
||||||
|
|
||||||
|
SizeType Append(SizeType l1, SizeType l2) {
|
||||||
|
SizeType old = l1;
|
||||||
|
while (GetState(l1).out != kRegexInvalidState)
|
||||||
|
l1 = GetState(l1).out;
|
||||||
|
GetState(l1).out = l2;
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Patch(SizeType l, SizeType s) {
|
||||||
|
for (SizeType next; l != kRegexInvalidState; l = next) {
|
||||||
|
next = GetState(l).out;
|
||||||
|
GetState(l).out = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Eval(Stack<Allocator>& operandStack, Operator op) {
|
||||||
|
switch (op) {
|
||||||
|
case kConcatenation:
|
||||||
|
RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag) * 2);
|
||||||
|
{
|
||||||
|
Frag e2 = *operandStack.template Pop<Frag>(1);
|
||||||
|
Frag e1 = *operandStack.template Pop<Frag>(1);
|
||||||
|
Patch(e1.out, e2.start);
|
||||||
|
*operandStack.template Push<Frag>() = Frag(e1.start, e2.out, Min(e1.minIndex, e2.minIndex));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case kAlternation:
|
||||||
|
if (operandStack.GetSize() >= sizeof(Frag) * 2) {
|
||||||
|
Frag e2 = *operandStack.template Pop<Frag>(1);
|
||||||
|
Frag e1 = *operandStack.template Pop<Frag>(1);
|
||||||
|
SizeType s = NewState(e1.start, e2.start, 0);
|
||||||
|
*operandStack.template Push<Frag>() = Frag(s, Append(e1.out, e2.out), Min(e1.minIndex, e2.minIndex));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case kZeroOrOne:
|
||||||
|
if (operandStack.GetSize() >= sizeof(Frag)) {
|
||||||
|
Frag e = *operandStack.template Pop<Frag>(1);
|
||||||
|
SizeType s = NewState(kRegexInvalidState, e.start, 0);
|
||||||
|
*operandStack.template Push<Frag>() = Frag(s, Append(e.out, s), e.minIndex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case kZeroOrMore:
|
||||||
|
if (operandStack.GetSize() >= sizeof(Frag)) {
|
||||||
|
Frag e = *operandStack.template Pop<Frag>(1);
|
||||||
|
SizeType s = NewState(kRegexInvalidState, e.start, 0);
|
||||||
|
Patch(e.out, s);
|
||||||
|
*operandStack.template Push<Frag>() = Frag(s, s, e.minIndex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
|
||||||
|
default:
|
||||||
|
RAPIDJSON_ASSERT(op == kOneOrMore);
|
||||||
|
if (operandStack.GetSize() >= sizeof(Frag)) {
|
||||||
|
Frag e = *operandStack.template Pop<Frag>(1);
|
||||||
|
SizeType s = NewState(kRegexInvalidState, e.start, 0);
|
||||||
|
Patch(e.out, s);
|
||||||
|
*operandStack.template Push<Frag>() = Frag(e.start, s, e.minIndex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EvalQuantifier(Stack<Allocator>& operandStack, unsigned n, unsigned m) {
|
||||||
|
RAPIDJSON_ASSERT(n <= m);
|
||||||
|
RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag));
|
||||||
|
|
||||||
|
if (n == 0) {
|
||||||
|
if (m == 0) // a{0} not support
|
||||||
|
return false;
|
||||||
|
else if (m == kInfinityQuantifier)
|
||||||
|
Eval(operandStack, kZeroOrMore); // a{0,} -> a*
|
||||||
|
else {
|
||||||
|
Eval(operandStack, kZeroOrOne); // a{0,5} -> a?
|
||||||
|
for (unsigned i = 0; i < m - 1; i++)
|
||||||
|
CloneTopOperand(operandStack); // a{0,5} -> a? a? a? a? a?
|
||||||
|
for (unsigned i = 0; i < m - 1; i++)
|
||||||
|
Eval(operandStack, kConcatenation); // a{0,5} -> a?a?a?a?a?
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < n - 1; i++) // a{3} -> a a a
|
||||||
|
CloneTopOperand(operandStack);
|
||||||
|
|
||||||
|
if (m == kInfinityQuantifier)
|
||||||
|
Eval(operandStack, kOneOrMore); // a{3,} -> a a a+
|
||||||
|
else if (m > n) {
|
||||||
|
CloneTopOperand(operandStack); // a{3,5} -> a a a a
|
||||||
|
Eval(operandStack, kZeroOrOne); // a{3,5} -> a a a a?
|
||||||
|
for (unsigned i = n; i < m - 1; i++)
|
||||||
|
CloneTopOperand(operandStack); // a{3,5} -> a a a a? a?
|
||||||
|
for (unsigned i = n; i < m; i++)
|
||||||
|
Eval(operandStack, kConcatenation); // a{3,5} -> a a aa?a?
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < n - 1; i++)
|
||||||
|
Eval(operandStack, kConcatenation); // a{3} -> aaa, a{3,} -> aaa+, a{3.5} -> aaaa?a?
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SizeType Min(SizeType a, SizeType b) { return a < b ? a : b; }
|
||||||
|
|
||||||
|
void CloneTopOperand(Stack<Allocator>& operandStack) {
|
||||||
|
const Frag src = *operandStack.template Top<Frag>(); // Copy constructor to prevent invalidation
|
||||||
|
SizeType count = stateCount_ - src.minIndex; // Assumes top operand contains states in [src->minIndex, stateCount_)
|
||||||
|
State* s = states_.template Push<State>(count);
|
||||||
|
memcpy(s, &GetState(src.minIndex), count * sizeof(State));
|
||||||
|
for (SizeType j = 0; j < count; j++) {
|
||||||
|
if (s[j].out != kRegexInvalidState)
|
||||||
|
s[j].out += count;
|
||||||
|
if (s[j].out1 != kRegexInvalidState)
|
||||||
|
s[j].out1 += count;
|
||||||
|
}
|
||||||
|
*operandStack.template Push<Frag>() = Frag(src.start + count, src.out + count, src.minIndex + count);
|
||||||
|
stateCount_ += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream>
|
||||||
|
bool ParseUnsigned(DecodedStream<InputStream>& ds, unsigned* u) {
|
||||||
|
unsigned r = 0;
|
||||||
|
if (ds.Peek() < '0' || ds.Peek() > '9')
|
||||||
|
return false;
|
||||||
|
while (ds.Peek() >= '0' && ds.Peek() <= '9') {
|
||||||
|
if (r >= 429496729 && ds.Peek() > '5') // 2^32 - 1 = 4294967295
|
||||||
|
return false; // overflow
|
||||||
|
r = r * 10 + (ds.Take() - '0');
|
||||||
|
}
|
||||||
|
*u = r;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream>
|
||||||
|
bool ParseRange(DecodedStream<InputStream>& ds, SizeType* range) {
|
||||||
|
bool isBegin = true;
|
||||||
|
bool negate = false;
|
||||||
|
int step = 0;
|
||||||
|
SizeType start = kRegexInvalidRange;
|
||||||
|
SizeType current = kRegexInvalidRange;
|
||||||
|
unsigned codepoint;
|
||||||
|
while ((codepoint = ds.Take()) != 0) {
|
||||||
|
if (isBegin) {
|
||||||
|
isBegin = false;
|
||||||
|
if (codepoint == '^') {
|
||||||
|
negate = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (codepoint) {
|
||||||
|
case ']':
|
||||||
|
if (start == kRegexInvalidRange)
|
||||||
|
return false; // Error: nothing inside []
|
||||||
|
if (step == 2) { // Add trailing '-'
|
||||||
|
SizeType r = NewRange('-');
|
||||||
|
RAPIDJSON_ASSERT(current != kRegexInvalidRange);
|
||||||
|
GetRange(current).next = r;
|
||||||
|
}
|
||||||
|
if (negate)
|
||||||
|
GetRange(start).start |= kRangeNegationFlag;
|
||||||
|
*range = start;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case '\\':
|
||||||
|
if (ds.Peek() == 'b') {
|
||||||
|
ds.Take();
|
||||||
|
codepoint = 0x0008; // Escape backspace character
|
||||||
|
}
|
||||||
|
else if (!CharacterEscape(ds, &codepoint))
|
||||||
|
return false;
|
||||||
|
// fall through to default
|
||||||
|
|
||||||
|
default:
|
||||||
|
switch (step) {
|
||||||
|
case 1:
|
||||||
|
if (codepoint == '-') {
|
||||||
|
step++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// fall through to step 0 for other characters
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
SizeType r = NewRange(codepoint);
|
||||||
|
if (current != kRegexInvalidRange)
|
||||||
|
GetRange(current).next = r;
|
||||||
|
if (start == kRegexInvalidRange)
|
||||||
|
start = r;
|
||||||
|
current = r;
|
||||||
|
}
|
||||||
|
step = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
RAPIDJSON_ASSERT(step == 2);
|
||||||
|
GetRange(current).end = codepoint;
|
||||||
|
step = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SizeType NewRange(unsigned codepoint) {
|
||||||
|
Range* r = ranges_.template Push<Range>();
|
||||||
|
r->start = r->end = codepoint;
|
||||||
|
r->next = kRegexInvalidRange;
|
||||||
|
return rangeCount_++;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream>
|
||||||
|
bool CharacterEscape(DecodedStream<InputStream>& ds, unsigned* escapedCodepoint) {
|
||||||
|
unsigned codepoint;
|
||||||
|
switch (codepoint = ds.Take()) {
|
||||||
|
case '^':
|
||||||
|
case '$':
|
||||||
|
case '|':
|
||||||
|
case '(':
|
||||||
|
case ')':
|
||||||
|
case '?':
|
||||||
|
case '*':
|
||||||
|
case '+':
|
||||||
|
case '.':
|
||||||
|
case '[':
|
||||||
|
case ']':
|
||||||
|
case '{':
|
||||||
|
case '}':
|
||||||
|
case '\\':
|
||||||
|
*escapedCodepoint = codepoint; return true;
|
||||||
|
case 'f': *escapedCodepoint = 0x000C; return true;
|
||||||
|
case 'n': *escapedCodepoint = 0x000A; return true;
|
||||||
|
case 'r': *escapedCodepoint = 0x000D; return true;
|
||||||
|
case 't': *escapedCodepoint = 0x0009; return true;
|
||||||
|
case 'v': *escapedCodepoint = 0x000B; return true;
|
||||||
|
default:
|
||||||
|
return false; // Unsupported escape character
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream>
|
||||||
|
bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) const {
|
||||||
|
RAPIDJSON_ASSERT(IsValid());
|
||||||
|
DecodedStream<InputStream> ds(is);
|
||||||
|
|
||||||
|
state0_.Clear();
|
||||||
|
Stack<Allocator> *current = &state0_, *next = &state1_;
|
||||||
|
const size_t stateSetSize = GetStateSetSize();
|
||||||
|
std::memset(stateSet_, 0, stateSetSize);
|
||||||
|
|
||||||
|
bool matched = AddState(*current, root_);
|
||||||
|
unsigned codepoint;
|
||||||
|
while (!current->Empty() && (codepoint = ds.Take()) != 0) {
|
||||||
|
std::memset(stateSet_, 0, stateSetSize);
|
||||||
|
next->Clear();
|
||||||
|
matched = false;
|
||||||
|
for (const SizeType* s = current->template Bottom<SizeType>(); s != current->template End<SizeType>(); ++s) {
|
||||||
|
const State& sr = GetState(*s);
|
||||||
|
if (sr.codepoint == codepoint ||
|
||||||
|
sr.codepoint == kAnyCharacterClass ||
|
||||||
|
(sr.codepoint == kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint)))
|
||||||
|
{
|
||||||
|
matched = AddState(*next, sr.out) || matched;
|
||||||
|
if (!anchorEnd && matched)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!anchorBegin)
|
||||||
|
AddState(*next, root_);
|
||||||
|
}
|
||||||
|
internal::Swap(current, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
return matched;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t GetStateSetSize() const {
|
||||||
|
return (stateCount_ + 31) / 32 * 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return whether the added states is a match state
|
||||||
|
bool AddState(Stack<Allocator>& l, SizeType index) const {
|
||||||
|
RAPIDJSON_ASSERT(index != kRegexInvalidState);
|
||||||
|
|
||||||
|
const State& s = GetState(index);
|
||||||
|
if (s.out1 != kRegexInvalidState) { // Split
|
||||||
|
bool matched = AddState(l, s.out);
|
||||||
|
return AddState(l, s.out1) || matched;
|
||||||
|
}
|
||||||
|
else if (!(stateSet_[index >> 5] & (1 << (index & 31)))) {
|
||||||
|
stateSet_[index >> 5] |= (1 << (index & 31));
|
||||||
|
*l.template PushUnsafe<SizeType>() = index;
|
||||||
|
}
|
||||||
|
return s.out == kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not validated due to reallocation.
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MatchRange(SizeType rangeIndex, unsigned codepoint) const {
|
||||||
|
bool yes = (GetRange(rangeIndex).start & kRangeNegationFlag) == 0;
|
||||||
|
while (rangeIndex != kRegexInvalidRange) {
|
||||||
|
const Range& r = GetRange(rangeIndex);
|
||||||
|
if (codepoint >= (r.start & ~kRangeNegationFlag) && codepoint <= r.end)
|
||||||
|
return yes;
|
||||||
|
rangeIndex = r.next;
|
||||||
|
}
|
||||||
|
return !yes;
|
||||||
|
}
|
||||||
|
|
||||||
|
Stack<Allocator> states_;
|
||||||
|
Stack<Allocator> ranges_;
|
||||||
|
SizeType root_;
|
||||||
|
SizeType stateCount_;
|
||||||
|
SizeType rangeCount_;
|
||||||
|
|
||||||
|
static const unsigned kInfinityQuantifier = ~0u;
|
||||||
|
|
||||||
|
// For SearchWithAnchoring()
|
||||||
|
uint32_t* stateSet_; // allocated by states_.GetAllocator()
|
||||||
|
mutable Stack<Allocator> state0_;
|
||||||
|
mutable Stack<Allocator> state1_;
|
||||||
|
bool anchorBegin_;
|
||||||
|
bool anchorEnd_;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef GenericRegex<UTF8<> > Regex;
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_INTERNAL_REGEX_H_
|
||||||
230
libs/discordrpc/rapidjson/internal/stack.h
Normal file
230
libs/discordrpc/rapidjson/internal/stack.h
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_INTERNAL_STACK_H_
|
||||||
|
#define RAPIDJSON_INTERNAL_STACK_H_
|
||||||
|
|
||||||
|
#include "../allocators.h"
|
||||||
|
#include "swap.h"
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Stack
|
||||||
|
|
||||||
|
//! A type-unsafe stack for storing different types of data.
|
||||||
|
/*! \tparam Allocator Allocator for allocating stack memory.
|
||||||
|
*/
|
||||||
|
template <typename Allocator>
|
||||||
|
class Stack {
|
||||||
|
public:
|
||||||
|
// Optimization note: Do not allocate memory for stack_ in constructor.
|
||||||
|
// Do it lazily when first Push() -> Expand() -> Resize().
|
||||||
|
Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) {
|
||||||
|
}
|
||||||
|
|
||||||
|
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
|
Stack(Stack&& rhs)
|
||||||
|
: allocator_(rhs.allocator_),
|
||||||
|
ownAllocator_(rhs.ownAllocator_),
|
||||||
|
stack_(rhs.stack_),
|
||||||
|
stackTop_(rhs.stackTop_),
|
||||||
|
stackEnd_(rhs.stackEnd_),
|
||||||
|
initialCapacity_(rhs.initialCapacity_)
|
||||||
|
{
|
||||||
|
rhs.allocator_ = 0;
|
||||||
|
rhs.ownAllocator_ = 0;
|
||||||
|
rhs.stack_ = 0;
|
||||||
|
rhs.stackTop_ = 0;
|
||||||
|
rhs.stackEnd_ = 0;
|
||||||
|
rhs.initialCapacity_ = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
~Stack() {
|
||||||
|
Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
|
Stack& operator=(Stack&& rhs) {
|
||||||
|
if (&rhs != this)
|
||||||
|
{
|
||||||
|
Destroy();
|
||||||
|
|
||||||
|
allocator_ = rhs.allocator_;
|
||||||
|
ownAllocator_ = rhs.ownAllocator_;
|
||||||
|
stack_ = rhs.stack_;
|
||||||
|
stackTop_ = rhs.stackTop_;
|
||||||
|
stackEnd_ = rhs.stackEnd_;
|
||||||
|
initialCapacity_ = rhs.initialCapacity_;
|
||||||
|
|
||||||
|
rhs.allocator_ = 0;
|
||||||
|
rhs.ownAllocator_ = 0;
|
||||||
|
rhs.stack_ = 0;
|
||||||
|
rhs.stackTop_ = 0;
|
||||||
|
rhs.stackEnd_ = 0;
|
||||||
|
rhs.initialCapacity_ = 0;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT {
|
||||||
|
internal::Swap(allocator_, rhs.allocator_);
|
||||||
|
internal::Swap(ownAllocator_, rhs.ownAllocator_);
|
||||||
|
internal::Swap(stack_, rhs.stack_);
|
||||||
|
internal::Swap(stackTop_, rhs.stackTop_);
|
||||||
|
internal::Swap(stackEnd_, rhs.stackEnd_);
|
||||||
|
internal::Swap(initialCapacity_, rhs.initialCapacity_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clear() { stackTop_ = stack_; }
|
||||||
|
|
||||||
|
void ShrinkToFit() {
|
||||||
|
if (Empty()) {
|
||||||
|
// If the stack is empty, completely deallocate the memory.
|
||||||
|
Allocator::Free(stack_);
|
||||||
|
stack_ = 0;
|
||||||
|
stackTop_ = 0;
|
||||||
|
stackEnd_ = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Resize(GetSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optimization note: try to minimize the size of this function for force inline.
|
||||||
|
// Expansion is run very infrequently, so it is moved to another (probably non-inline) function.
|
||||||
|
template<typename T>
|
||||||
|
RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) {
|
||||||
|
// Expand the stack if needed
|
||||||
|
if (RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count > stackEnd_))
|
||||||
|
Expand<T>(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
|
||||||
|
Reserve<T>(count);
|
||||||
|
return PushUnsafe<T>(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) {
|
||||||
|
RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count <= stackEnd_);
|
||||||
|
T* ret = reinterpret_cast<T*>(stackTop_);
|
||||||
|
stackTop_ += sizeof(T) * count;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T* Pop(size_t count) {
|
||||||
|
RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
|
||||||
|
stackTop_ -= count * sizeof(T);
|
||||||
|
return reinterpret_cast<T*>(stackTop_);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T* Top() {
|
||||||
|
RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
|
||||||
|
return reinterpret_cast<T*>(stackTop_ - sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
const T* Top() const {
|
||||||
|
RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
|
||||||
|
return reinterpret_cast<T*>(stackTop_ - sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T* End() { return reinterpret_cast<T*>(stackTop_); }
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
const T* End() const { return reinterpret_cast<T*>(stackTop_); }
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T* Bottom() { return reinterpret_cast<T*>(stack_); }
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
const T* Bottom() const { return reinterpret_cast<T*>(stack_); }
|
||||||
|
|
||||||
|
bool HasAllocator() const {
|
||||||
|
return allocator_ != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Allocator& GetAllocator() {
|
||||||
|
RAPIDJSON_ASSERT(allocator_);
|
||||||
|
return *allocator_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Empty() const { return stackTop_ == stack_; }
|
||||||
|
size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
|
||||||
|
size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
template<typename T>
|
||||||
|
void Expand(size_t count) {
|
||||||
|
// Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.
|
||||||
|
size_t newCapacity;
|
||||||
|
if (stack_ == 0) {
|
||||||
|
if (!allocator_)
|
||||||
|
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
|
||||||
|
newCapacity = initialCapacity_;
|
||||||
|
} else {
|
||||||
|
newCapacity = GetCapacity();
|
||||||
|
newCapacity += (newCapacity + 1) / 2;
|
||||||
|
}
|
||||||
|
size_t newSize = GetSize() + sizeof(T) * count;
|
||||||
|
if (newCapacity < newSize)
|
||||||
|
newCapacity = newSize;
|
||||||
|
|
||||||
|
Resize(newCapacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Resize(size_t newCapacity) {
|
||||||
|
const size_t size = GetSize(); // Backup the current size
|
||||||
|
stack_ = static_cast<char*>(allocator_->Realloc(stack_, GetCapacity(), newCapacity));
|
||||||
|
stackTop_ = stack_ + size;
|
||||||
|
stackEnd_ = stack_ + newCapacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Destroy() {
|
||||||
|
Allocator::Free(stack_);
|
||||||
|
RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prohibit copy constructor & assignment operator.
|
||||||
|
Stack(const Stack&);
|
||||||
|
Stack& operator=(const Stack&);
|
||||||
|
|
||||||
|
Allocator* allocator_;
|
||||||
|
Allocator* ownAllocator_;
|
||||||
|
char *stack_;
|
||||||
|
char *stackTop_;
|
||||||
|
char *stackEnd_;
|
||||||
|
size_t initialCapacity_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_STACK_H_
|
||||||
55
libs/discordrpc/rapidjson/internal/strfunc.h
Normal file
55
libs/discordrpc/rapidjson/internal/strfunc.h
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_
|
||||||
|
#define RAPIDJSON_INTERNAL_STRFUNC_H_
|
||||||
|
|
||||||
|
#include "../stream.h"
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
//! Custom strlen() which works on different character types.
|
||||||
|
/*! \tparam Ch Character type (e.g. char, wchar_t, short)
|
||||||
|
\param s Null-terminated input string.
|
||||||
|
\return Number of characters in the string.
|
||||||
|
\note This has the same semantics as strlen(), the return value is not number of Unicode codepoints.
|
||||||
|
*/
|
||||||
|
template <typename Ch>
|
||||||
|
inline SizeType StrLen(const Ch* s) {
|
||||||
|
const Ch* p = s;
|
||||||
|
while (*p) ++p;
|
||||||
|
return SizeType(p - s);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Returns number of code points in a encoded string.
|
||||||
|
template<typename Encoding>
|
||||||
|
bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) {
|
||||||
|
GenericStringStream<Encoding> is(s);
|
||||||
|
const typename Encoding::Ch* end = s + length;
|
||||||
|
SizeType count = 0;
|
||||||
|
while (is.src_ < end) {
|
||||||
|
unsigned codepoint;
|
||||||
|
if (!Encoding::Decode(is, &codepoint))
|
||||||
|
return false;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
*outCount = count;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_INTERNAL_STRFUNC_H_
|
||||||
269
libs/discordrpc/rapidjson/internal/strtod.h
Normal file
269
libs/discordrpc/rapidjson/internal/strtod.h
Normal file
@@ -0,0 +1,269 @@
|
|||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_STRTOD_
|
||||||
|
#define RAPIDJSON_STRTOD_
|
||||||
|
|
||||||
|
#include "ieee754.h"
|
||||||
|
#include "biginteger.h"
|
||||||
|
#include "diyfp.h"
|
||||||
|
#include "pow10.h"
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
inline double FastPath(double significand, int exp) {
|
||||||
|
if (exp < -308)
|
||||||
|
return 0.0;
|
||||||
|
else if (exp >= 0)
|
||||||
|
return significand * internal::Pow10(exp);
|
||||||
|
else
|
||||||
|
return significand / internal::Pow10(-exp);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double StrtodNormalPrecision(double d, int p) {
|
||||||
|
if (p < -308) {
|
||||||
|
// Prevent expSum < -308, making Pow10(p) = 0
|
||||||
|
d = FastPath(d, -308);
|
||||||
|
d = FastPath(d, p + 308);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
d = FastPath(d, p);
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline T Min3(T a, T b, T c) {
|
||||||
|
T m = a;
|
||||||
|
if (m > b) m = b;
|
||||||
|
if (m > c) m = c;
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) {
|
||||||
|
const Double db(b);
|
||||||
|
const uint64_t bInt = db.IntegerSignificand();
|
||||||
|
const int bExp = db.IntegerExponent();
|
||||||
|
const int hExp = bExp - 1;
|
||||||
|
|
||||||
|
int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0;
|
||||||
|
|
||||||
|
// Adjust for decimal exponent
|
||||||
|
if (dExp >= 0) {
|
||||||
|
dS_Exp2 += dExp;
|
||||||
|
dS_Exp5 += dExp;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bS_Exp2 -= dExp;
|
||||||
|
bS_Exp5 -= dExp;
|
||||||
|
hS_Exp2 -= dExp;
|
||||||
|
hS_Exp5 -= dExp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adjust for binary exponent
|
||||||
|
if (bExp >= 0)
|
||||||
|
bS_Exp2 += bExp;
|
||||||
|
else {
|
||||||
|
dS_Exp2 -= bExp;
|
||||||
|
hS_Exp2 -= bExp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adjust for half ulp exponent
|
||||||
|
if (hExp >= 0)
|
||||||
|
hS_Exp2 += hExp;
|
||||||
|
else {
|
||||||
|
dS_Exp2 -= hExp;
|
||||||
|
bS_Exp2 -= hExp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove common power of two factor from all three scaled values
|
||||||
|
int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2);
|
||||||
|
dS_Exp2 -= common_Exp2;
|
||||||
|
bS_Exp2 -= common_Exp2;
|
||||||
|
hS_Exp2 -= common_Exp2;
|
||||||
|
|
||||||
|
BigInteger dS = d;
|
||||||
|
dS.MultiplyPow5(static_cast<unsigned>(dS_Exp5)) <<= static_cast<unsigned>(dS_Exp2);
|
||||||
|
|
||||||
|
BigInteger bS(bInt);
|
||||||
|
bS.MultiplyPow5(static_cast<unsigned>(bS_Exp5)) <<= static_cast<unsigned>(bS_Exp2);
|
||||||
|
|
||||||
|
BigInteger hS(1);
|
||||||
|
hS.MultiplyPow5(static_cast<unsigned>(hS_Exp5)) <<= static_cast<unsigned>(hS_Exp2);
|
||||||
|
|
||||||
|
BigInteger delta(0);
|
||||||
|
dS.Difference(bS, &delta);
|
||||||
|
|
||||||
|
return delta.Compare(hS);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool StrtodFast(double d, int p, double* result) {
|
||||||
|
// Use fast path for string-to-double conversion if possible
|
||||||
|
// see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
|
||||||
|
if (p > 22 && p < 22 + 16) {
|
||||||
|
// Fast Path Cases In Disguise
|
||||||
|
d *= internal::Pow10(p - 22);
|
||||||
|
p = 22;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1
|
||||||
|
*result = FastPath(d, p);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute an approximation and see if it is within 1/2 ULP
|
||||||
|
inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosition, int exp, double* result) {
|
||||||
|
uint64_t significand = 0;
|
||||||
|
size_t i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999
|
||||||
|
for (; i < length; i++) {
|
||||||
|
if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
|
||||||
|
(significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))
|
||||||
|
break;
|
||||||
|
significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < length && decimals[i] >= '5') // Rounding
|
||||||
|
significand++;
|
||||||
|
|
||||||
|
size_t remaining = length - i;
|
||||||
|
const unsigned kUlpShift = 3;
|
||||||
|
const unsigned kUlp = 1 << kUlpShift;
|
||||||
|
int64_t error = (remaining == 0) ? 0 : kUlp / 2;
|
||||||
|
|
||||||
|
DiyFp v(significand, 0);
|
||||||
|
v = v.Normalize();
|
||||||
|
error <<= -v.e;
|
||||||
|
|
||||||
|
const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(i) + exp;
|
||||||
|
|
||||||
|
int actualExp;
|
||||||
|
DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);
|
||||||
|
if (actualExp != dExp) {
|
||||||
|
static const DiyFp kPow10[] = {
|
||||||
|
DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60), // 10^1
|
||||||
|
DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 00000000), -57), // 10^2
|
||||||
|
DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 00000000), -54), // 10^3
|
||||||
|
DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 00000000), -50), // 10^4
|
||||||
|
DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 00000000), -47), // 10^5
|
||||||
|
DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44), // 10^6
|
||||||
|
DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40) // 10^7
|
||||||
|
};
|
||||||
|
int adjustment = dExp - actualExp - 1;
|
||||||
|
RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7);
|
||||||
|
v = v * kPow10[adjustment];
|
||||||
|
if (length + static_cast<unsigned>(adjustment)> 19u) // has more digits than decimal digits in 64-bit
|
||||||
|
error += kUlp / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
v = v * cachedPower;
|
||||||
|
|
||||||
|
error += kUlp + (error == 0 ? 0 : 1);
|
||||||
|
|
||||||
|
const int oldExp = v.e;
|
||||||
|
v = v.Normalize();
|
||||||
|
error <<= oldExp - v.e;
|
||||||
|
|
||||||
|
const unsigned effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e);
|
||||||
|
unsigned precisionSize = 64 - effectiveSignificandSize;
|
||||||
|
if (precisionSize + kUlpShift >= 64) {
|
||||||
|
unsigned scaleExp = (precisionSize + kUlpShift) - 63;
|
||||||
|
v.f >>= scaleExp;
|
||||||
|
v.e += scaleExp;
|
||||||
|
error = (error >> scaleExp) + 1 + static_cast<int>(kUlp);
|
||||||
|
precisionSize -= scaleExp;
|
||||||
|
}
|
||||||
|
|
||||||
|
DiyFp rounded(v.f >> precisionSize, v.e + static_cast<int>(precisionSize));
|
||||||
|
const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp;
|
||||||
|
const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp;
|
||||||
|
if (precisionBits >= halfWay + static_cast<unsigned>(error)) {
|
||||||
|
rounded.f++;
|
||||||
|
if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340)
|
||||||
|
rounded.f >>= 1;
|
||||||
|
rounded.e++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*result = rounded.ToDouble();
|
||||||
|
|
||||||
|
return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) {
|
||||||
|
const BigInteger dInt(decimals, length);
|
||||||
|
const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(length) + exp;
|
||||||
|
Double a(approx);
|
||||||
|
int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);
|
||||||
|
if (cmp < 0)
|
||||||
|
return a.Value(); // within half ULP
|
||||||
|
else if (cmp == 0) {
|
||||||
|
// Round towards even
|
||||||
|
if (a.Significand() & 1)
|
||||||
|
return a.NextPositiveDouble();
|
||||||
|
else
|
||||||
|
return a.Value();
|
||||||
|
}
|
||||||
|
else // adjustment
|
||||||
|
return a.NextPositiveDouble();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) {
|
||||||
|
RAPIDJSON_ASSERT(d >= 0.0);
|
||||||
|
RAPIDJSON_ASSERT(length >= 1);
|
||||||
|
|
||||||
|
double result;
|
||||||
|
if (StrtodFast(d, p, &result))
|
||||||
|
return result;
|
||||||
|
|
||||||
|
// Trim leading zeros
|
||||||
|
while (*decimals == '0' && length > 1) {
|
||||||
|
length--;
|
||||||
|
decimals++;
|
||||||
|
decimalPosition--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trim trailing zeros
|
||||||
|
while (decimals[length - 1] == '0' && length > 1) {
|
||||||
|
length--;
|
||||||
|
decimalPosition--;
|
||||||
|
exp++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trim right-most digits
|
||||||
|
const int kMaxDecimalDigit = 780;
|
||||||
|
if (static_cast<int>(length) > kMaxDecimalDigit) {
|
||||||
|
int delta = (static_cast<int>(length) - kMaxDecimalDigit);
|
||||||
|
exp += delta;
|
||||||
|
decimalPosition -= static_cast<unsigned>(delta);
|
||||||
|
length = kMaxDecimalDigit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If too small, underflow to zero
|
||||||
|
if (int(length) + exp < -324)
|
||||||
|
return 0.0;
|
||||||
|
|
||||||
|
if (StrtodDiyFp(decimals, length, decimalPosition, exp, &result))
|
||||||
|
return result;
|
||||||
|
|
||||||
|
// Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison
|
||||||
|
return StrtodBigInteger(result, decimals, length, decimalPosition, exp);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_STRTOD_
|
||||||
46
libs/discordrpc/rapidjson/internal/swap.h
Normal file
46
libs/discordrpc/rapidjson/internal/swap.h
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_INTERNAL_SWAP_H_
|
||||||
|
#define RAPIDJSON_INTERNAL_SWAP_H_
|
||||||
|
|
||||||
|
#include "../rapidjson.h"
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
//! Custom swap() to avoid dependency on C++ <algorithm> header
|
||||||
|
/*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only.
|
||||||
|
\note This has the same semantics as std::swap().
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT {
|
||||||
|
T tmp = a;
|
||||||
|
a = b;
|
||||||
|
b = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_INTERNAL_SWAP_H_
|
||||||
115
libs/discordrpc/rapidjson/istreamwrapper.h
Normal file
115
libs/discordrpc/rapidjson/istreamwrapper.h
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_ISTREAMWRAPPER_H_
|
||||||
|
#define RAPIDJSON_ISTREAMWRAPPER_H_
|
||||||
|
|
||||||
|
#include "stream.h"
|
||||||
|
#include <iosfwd>
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(padded)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
//! Wrapper of \c std::basic_istream into RapidJSON's Stream concept.
|
||||||
|
/*!
|
||||||
|
The classes can be wrapped including but not limited to:
|
||||||
|
|
||||||
|
- \c std::istringstream
|
||||||
|
- \c std::stringstream
|
||||||
|
- \c std::wistringstream
|
||||||
|
- \c std::wstringstream
|
||||||
|
- \c std::ifstream
|
||||||
|
- \c std::fstream
|
||||||
|
- \c std::wifstream
|
||||||
|
- \c std::wfstream
|
||||||
|
|
||||||
|
\tparam StreamType Class derived from \c std::basic_istream.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template <typename StreamType>
|
||||||
|
class BasicIStreamWrapper {
|
||||||
|
public:
|
||||||
|
typedef typename StreamType::char_type Ch;
|
||||||
|
BasicIStreamWrapper(StreamType& stream) : stream_(stream), count_(), peekBuffer_() {}
|
||||||
|
|
||||||
|
Ch Peek() const {
|
||||||
|
typename StreamType::int_type c = stream_.peek();
|
||||||
|
return RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()) ? static_cast<Ch>(c) : '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
Ch Take() {
|
||||||
|
typename StreamType::int_type c = stream_.get();
|
||||||
|
if (RAPIDJSON_LIKELY(c != StreamType::traits_type::eof())) {
|
||||||
|
count_++;
|
||||||
|
return static_cast<Ch>(c);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
// tellg() may return -1 when failed. So we count by ourself.
|
||||||
|
size_t Tell() const { return count_; }
|
||||||
|
|
||||||
|
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||||
|
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||||
|
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
|
||||||
|
// For encoding detection only.
|
||||||
|
const Ch* Peek4() const {
|
||||||
|
RAPIDJSON_ASSERT(sizeof(Ch) == 1); // Only usable for byte stream.
|
||||||
|
int i;
|
||||||
|
bool hasError = false;
|
||||||
|
for (i = 0; i < 4; ++i) {
|
||||||
|
typename StreamType::int_type c = stream_.get();
|
||||||
|
if (c == StreamType::traits_type::eof()) {
|
||||||
|
hasError = true;
|
||||||
|
stream_.clear();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
peekBuffer_[i] = static_cast<Ch>(c);
|
||||||
|
}
|
||||||
|
for (--i; i >= 0; --i)
|
||||||
|
stream_.putback(peekBuffer_[i]);
|
||||||
|
return !hasError ? peekBuffer_ : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
BasicIStreamWrapper(const BasicIStreamWrapper&);
|
||||||
|
BasicIStreamWrapper& operator=(const BasicIStreamWrapper&);
|
||||||
|
|
||||||
|
StreamType& stream_;
|
||||||
|
size_t count_; //!< Number of characters read. Note:
|
||||||
|
mutable Ch peekBuffer_[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef BasicIStreamWrapper<std::istream> IStreamWrapper;
|
||||||
|
typedef BasicIStreamWrapper<std::wistream> WIStreamWrapper;
|
||||||
|
|
||||||
|
#if defined(__clang__) || defined(_MSC_VER)
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_ISTREAMWRAPPER_H_
|
||||||
70
libs/discordrpc/rapidjson/memorybuffer.h
Normal file
70
libs/discordrpc/rapidjson/memorybuffer.h
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_MEMORYBUFFER_H_
|
||||||
|
#define RAPIDJSON_MEMORYBUFFER_H_
|
||||||
|
|
||||||
|
#include "stream.h"
|
||||||
|
#include "internal/stack.h"
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
//! Represents an in-memory output byte stream.
|
||||||
|
/*!
|
||||||
|
This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream.
|
||||||
|
|
||||||
|
It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file.
|
||||||
|
|
||||||
|
Differences between MemoryBuffer and StringBuffer:
|
||||||
|
1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer.
|
||||||
|
2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator.
|
||||||
|
|
||||||
|
\tparam Allocator type for allocating memory buffer.
|
||||||
|
\note implements Stream concept
|
||||||
|
*/
|
||||||
|
template <typename Allocator = CrtAllocator>
|
||||||
|
struct GenericMemoryBuffer {
|
||||||
|
typedef char Ch; // byte
|
||||||
|
|
||||||
|
GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
|
||||||
|
|
||||||
|
void Put(Ch c) { *stack_.template Push<Ch>() = c; }
|
||||||
|
void Flush() {}
|
||||||
|
|
||||||
|
void Clear() { stack_.Clear(); }
|
||||||
|
void ShrinkToFit() { stack_.ShrinkToFit(); }
|
||||||
|
Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
|
||||||
|
void Pop(size_t count) { stack_.template Pop<Ch>(count); }
|
||||||
|
|
||||||
|
const Ch* GetBuffer() const {
|
||||||
|
return stack_.template Bottom<Ch>();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t GetSize() const { return stack_.GetSize(); }
|
||||||
|
|
||||||
|
static const size_t kDefaultCapacity = 256;
|
||||||
|
mutable internal::Stack<Allocator> stack_;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef GenericMemoryBuffer<> MemoryBuffer;
|
||||||
|
|
||||||
|
//! Implement specialized version of PutN() with memset() for better performance.
|
||||||
|
template<>
|
||||||
|
inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) {
|
||||||
|
std::memset(memoryBuffer.stack_.Push<char>(n), c, n * sizeof(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_MEMORYBUFFER_H_
|
||||||
71
libs/discordrpc/rapidjson/memorystream.h
Normal file
71
libs/discordrpc/rapidjson/memorystream.h
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_MEMORYSTREAM_H_
|
||||||
|
#define RAPIDJSON_MEMORYSTREAM_H_
|
||||||
|
|
||||||
|
#include "stream.h"
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(unreachable-code)
|
||||||
|
RAPIDJSON_DIAG_OFF(missing-noreturn)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
//! Represents an in-memory input byte stream.
|
||||||
|
/*!
|
||||||
|
This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream.
|
||||||
|
|
||||||
|
It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file.
|
||||||
|
|
||||||
|
Differences between MemoryStream and StringStream:
|
||||||
|
1. StringStream has encoding but MemoryStream is a byte stream.
|
||||||
|
2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source.
|
||||||
|
3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4().
|
||||||
|
\note implements Stream concept
|
||||||
|
*/
|
||||||
|
struct MemoryStream {
|
||||||
|
typedef char Ch; // byte
|
||||||
|
|
||||||
|
MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {}
|
||||||
|
|
||||||
|
Ch Peek() const { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_; }
|
||||||
|
Ch Take() { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++; }
|
||||||
|
size_t Tell() const { return static_cast<size_t>(src_ - begin_); }
|
||||||
|
|
||||||
|
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||||
|
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||||
|
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
|
||||||
|
// For encoding detection only.
|
||||||
|
const Ch* Peek4() const {
|
||||||
|
return Tell() + 4 <= size_ ? src_ : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Ch* src_; //!< Current read position.
|
||||||
|
const Ch* begin_; //!< Original head of the string.
|
||||||
|
const Ch* end_; //!< End of stream.
|
||||||
|
size_t size_; //!< Size of the stream.
|
||||||
|
};
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_MEMORYBUFFER_H_
|
||||||
316
libs/discordrpc/rapidjson/msinttypes/inttypes.h
Normal file
316
libs/discordrpc/rapidjson/msinttypes/inttypes.h
Normal file
@@ -0,0 +1,316 @@
|
|||||||
|
// ISO C9x compliant inttypes.h for Microsoft Visual Studio
|
||||||
|
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
|
||||||
|
//
|
||||||
|
// Copyright (c) 2006-2013 Alexander Chemeris
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are met:
|
||||||
|
//
|
||||||
|
// 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer.
|
||||||
|
//
|
||||||
|
// 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer in the
|
||||||
|
// documentation and/or other materials provided with the distribution.
|
||||||
|
//
|
||||||
|
// 3. Neither the name of the product nor the names of its contributors may
|
||||||
|
// be used to endorse or promote products derived from this software
|
||||||
|
// without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||||
|
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||||
|
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// The above software in this distribution may have been modified by
|
||||||
|
// THL A29 Limited ("Tencent Modifications").
|
||||||
|
// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.
|
||||||
|
|
||||||
|
#ifndef _MSC_VER // [
|
||||||
|
#error "Use this header only with Microsoft Visual C++ compilers!"
|
||||||
|
#endif // _MSC_VER ]
|
||||||
|
|
||||||
|
#ifndef _MSC_INTTYPES_H_ // [
|
||||||
|
#define _MSC_INTTYPES_H_
|
||||||
|
|
||||||
|
#if _MSC_VER > 1000
|
||||||
|
#pragma once
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "stdint.h"
|
||||||
|
|
||||||
|
// miloyip: VC supports inttypes.h since VC2013
|
||||||
|
#if _MSC_VER >= 1800
|
||||||
|
#include <inttypes.h>
|
||||||
|
#else
|
||||||
|
|
||||||
|
// 7.8 Format conversion of integer types
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
intmax_t quot;
|
||||||
|
intmax_t rem;
|
||||||
|
} imaxdiv_t;
|
||||||
|
|
||||||
|
// 7.8.1 Macros for format specifiers
|
||||||
|
|
||||||
|
#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198
|
||||||
|
|
||||||
|
// The fprintf macros for signed integers are:
|
||||||
|
#define PRId8 "d"
|
||||||
|
#define PRIi8 "i"
|
||||||
|
#define PRIdLEAST8 "d"
|
||||||
|
#define PRIiLEAST8 "i"
|
||||||
|
#define PRIdFAST8 "d"
|
||||||
|
#define PRIiFAST8 "i"
|
||||||
|
|
||||||
|
#define PRId16 "hd"
|
||||||
|
#define PRIi16 "hi"
|
||||||
|
#define PRIdLEAST16 "hd"
|
||||||
|
#define PRIiLEAST16 "hi"
|
||||||
|
#define PRIdFAST16 "hd"
|
||||||
|
#define PRIiFAST16 "hi"
|
||||||
|
|
||||||
|
#define PRId32 "I32d"
|
||||||
|
#define PRIi32 "I32i"
|
||||||
|
#define PRIdLEAST32 "I32d"
|
||||||
|
#define PRIiLEAST32 "I32i"
|
||||||
|
#define PRIdFAST32 "I32d"
|
||||||
|
#define PRIiFAST32 "I32i"
|
||||||
|
|
||||||
|
#define PRId64 "I64d"
|
||||||
|
#define PRIi64 "I64i"
|
||||||
|
#define PRIdLEAST64 "I64d"
|
||||||
|
#define PRIiLEAST64 "I64i"
|
||||||
|
#define PRIdFAST64 "I64d"
|
||||||
|
#define PRIiFAST64 "I64i"
|
||||||
|
|
||||||
|
#define PRIdMAX "I64d"
|
||||||
|
#define PRIiMAX "I64i"
|
||||||
|
|
||||||
|
#define PRIdPTR "Id"
|
||||||
|
#define PRIiPTR "Ii"
|
||||||
|
|
||||||
|
// The fprintf macros for unsigned integers are:
|
||||||
|
#define PRIo8 "o"
|
||||||
|
#define PRIu8 "u"
|
||||||
|
#define PRIx8 "x"
|
||||||
|
#define PRIX8 "X"
|
||||||
|
#define PRIoLEAST8 "o"
|
||||||
|
#define PRIuLEAST8 "u"
|
||||||
|
#define PRIxLEAST8 "x"
|
||||||
|
#define PRIXLEAST8 "X"
|
||||||
|
#define PRIoFAST8 "o"
|
||||||
|
#define PRIuFAST8 "u"
|
||||||
|
#define PRIxFAST8 "x"
|
||||||
|
#define PRIXFAST8 "X"
|
||||||
|
|
||||||
|
#define PRIo16 "ho"
|
||||||
|
#define PRIu16 "hu"
|
||||||
|
#define PRIx16 "hx"
|
||||||
|
#define PRIX16 "hX"
|
||||||
|
#define PRIoLEAST16 "ho"
|
||||||
|
#define PRIuLEAST16 "hu"
|
||||||
|
#define PRIxLEAST16 "hx"
|
||||||
|
#define PRIXLEAST16 "hX"
|
||||||
|
#define PRIoFAST16 "ho"
|
||||||
|
#define PRIuFAST16 "hu"
|
||||||
|
#define PRIxFAST16 "hx"
|
||||||
|
#define PRIXFAST16 "hX"
|
||||||
|
|
||||||
|
#define PRIo32 "I32o"
|
||||||
|
#define PRIu32 "I32u"
|
||||||
|
#define PRIx32 "I32x"
|
||||||
|
#define PRIX32 "I32X"
|
||||||
|
#define PRIoLEAST32 "I32o"
|
||||||
|
#define PRIuLEAST32 "I32u"
|
||||||
|
#define PRIxLEAST32 "I32x"
|
||||||
|
#define PRIXLEAST32 "I32X"
|
||||||
|
#define PRIoFAST32 "I32o"
|
||||||
|
#define PRIuFAST32 "I32u"
|
||||||
|
#define PRIxFAST32 "I32x"
|
||||||
|
#define PRIXFAST32 "I32X"
|
||||||
|
|
||||||
|
#define PRIo64 "I64o"
|
||||||
|
#define PRIu64 "I64u"
|
||||||
|
#define PRIx64 "I64x"
|
||||||
|
#define PRIX64 "I64X"
|
||||||
|
#define PRIoLEAST64 "I64o"
|
||||||
|
#define PRIuLEAST64 "I64u"
|
||||||
|
#define PRIxLEAST64 "I64x"
|
||||||
|
#define PRIXLEAST64 "I64X"
|
||||||
|
#define PRIoFAST64 "I64o"
|
||||||
|
#define PRIuFAST64 "I64u"
|
||||||
|
#define PRIxFAST64 "I64x"
|
||||||
|
#define PRIXFAST64 "I64X"
|
||||||
|
|
||||||
|
#define PRIoMAX "I64o"
|
||||||
|
#define PRIuMAX "I64u"
|
||||||
|
#define PRIxMAX "I64x"
|
||||||
|
#define PRIXMAX "I64X"
|
||||||
|
|
||||||
|
#define PRIoPTR "Io"
|
||||||
|
#define PRIuPTR "Iu"
|
||||||
|
#define PRIxPTR "Ix"
|
||||||
|
#define PRIXPTR "IX"
|
||||||
|
|
||||||
|
// The fscanf macros for signed integers are:
|
||||||
|
#define SCNd8 "d"
|
||||||
|
#define SCNi8 "i"
|
||||||
|
#define SCNdLEAST8 "d"
|
||||||
|
#define SCNiLEAST8 "i"
|
||||||
|
#define SCNdFAST8 "d"
|
||||||
|
#define SCNiFAST8 "i"
|
||||||
|
|
||||||
|
#define SCNd16 "hd"
|
||||||
|
#define SCNi16 "hi"
|
||||||
|
#define SCNdLEAST16 "hd"
|
||||||
|
#define SCNiLEAST16 "hi"
|
||||||
|
#define SCNdFAST16 "hd"
|
||||||
|
#define SCNiFAST16 "hi"
|
||||||
|
|
||||||
|
#define SCNd32 "ld"
|
||||||
|
#define SCNi32 "li"
|
||||||
|
#define SCNdLEAST32 "ld"
|
||||||
|
#define SCNiLEAST32 "li"
|
||||||
|
#define SCNdFAST32 "ld"
|
||||||
|
#define SCNiFAST32 "li"
|
||||||
|
|
||||||
|
#define SCNd64 "I64d"
|
||||||
|
#define SCNi64 "I64i"
|
||||||
|
#define SCNdLEAST64 "I64d"
|
||||||
|
#define SCNiLEAST64 "I64i"
|
||||||
|
#define SCNdFAST64 "I64d"
|
||||||
|
#define SCNiFAST64 "I64i"
|
||||||
|
|
||||||
|
#define SCNdMAX "I64d"
|
||||||
|
#define SCNiMAX "I64i"
|
||||||
|
|
||||||
|
#ifdef _WIN64 // [
|
||||||
|
# define SCNdPTR "I64d"
|
||||||
|
# define SCNiPTR "I64i"
|
||||||
|
#else // _WIN64 ][
|
||||||
|
# define SCNdPTR "ld"
|
||||||
|
# define SCNiPTR "li"
|
||||||
|
#endif // _WIN64 ]
|
||||||
|
|
||||||
|
// The fscanf macros for unsigned integers are:
|
||||||
|
#define SCNo8 "o"
|
||||||
|
#define SCNu8 "u"
|
||||||
|
#define SCNx8 "x"
|
||||||
|
#define SCNX8 "X"
|
||||||
|
#define SCNoLEAST8 "o"
|
||||||
|
#define SCNuLEAST8 "u"
|
||||||
|
#define SCNxLEAST8 "x"
|
||||||
|
#define SCNXLEAST8 "X"
|
||||||
|
#define SCNoFAST8 "o"
|
||||||
|
#define SCNuFAST8 "u"
|
||||||
|
#define SCNxFAST8 "x"
|
||||||
|
#define SCNXFAST8 "X"
|
||||||
|
|
||||||
|
#define SCNo16 "ho"
|
||||||
|
#define SCNu16 "hu"
|
||||||
|
#define SCNx16 "hx"
|
||||||
|
#define SCNX16 "hX"
|
||||||
|
#define SCNoLEAST16 "ho"
|
||||||
|
#define SCNuLEAST16 "hu"
|
||||||
|
#define SCNxLEAST16 "hx"
|
||||||
|
#define SCNXLEAST16 "hX"
|
||||||
|
#define SCNoFAST16 "ho"
|
||||||
|
#define SCNuFAST16 "hu"
|
||||||
|
#define SCNxFAST16 "hx"
|
||||||
|
#define SCNXFAST16 "hX"
|
||||||
|
|
||||||
|
#define SCNo32 "lo"
|
||||||
|
#define SCNu32 "lu"
|
||||||
|
#define SCNx32 "lx"
|
||||||
|
#define SCNX32 "lX"
|
||||||
|
#define SCNoLEAST32 "lo"
|
||||||
|
#define SCNuLEAST32 "lu"
|
||||||
|
#define SCNxLEAST32 "lx"
|
||||||
|
#define SCNXLEAST32 "lX"
|
||||||
|
#define SCNoFAST32 "lo"
|
||||||
|
#define SCNuFAST32 "lu"
|
||||||
|
#define SCNxFAST32 "lx"
|
||||||
|
#define SCNXFAST32 "lX"
|
||||||
|
|
||||||
|
#define SCNo64 "I64o"
|
||||||
|
#define SCNu64 "I64u"
|
||||||
|
#define SCNx64 "I64x"
|
||||||
|
#define SCNX64 "I64X"
|
||||||
|
#define SCNoLEAST64 "I64o"
|
||||||
|
#define SCNuLEAST64 "I64u"
|
||||||
|
#define SCNxLEAST64 "I64x"
|
||||||
|
#define SCNXLEAST64 "I64X"
|
||||||
|
#define SCNoFAST64 "I64o"
|
||||||
|
#define SCNuFAST64 "I64u"
|
||||||
|
#define SCNxFAST64 "I64x"
|
||||||
|
#define SCNXFAST64 "I64X"
|
||||||
|
|
||||||
|
#define SCNoMAX "I64o"
|
||||||
|
#define SCNuMAX "I64u"
|
||||||
|
#define SCNxMAX "I64x"
|
||||||
|
#define SCNXMAX "I64X"
|
||||||
|
|
||||||
|
#ifdef _WIN64 // [
|
||||||
|
# define SCNoPTR "I64o"
|
||||||
|
# define SCNuPTR "I64u"
|
||||||
|
# define SCNxPTR "I64x"
|
||||||
|
# define SCNXPTR "I64X"
|
||||||
|
#else // _WIN64 ][
|
||||||
|
# define SCNoPTR "lo"
|
||||||
|
# define SCNuPTR "lu"
|
||||||
|
# define SCNxPTR "lx"
|
||||||
|
# define SCNXPTR "lX"
|
||||||
|
#endif // _WIN64 ]
|
||||||
|
|
||||||
|
#endif // __STDC_FORMAT_MACROS ]
|
||||||
|
|
||||||
|
// 7.8.2 Functions for greatest-width integer types
|
||||||
|
|
||||||
|
// 7.8.2.1 The imaxabs function
|
||||||
|
#define imaxabs _abs64
|
||||||
|
|
||||||
|
// 7.8.2.2 The imaxdiv function
|
||||||
|
|
||||||
|
// This is modified version of div() function from Microsoft's div.c found
|
||||||
|
// in %MSVC.NET%\crt\src\div.c
|
||||||
|
#ifdef STATIC_IMAXDIV // [
|
||||||
|
static
|
||||||
|
#else // STATIC_IMAXDIV ][
|
||||||
|
_inline
|
||||||
|
#endif // STATIC_IMAXDIV ]
|
||||||
|
imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)
|
||||||
|
{
|
||||||
|
imaxdiv_t result;
|
||||||
|
|
||||||
|
result.quot = numer / denom;
|
||||||
|
result.rem = numer % denom;
|
||||||
|
|
||||||
|
if (numer < 0 && result.rem > 0) {
|
||||||
|
// did division wrong; must fix up
|
||||||
|
++result.quot;
|
||||||
|
result.rem -= denom;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7.8.2.3 The strtoimax and strtoumax functions
|
||||||
|
#define strtoimax _strtoi64
|
||||||
|
#define strtoumax _strtoui64
|
||||||
|
|
||||||
|
// 7.8.2.4 The wcstoimax and wcstoumax functions
|
||||||
|
#define wcstoimax _wcstoi64
|
||||||
|
#define wcstoumax _wcstoui64
|
||||||
|
|
||||||
|
#endif // _MSC_VER >= 1800
|
||||||
|
|
||||||
|
#endif // _MSC_INTTYPES_H_ ]
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user