diff --git a/OSS13 Client/OSS13 Client.vcxproj b/OSS13 Client/OSS13 Client.vcxproj
index 7b10080..ae27e50 100644
--- a/OSS13 Client/OSS13 Client.vcxproj
+++ b/OSS13 Client/OSS13 Client.vcxproj
@@ -150,6 +150,7 @@
+
@@ -183,6 +184,7 @@
+
diff --git a/OSS13 Client/OSS13 Client.vcxproj.filters b/OSS13 Client/OSS13 Client.vcxproj.filters
index fb5ba67..d676386 100644
--- a/OSS13 Client/OSS13 Client.vcxproj.filters
+++ b/OSS13 Client/OSS13 Client.vcxproj.filters
@@ -96,6 +96,9 @@
Файлы исходного кода
+
+ Файлы исходного кода
+
@@ -191,5 +194,8 @@
Заголовочные файлы
+
+ Заголовочные файлы
+
\ No newline at end of file
diff --git a/OSS13 Client/Sources/Graphics/Sprite.cpp b/OSS13 Client/Sources/Graphics/Sprite.cpp
index 977ec68..bb3b4c2 100644
--- a/OSS13 Client/Sources/Graphics/Sprite.cpp
+++ b/OSS13 Client/Sources/Graphics/Sprite.cpp
@@ -75,4 +75,8 @@ void Sprite::updateSpriteVariables() {
sfSprite.setTexture(*texture->GetSFMLTexture());
sfSprite.setTextureRect(rect);
-}
\ No newline at end of file
+}
+
+const sf::Sprite &Sprite::GetSfmlSprite() const {
+ return sfSprite;
+}
diff --git a/OSS13 Client/Sources/Graphics/Sprite.hpp b/OSS13 Client/Sources/Graphics/Sprite.hpp
index 6a91ef0..10b42e2 100644
--- a/OSS13 Client/Sources/Graphics/Sprite.hpp
+++ b/OSS13 Client/Sources/Graphics/Sprite.hpp
@@ -27,6 +27,7 @@ class Sprite {
bool IsValid() const;
bool IsAnimated() const;
bool PixelTransparent(uf::vec2u pixel) const;
+ const sf::Sprite &GetSfmlSprite() const;
private:
mutable sf::Sprite sfSprite;
diff --git a/OSS13 Client/Sources/Graphics/UI/UIModule/GameProcessUI.cpp b/OSS13 Client/Sources/Graphics/UI/UIModule/GameProcessUI.cpp
index 6a3ee33..d0cb675 100644
--- a/OSS13 Client/Sources/Graphics/UI/UIModule/GameProcessUI.cpp
+++ b/OSS13 Client/Sources/Graphics/UI/UIModule/GameProcessUI.cpp
@@ -7,6 +7,7 @@
#include
#include
#include
+#include
#include
#include
@@ -115,6 +116,19 @@ void GameProcessUI::HandleEvent(sf::Event event) {
UIModule::HandleEvent(event);
}
+void GameProcessUI::OpenSpawnWindow() {
+ for (auto &widget : widgets)
+ if (dynamic_cast(widget.get()))
+ return;
+ widgets.push_back(std::make_unique());
+}
+
+void GameProcessUI::UpdateSpawnWindow(std::vector &&types) {
+ for (auto &widget : widgets)
+ if (auto *spawnWidget = dynamic_cast(widget.get()))
+ spawnWidget->UpdateTypes(std::forward>(types));
+}
+
InfoLabel *GameProcessUI::GetInfoLabel() const { return infoLabel.get(); }
TileGrid *GameProcessUI::GetTileGrid() const { return tileGrid; }
diff --git a/OSS13 Client/Sources/Graphics/UI/UIModule/GameProcessUI.hpp b/OSS13 Client/Sources/Graphics/UI/UIModule/GameProcessUI.hpp
index 2bef4d8..cf4720e 100644
--- a/OSS13 Client/Sources/Graphics/UI/UIModule/GameProcessUI.hpp
+++ b/OSS13 Client/Sources/Graphics/UI/UIModule/GameProcessUI.hpp
@@ -7,6 +7,8 @@
#include "Graphics/UI/Widget/FormattedTextField.hpp"
#include "UIModule.hpp"
+#include
+
class UI;
class TileGrid;
@@ -27,6 +29,9 @@ class GameProcessUI : public UIModule {
void Update(sf::Time timeElapsed) override final;
void HandleEvent(sf::Event event) override;
+ void OpenSpawnWindow();
+ void UpdateSpawnWindow(std::vector &&types);
+
InfoLabel *GetInfoLabel() const;
TileGrid *GetTileGrid() const;
diff --git a/OSS13 Client/Sources/Graphics/UI/Widget/SpawnWindow.cpp b/OSS13 Client/Sources/Graphics/UI/Widget/SpawnWindow.cpp
new file mode 100644
index 0000000..b58da05
--- /dev/null
+++ b/OSS13 Client/Sources/Graphics/UI/Widget/SpawnWindow.cpp
@@ -0,0 +1,131 @@
+#include "SpawnWindow.h"
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include
+
+
+void SpawnWindow::Update(sf::Time timeElapsed) {
+ std::unique_lock lock(guard);
+
+ ImGui::SetNextWindowPos(ImVec2(60, 60), ImGuiCond_Once);
+ ImGui::SetNextWindowSize(ImVec2(300, 300), ImGuiCond_Once);
+
+ if (!ImGui::Begin("Object Spawner")) {
+ ImGui::End();
+ return;
+ }
+
+ drawHeader();
+ drawBody();
+
+ ImGui::End();
+}
+
+void SpawnWindow::UpdateTypes(std::vector &&types) {
+ std::unique_lock lock(guard);
+
+ this->types = std::forward>(types);
+ noQueriesYet = false;
+}
+
+void searchTypesAndDropBuffer(std::string &searchBuffer) {
+ auto command = std::make_unique();
+ std::swap(command->searchBuffer, searchBuffer);
+ Connection::commandQueue.Push(command.release());
+}
+
+void drawHeaderInput(std::string &searchBuffer) {
+ if (ImGui::InputTextWithHint("", "all object types", &searchBuffer, ImGuiInputTextFlags_EnterReturnsTrue)) {
+ searchTypesAndDropBuffer(searchBuffer);
+ }
+}
+
+void drawHeaderSearchButton(std::string &searchBuffer) {
+ ImGui::SameLine();
+ if (ImGui::Button("Search")) {
+ searchTypesAndDropBuffer(searchBuffer);
+ }
+}
+
+void SpawnWindow::drawHeader() {
+ drawHeaderInput(searchBuffer);
+ drawHeaderSearchButton(searchBuffer);
+}
+
+void drawTypesListItemTooltip(const network::protocol::ObjectType &type) {
+ if (type.sprite) {
+ auto sprite = CC::Get()->RM.CreateSprite(type.sprite);
+ ImGui::Image(sprite.GetSfmlSprite());
+ ImGui::SameLine();
+ }
+
+ ImGui::BeginGroup();
+ ImGui::Text(type.name.c_str());
+ ImGui::Text(type.typeKey.c_str());
+ ImGui::Text(type.description.c_str());
+ ImGui::EndGroup();
+}
+
+void drawTypesListItem(const network::protocol::ObjectType &type, bool &selected) {
+ ImGui::Selectable(type.typeKey.c_str(), &selected);
+
+ if (ImGui::IsItemHovered()) {
+ ImGui::BeginTooltip();
+ drawTypesListItemTooltip(type);
+ ImGui::EndTooltip();
+ }
+}
+
+void drawTypesListEmptySearchResultText() {
+ ImGui::Text("No types were found!");
+}
+
+void drawTypesListContent(const std::vector &types, size_t &selectedIndex) {
+ size_t counter = 0;
+ for (auto &type : types) {
+ counter++;
+ bool selected = (counter == selectedIndex);
+ drawTypesListItem(type, selected);
+ if (selected)
+ selectedIndex = counter;
+ }
+}
+
+void SpawnWindow::drawTypesList() {
+ const float footerHeightToReserve = ImGui::GetFrameHeightWithSpacing();
+ ImGui::BeginChild("types list", ImVec2(0, -footerHeightToReserve), true);
+
+ if (!types.size() && !noQueriesYet)
+ drawTypesListEmptySearchResultText();
+ else
+ drawTypesListContent(types, selectedIndex);
+
+ ImGui::EndChild();
+}
+
+void spawnObject(const std::string &typeKey) {
+ auto command = std::make_unique();
+ command->typeKey = typeKey;
+ Connection::commandQueue.Push(command.release());
+}
+
+void SpawnWindow::drawSpawnButton() {
+ bool disabled = (selectedIndex == 0);
+ if (ImGui::Button("Spawn", disabled)) {
+ spawnObject(types[selectedIndex - 1].typeKey);
+ }
+}
+
+void SpawnWindow::drawBody() {
+ drawTypesList();
+ drawSpawnButton();
+}
diff --git a/OSS13 Client/Sources/Graphics/UI/Widget/SpawnWindow.h b/OSS13 Client/Sources/Graphics/UI/Widget/SpawnWindow.h
new file mode 100644
index 0000000..21d916b
--- /dev/null
+++ b/OSS13 Client/Sources/Graphics/UI/Widget/SpawnWindow.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include
+
+#include
+
+#include
+
+class SpawnWindow : public ImGuiWidget {
+public:
+ void Update(sf::Time timeElapsed) final;
+
+ void UpdateTypes(std::vector &&types);
+
+private:
+ void drawHeader();
+ void drawBody();
+ void drawTypesList();
+ void drawSpawnButton();
+
+private:
+ std::vector types;
+ size_t selectedIndex{0};
+ std::string searchBuffer;
+ std::mutex guard;
+ bool noQueriesYet{true};
+};
diff --git a/OSS13 Client/Sources/Network.cpp b/OSS13 Client/Sources/Network.cpp
index 76cac63..1a3b3f5 100644
--- a/OSS13 Client/Sources/Network.cpp
+++ b/OSS13 Client/Sources/Network.cpp
@@ -255,6 +255,20 @@ bool Connection::parsePacket(Packet &packet) {
return true;
}
+ if (auto *command = dynamic_cast(p.get())) {
+ GameProcessUI *gameProcessUI = dynamic_cast(CC::Get()->GetWindow()->GetUI()->GetCurrentUIModule());
+ EXPECT(gameProcessUI);
+ gameProcessUI->OpenSpawnWindow();
+ return true;
+ }
+
+ if (auto *command = dynamic_cast(p.get())) {
+ GameProcessUI *gameProcessUI = dynamic_cast(CC::Get()->GetWindow()->GetUI()->GetCurrentUIModule());
+ EXPECT(gameProcessUI);
+ gameProcessUI->UpdateSpawnWindow(std::forward>(command->types));
+ return true;
+ }
+
if (auto *command = dynamic_cast(p.get())) {
UIModule *uiModule = CC::Get()->GetWindow()->GetUI()->GetCurrentUIModule();
EXPECT(uiModule);