feat: add summon menu

This commit is contained in:
2021-11-04 10:03:37 +01:00
parent f2f79781db
commit 129544d127
15 changed files with 307 additions and 51 deletions

View File

@@ -27,7 +27,9 @@ enum class MobType : std::uint8_t {
Blaze, Blaze,
Witch, Witch,
Slime, Slime,
Giant Giant,
MOB_COUNT
}; };
typedef std::uint32_t MobID; typedef std::uint32_t MobID;
@@ -132,6 +134,62 @@ public:
virtual MobType getType() const { return MobType::Spider; } virtual MobType getType() const { return MobType::Spider; }
}; };
class Skeleton : public Mob {
public:
Skeleton(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initHealth(); }
virtual MobType getType() const { return MobType::Skeleton; }
};
class PigMan : public Mob {
public:
PigMan(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initHealth(); }
virtual MobType getType() const { return MobType::Pigman; }
};
class Creeper : public Mob {
public:
Creeper(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initHealth(); }
virtual MobType getType() const { return MobType::Creeper; }
};
class Silverfish : public Mob {
public:
Silverfish(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initHealth(); }
virtual MobType getType() const { return MobType::Silverfish; }
};
class Blaze : public Mob {
public:
Blaze(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initHealth(); }
virtual MobType getType() const { return MobType::Blaze; }
};
class Witch : public Mob {
public:
Witch(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initHealth(); }
virtual MobType getType() const { return MobType::Witch; }
};
class Slime : public Mob {
public:
Slime(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initHealth(); }
virtual MobType getType() const { return MobType::Slime; }
};
class Giant : public Mob {
public:
Giant(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initHealth(); }
virtual MobType getType() const { return MobType::Giant; }
};
namespace MobFactory { namespace MobFactory {
MobPtr createMob(MobID id, MobType type, std::uint8_t level, PlayerID sender); MobPtr createMob(MobID id, MobType type, std::uint8_t level, PlayerID sender);
} }

View File

@@ -6,6 +6,8 @@
#include "game/Team.h" #include "game/Team.h"
#include "game/Player.h" #include "game/Player.h"
#include "protocol/Protocol.h"
#include "render/Renderer.h" #include "render/Renderer.h"
#include "network/Network.h" #include "network/Network.h"
@@ -39,6 +41,7 @@ public:
bool isConnected() const { return m_Connexion.getSocketStatus() == network::Socket::Connected; } bool isConnected() const { return m_Connexion.getSocketStatus() == network::Socket::Connected; }
void selectTeam(game::TeamColor team); void selectTeam(game::TeamColor team);
void sendMobs(const std::vector<protocol::MobSend>& mobSends);
}; };
} // namespace client } // namespace client

View File

@@ -38,6 +38,7 @@ public:
virtual void HandlePacket(protocol::SelectTeamPacket* packet); virtual void HandlePacket(protocol::SelectTeamPacket* packet);
virtual void HandlePacket(protocol::DisconnectPacket* packet); virtual void HandlePacket(protocol::DisconnectPacket* packet);
virtual void HandlePacket(protocol::PlaceTowerPacket* packet); virtual void HandlePacket(protocol::PlaceTowerPacket* packet);
virtual void HandlePacket(protocol::SendMobsPacket* packet);
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; }

View File

@@ -36,6 +36,7 @@ public:
virtual void HandlePacket(PlaceTowerPacket* packet) {} virtual void HandlePacket(PlaceTowerPacket* packet) {}
virtual void HandlePacket(WorldAddTowerPacket* packet) {} virtual void HandlePacket(WorldAddTowerPacket* packet) {}
virtual void HandlePacket(WorldRemoveTowerPacket* packet) {} virtual void HandlePacket(WorldRemoveTowerPacket* packet) {}
virtual void HandlePacket(SendMobsPacket* packet) {}
}; };
} // namespace protocol } // namespace protocol

View File

@@ -28,6 +28,7 @@ enum class PacketType : std::uint8_t {
UpdatePlayerTeam, UpdatePlayerTeam,
ServerTps, ServerTps,
SpawnMob, SpawnMob,
SendMobs,
PlaceTower, PlaceTower,
WorldAddTower, WorldAddTower,
WorldRemoveTower, WorldRemoveTower,
@@ -369,6 +370,29 @@ public:
virtual PacketType getType() const { return PacketType::ServerTps; } virtual PacketType getType() const { return PacketType::ServerTps; }
}; };
struct MobSend { // represents a mob send
game::MobType mobType;
game::MobLevel mobLevel;
std::uint8_t mobCount; // the max is 12
};
class SendMobsPacket : public Packet {
private:
std::vector<MobSend> m_MobSends;
public:
SendMobsPacket() {}
SendMobsPacket(const std::vector<MobSend>& mobSends) : m_MobSends(mobSends) {}
virtual ~SendMobsPacket() {}
virtual DataBuffer Serialize() const;
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler);
const std::vector<MobSend>& getMobSends() const { return m_MobSends; }
virtual PacketType getType() const { return PacketType::SendMobs; }
};
class SpawnMobPacket : public Packet { class SpawnMobPacket : public Packet {
private: private:
game::MobID m_MobID; game::MobID m_MobID;

View File

@@ -0,0 +1,27 @@
#pragma once
#include "GuiWidget.h"
#include <vector>
#include <memory>
namespace td {
namespace gui {
class GuiManager {
private:
std::vector<std::shared_ptr<GuiWidget>> m_Widgets;
public:
void renderWidgets(){
for(auto widget : m_Widgets){
widget->render();
}
}
void addWidgets(const std::shared_ptr<GuiWidget>& widget){
m_Widgets.push_back(std::move(widget));
}
};
} // namespace gui
} // namespace td

View File

@@ -0,0 +1,25 @@
#pragma once
namespace td {
namespace client {
class Client;
} // namespace client
namespace gui {
class GuiWidget {
protected:
client::Client* m_Client;
public:
GuiWidget(client::Client* client) {
m_Client = client;
}
client::Client* getClient() { return m_Client; }
virtual void render() = 0;
};
} // namespace gui
} // namespace td

View File

@@ -0,0 +1,26 @@
#pragma once
#include "GuiWidget.h"
#include <array>
#include "game/Mobs.h"
namespace td {
namespace gui {
class SummonMenu : public GuiWidget{
private:
bool m_MenuOpened;
int m_ImageWidth = 100;
static constexpr int m_MobTypeCount = static_cast<std::size_t>(td::game::MobType::MOB_COUNT);
std::array<int, static_cast<std::size_t>(m_MobTypeCount)> m_Values;
public:
SummonMenu(client::Client* client);
virtual void render();
private:
void setSummonMax(int valueIndex);
};
} // namespace gui
} // namespace td

View File

@@ -253,8 +253,16 @@ MobPtr MobFactory::createMob(MobID id, MobType type, std::uint8_t level, PlayerI
using MobCreator = std::function<std::shared_ptr<Mob>(MobID, std::uint8_t, PlayerID)>; using MobCreator = std::function<std::shared_ptr<Mob>(MobID, std::uint8_t, PlayerID)>;
static std::map<MobType, MobCreator> mobFactory = { static std::map<MobType, MobCreator> mobFactory = {
{MobType::Zombie, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Zombie>(id, level, sender);} }, {MobType::Zombie, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Zombie>(id, level, sender);} },
{MobType::Spider, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Spider>(id, level, sender);} }, {MobType::Spider, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Spider>(id, level, sender);} },
{MobType::Skeleton, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Skeleton>(id, level, sender);} },
{MobType::Pigman, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<PigMan>(id, level, sender);} },
{MobType::Creeper, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Creeper>(id, level, sender);} },
{MobType::Silverfish, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Silverfish>(id, level, sender);} },
{MobType::Blaze, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Blaze>(id, level, sender);} },
{MobType::Witch, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Witch>(id, level, sender);} },
{MobType::Slime, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Slime>(id, level, sender);} },
{MobType::Giant, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Giant>(id, level, sender);} },
}; };
return mobFactory[type](id, level, sender); return mobFactory[type](id, level, sender);

View File

@@ -49,5 +49,10 @@ void Client::render() {
m_Game.renderWorld(); m_Game.renderWorld();
} }
void Client::sendMobs(const std::vector<protocol::MobSend>& mobSends){
protocol::SendMobsPacket packet(mobSends);
m_Connexion.sendPacket(&packet);
}
} // namespace client } // namespace client
} // namespace td } // namespace td

View File

@@ -39,6 +39,7 @@ void ServerConnexion::registerHandlers() {
GetDispatcher()->RegisterHandler(protocol::PacketType::SelectTeam, this); GetDispatcher()->RegisterHandler(protocol::PacketType::SelectTeam, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::Disconnect, this); GetDispatcher()->RegisterHandler(protocol::PacketType::Disconnect, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::PlaceTower, this); GetDispatcher()->RegisterHandler(protocol::PacketType::PlaceTower, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::SendMobs, this);
} }
bool ServerConnexion::updateSocket() { bool ServerConnexion::updateSocket() {
@@ -147,6 +148,7 @@ void ServerConnexion::HandlePacket(protocol::PlaceTowerPacket* packet) {
game::TowerType towerType = packet->getTowerType(); game::TowerType towerType = packet->getTowerType();
const game::TowerInfo& towerInfo = game::getTowerInfo(towerType); const game::TowerInfo& towerInfo = game::getTowerInfo(towerType);
server::ServerWorld* world = m_Server->getGame().getServerWorld(); server::ServerWorld* world = m_Server->getGame().getServerWorld();
if (towerInfo.isBigTower()) { if (towerInfo.isBigTower()) {
if (!world->CanPlaceBigTower({ packet->getTowerX(), packet->getTowerY() }, m_ID)) if (!world->CanPlaceBigTower({ packet->getTowerX(), packet->getTowerY() }, m_ID))
return; return;
@@ -161,6 +163,16 @@ void ServerConnexion::HandlePacket(protocol::PlaceTowerPacket* packet) {
m_Server->broadcastPacket(&addTowerPacket); m_Server->broadcastPacket(&addTowerPacket);
} }
void ServerConnexion::HandlePacket(protocol::SendMobsPacket* packet) {
const std::vector<protocol::MobSend>& mobSent = packet->getMobSends();
//TODO: verify the packet
for(protocol::MobSend mobSend : mobSent){
m_Server->getGame().getServerWorld()->spawnMobs(mobSend.mobType, mobSend.mobLevel, m_ID, mobSend.mobCount);
}
}
ServerConnexion::~ServerConnexion() { ServerConnexion::~ServerConnexion() {
if (GetDispatcher() != nullptr) if (GetDispatcher() != nullptr)
GetDispatcher()->UnregisterHandler(this); GetDispatcher()->UnregisterHandler(this);

View File

@@ -29,6 +29,7 @@ static std::map<PacketType, PacketCreator> packets = {
{PacketType::PlaceTower, []() -> Packet* {return new PlaceTowerPacket(); } }, {PacketType::PlaceTower, []() -> Packet* {return new PlaceTowerPacket(); } },
{PacketType::WorldAddTower, []() -> Packet* {return new WorldAddTowerPacket(); } }, {PacketType::WorldAddTower, []() -> Packet* {return new WorldAddTowerPacket(); } },
{PacketType::WorldRemoveTower, []() -> Packet* {return new WorldRemoveTowerPacket(); } }, {PacketType::WorldRemoveTower, []() -> Packet* {return new WorldRemoveTowerPacket(); } },
{PacketType::SendMobs, []() -> Packet* {return new SendMobsPacket(); } },
}; };
Packet* createPacket(PacketType type, DataBuffer& buffer) { Packet* createPacket(PacketType type, DataBuffer& buffer) {

View File

@@ -495,6 +495,25 @@ void WorldRemoveTowerPacket::Deserialize(DataBuffer& data) {
data >> m_TowerID; data >> m_TowerID;
} }
DataBuffer SendMobsPacket::Serialize() const {
DataBuffer data;
data << getID() << static_cast<std::uint8_t>(m_MobSends.size());
for(const MobSend& mobSend : m_MobSends){
data << mobSend;
}
return data;
}
void SendMobsPacket::Deserialize(DataBuffer& data) {
std::uint8_t mobSendCount;
data >> mobSendCount;
protocol::MobSend mobSend;
for(int i = 0; i < mobSendCount; i++){
data >> mobSend;
m_MobSends.push_back(mobSend);
}
}
REGISTER_DISPATCH_CLASS(PlayerLoginPacket); REGISTER_DISPATCH_CLASS(PlayerLoginPacket);
REGISTER_DISPATCH_CLASS(WorldBeginDataPacket); REGISTER_DISPATCH_CLASS(WorldBeginDataPacket);
REGISTER_DISPATCH_CLASS(WorldDataPacket); REGISTER_DISPATCH_CLASS(WorldDataPacket);
@@ -515,6 +534,7 @@ REGISTER_DISPATCH_CLASS(SpawnMobPacket);
REGISTER_DISPATCH_CLASS(PlaceTowerPacket); REGISTER_DISPATCH_CLASS(PlaceTowerPacket);
REGISTER_DISPATCH_CLASS(WorldAddTowerPacket); REGISTER_DISPATCH_CLASS(WorldAddTowerPacket);
REGISTER_DISPATCH_CLASS(WorldRemoveTowerPacket); REGISTER_DISPATCH_CLASS(WorldRemoveTowerPacket);
REGISTER_DISPATCH_CLASS(SendMobsPacket);
} // namespace protocol } // namespace protocol
} // namespace td } // namespace td

View File

@@ -0,0 +1,82 @@
#include "render/gui/SummonMenu.h"
#include "game/client/Client.h"
#include "render/gui/imgui/imgui.h"
namespace td {
namespace gui {
SummonMenu::SummonMenu(client::Client* client) : GuiWidget(client), m_MenuOpened(true){
m_Values.fill(0);
}
void SummonMenu::render(){
if (m_MenuOpened) {
ImGui::Begin("Summon", &m_MenuOpened);
ImTextureID my_tex_id = ImGui::GetIO().Fonts->TexID;
for (int i = 0; i < m_MobTypeCount / 2; i++) {
ImGui::SameLine();
ImGui::PushID(i);
ImGui::Image(my_tex_id, ImVec2(100, 100));
ImGui::PopID();
}
ImGui::Separator();
ImGui::PushItemWidth(m_ImageWidth);
for (int i = 0; i < m_MobTypeCount / 2; i++) {
ImGui::SameLine();
ImGui::PushID(i);
if (ImGui::InputInt("", m_Values.data() + i, 1, 10)) {
setSummonMax(i);
}
ImGui::PopID();
}
ImGui::PopItemWidth();
ImGui::Separator();
for (int i = m_MobTypeCount / 2; i < m_MobTypeCount; i++) {
ImGui::SameLine();
ImGui::PushID(i);
ImGui::Image(my_tex_id, ImVec2(100, 100));
ImGui::PopID();
}
ImGui::Separator();
ImGui::PushItemWidth(m_ImageWidth);
for (int i = m_MobTypeCount / 2; i < m_MobTypeCount; i++) {
ImGui::SameLine();
ImGui::PushID(i);
if (ImGui::InputInt("", m_Values.data() + i, 1, m_MobTypeCount)) {
setSummonMax(i);
}
ImGui::PopID();
}
ImGui::PopItemWidth();
if (ImGui::Button("Send")) {
std::vector<protocol::MobSend> mobSent;
protocol::MobSend mobSend;
for(int i = 0; i < m_MobTypeCount; i++){
if(m_Values[i] != 0){
mobSend.mobCount = m_Values[i];
mobSend.mobLevel = 1; // TODO: add mob levels
mobSend.mobType = td::game::MobType(i);
mobSent.push_back(mobSend);
}
}
m_Client->sendMobs(mobSent);
m_Values.fill(0);
}
ImGui::End();
}
}
void SummonMenu::setSummonMax(int valueIndex){
int& value = m_Values[valueIndex];
value = std::max(0, value);
value = std::min(12, value);
int total = 0;
for (std::size_t i = 0; i < m_Values.size(); i++) {
total += m_Values[i];
}
if (total == 13) // if the total is greater than the maximum, we substract the value
value--;
}
} // namespace gui
} // namespace td

View File

@@ -18,6 +18,9 @@
#include "render/Renderer.h" #include "render/Renderer.h"
#include "network/Network.h" #include "network/Network.h"
#include "render/gui/GuiManager.h"
#include "render/gui/SummonMenu.h"
#include <iostream> #include <iostream>
#include <cmath> #include <cmath>
@@ -28,9 +31,14 @@ static SDL_GLContext gl_context;
static std::unique_ptr<td::client::Client> client; static std::unique_ptr<td::client::Client> client;
static std::thread* serverThread; static std::thread* serverThread;
static td::render::Renderer* renderer; static td::render::Renderer* renderer;
static td::gui::GuiManager guiManager;
bool serverShouldStop = false; bool serverShouldStop = false;
void initWidgets(){
guiManager.addWidgets(std::make_shared<td::gui::SummonMenu>(client.get()));
}
void init(SDL_Window* sdl_window, SDL_GLContext sdlContext, td::render::Renderer* render) { void init(SDL_Window* sdl_window, SDL_GLContext sdlContext, td::render::Renderer* render) {
window = sdl_window; window = sdl_window;
gl_context = sdlContext; gl_context = sdlContext;
@@ -44,6 +52,7 @@ void init(SDL_Window* sdl_window, SDL_GLContext sdlContext, td::render::Renderer
ImGui::GetIO().Fonts->AddFontDefault(&c); ImGui::GetIO().Fonts->AddFontDefault(&c);
renderer = render; renderer = render;
client = std::make_unique<td::client::Client>(render); client = std::make_unique<td::client::Client>(render);
initWidgets();
} }
void beginFrame() { void beginFrame() {
@@ -237,53 +246,7 @@ void capValues(int* values, int& value) {
} }
void renderSummonMenu() { void renderSummonMenu() {
static bool menu_open = true;
if (menu_open) {
ImGui::Begin("Summon", &menu_open);
static int width = 100;
static int values[16]{ 0 };
ImTextureID my_tex_id = ImGui::GetIO().Fonts->TexID;
for (int i = 0; i < 8; i++) {
ImGui::SameLine();
ImGui::PushID(i);
ImGui::Image(my_tex_id, ImVec2(100, 100));
ImGui::PopID();
}
ImGui::Separator();
ImGui::PushItemWidth(width);
for (int i = 0; i < 8; i++) {
ImGui::SameLine();
ImGui::PushID(i);
if (ImGui::InputInt("", values + i, 1, 10)) {
capValues(values, values[i]);
}
ImGui::PopID();
}
ImGui::PopItemWidth();
ImGui::Separator();
for (int i = 0; i < 8; i++) {
ImGui::SameLine();
ImGui::PushID(i);
ImGui::Image(my_tex_id, ImVec2(100, 100));
ImGui::PopID();
}
ImGui::Separator();
ImGui::PushItemWidth(width);
for (int i = 8; i < 16; i++) {
ImGui::SameLine();
ImGui::PushID(i);
if (ImGui::InputInt("", values + i, 1, 10)) {
capValues(values, values[i]);
}
ImGui::PopID();
}
ImGui::PopItemWidth();
if (ImGui::Button("Send")) {
std::cout << "Sending Troops ...\n";
}
ImGui::End();
}
} }
void renderGame() { void renderGame() {
@@ -303,7 +266,7 @@ void renderGame() {
showTPS(); showTPS();
showStats(); showStats();
showPlayers(); showPlayers();
renderSummonMenu(); guiManager.renderWidgets();
ImGui::End(); ImGui::End();
} }