diff options
author | LaG1924 <12997935+LaG1924@users.noreply.github.com> | 2017-09-16 17:48:19 +0200 |
---|---|---|
committer | LaG1924 <12997935+LaG1924@users.noreply.github.com> | 2018-01-13 03:39:31 +0100 |
commit | 892b9732751b64c2016ba476801e1fe4ed4e750f (patch) | |
tree | 99aa40953de5d61e30d47bdf345ee2cb9c3c18e1 | |
parent | 2017-09-15 (diff) | |
download | AltCraft-892b9732751b64c2016ba476801e1fe4ed4e750f.tar AltCraft-892b9732751b64c2016ba476801e1fe4ed4e750f.tar.gz AltCraft-892b9732751b64c2016ba476801e1fe4ed4e750f.tar.bz2 AltCraft-892b9732751b64c2016ba476801e1fe4ed4e750f.tar.lz AltCraft-892b9732751b64c2016ba476801e1fe4ed4e750f.tar.xz AltCraft-892b9732751b64c2016ba476801e1fe4ed4e750f.tar.zst AltCraft-892b9732751b64c2016ba476801e1fe4ed4e750f.zip |
Diffstat (limited to '')
-rw-r--r-- | src/Entity.hpp | 4 | ||||
-rw-r--r-- | src/GameState.cpp | 20 | ||||
-rw-r--r-- | src/NetworkClient.cpp | 6 | ||||
-rw-r--r-- | src/Packet.hpp | 21 | ||||
-rw-r--r-- | src/Render.cpp | 96 | ||||
-rw-r--r-- | src/RendererSection.cpp | 2 | ||||
-rw-r--r-- | src/RendererWidget.cpp | 76 | ||||
-rw-r--r-- | src/RendererWidget.hpp | 15 | ||||
-rw-r--r-- | src/RendererWorld.cpp | 2 | ||||
-rw-r--r-- | src/Stream.cpp | 7 | ||||
-rw-r--r-- | src/Widget.cpp | 124 | ||||
-rw-r--r-- | src/Widget.hpp | 74 | ||||
-rw-r--r-- | src/Window.cpp | 32 | ||||
-rw-r--r-- | src/Window.hpp | 8 | ||||
-rw-r--r-- | src/World.cpp | 3 |
15 files changed, 170 insertions, 320 deletions
diff --git a/src/Entity.hpp b/src/Entity.hpp index 279f127..c818abe 100644 --- a/src/Entity.hpp +++ b/src/Entity.hpp @@ -126,8 +126,8 @@ struct Entity { unsigned int entityId = 0; double yaw = 0; double pitch = 0; - double width = 0.1; - double height = 0.1; + double width = 1.0; + double height = 1.0; glm::vec3 renderColor; int entityType=0; bool isMob=false; diff --git a/src/GameState.cpp b/src/GameState.cpp index 46b236c..98b49f7 100644 --- a/src/GameState.cpp +++ b/src/GameState.cpp @@ -140,8 +140,17 @@ void GameState::UpdatePacket() world.ParseChunkData(packet); break; } - case ConfirmTransactionCB: + case ConfirmTransactionCB: { + auto packet = std::static_pointer_cast<PacketConfirmTransactionCB>(ptr); + if (packet->WindowId == 0) { + try { + playerInventory.ConfirmTransaction(*packet); + } catch (std::exception &e) { + EventAgregator::PushEvent(EventType::Disconnect, DisconnectData{ "Transaction failed" }); + } + } break; + } case CloseWindowCB: break; case OpenWindow: { @@ -160,8 +169,13 @@ void GameState::UpdatePacket() } case WindowProperty: break; - case SetSlot: + case SetSlot: { + auto packet = std::static_pointer_cast<PacketSetSlot>(ptr); + if (packet->WindowId == 0) { + playerInventory.slots[packet->Slot] = packet->SlotData; + } break; + } case SetCooldown: break; case PluginMessageCB: @@ -433,7 +447,7 @@ void GameState::HandleMovement(GameState::Direction direction, float deltaTime) break; case JUMP: if (g_OnGround) { - vel.y += 10; + vel.y += 5; g_OnGround = false; } break; diff --git a/src/NetworkClient.cpp b/src/NetworkClient.cpp index 5877952..027eeb5 100644 --- a/src/NetworkClient.cpp +++ b/src/NetworkClient.cpp @@ -5,7 +5,7 @@ NetworkClient::NetworkClient(std::string address, unsigned short port, std::stri state = Handshaking; PacketHandshake handshake; - handshake.protocolVersion = 335; + handshake.protocolVersion = 338; handshake.serverAddress = address; handshake.serverPort = port; handshake.nextState = 2; @@ -17,6 +17,10 @@ NetworkClient::NetworkClient(std::string address, unsigned short port, std::stri network.SendPacket(loginStart); auto response = std::static_pointer_cast<PacketLoginSuccess>(network.ReceivePacket(Login)); + + while (!response) + response = std::static_pointer_cast<PacketLoginSuccess>(network.ReceivePacket(Login)); + if (response->Username != username) { throw std::logic_error("Received username is not sended username"); } diff --git a/src/Packet.hpp b/src/Packet.hpp index e00f1ed..f71922f 100644 --- a/src/Packet.hpp +++ b/src/Packet.hpp @@ -8,7 +8,6 @@ enum PacketNameLoginSB { }; enum PacketNamePlaySB { TeleportConfirm = 0x00, - PrepareCraftingGrid, TabCompleteSB, ChatMessageSB, ClientStatus, @@ -26,6 +25,7 @@ enum PacketNamePlaySB { PlayerLook, VehicleMoveSB, SteerBoat, + CraftRecipeRequest, PlayerAbilitiesSB, PlayerDigging, EntityAction, @@ -95,6 +95,7 @@ enum PacketNamePlayCB { EntityCB, VehicleMove, OpenSignEditor, + CraftRecipeResponse, PlayerAbilitiesCB, CombatEvent, PlayerListItem, @@ -986,7 +987,7 @@ struct PacketClickWindow : Packet { stream->WriteShort(Slot); stream->WriteByte(Button); stream->WriteShort(ActionNumber); - stream->WriteInt(Mode); + stream->WriteVarInt(Mode); stream->WriteSlot(ClickedItem); } @@ -1023,4 +1024,20 @@ struct PacketCloseWindowSB : Packet { } unsigned char WindowId; +}; + +struct PacketDisconnect : Packet { + void ToStream(StreamOutput *stream) override { + + } + + void FromStream(StreamInput *stream) override { + Reason = stream->ReadChat(); + } + + int GetPacketId() override { + return PacketNameLoginCB::Disconnect; + } + + std::string Reason; };
\ No newline at end of file diff --git a/src/Render.cpp b/src/Render.cpp index 2382ec2..1473ae0 100644 --- a/src/Render.cpp +++ b/src/Render.cpp @@ -153,6 +153,7 @@ void Render::HandleEvents() { SetMouseCapture(false); if (state == GlobalState::Playing) state = GlobalState::Paused; + isDisplayInventory = false; break; } break; @@ -298,8 +299,10 @@ void Render::RenderGui() { ImGui::Text("TPS: %.1f (%.2fms)", 1000.0f/gameTime, gameTime); ImGui::Text("Sections loaded: %d", (int)DebugInfo::totalSections); ImGui::Text("SectionsRenderer: %d (%d)", (int)DebugInfo::renderSections, (int)DebugInfo::readyRenderer); - if (world) + if (world) { ImGui::Text("Player pos: %.1f %.1f %.1f", world->GameStatePtr()->g_PlayerX, world->GameStatePtr()->g_PlayerY, world->GameStatePtr()->g_PlayerZ); + ImGui::Text("Player health: %.1f/%.1f", world->GameStatePtr()->g_PlayerHealth, 20.0f); + } ImGui::End(); @@ -324,25 +327,90 @@ void Render::RenderGui() { break; case GlobalState::Playing: if (isDisplayInventory) { + auto renderSlot = [](const SlotData &slot, int i) -> bool { + return ImGui::Button(((slot.BlockId == -1 ? " ##" : + AssetManager::Instance().GetAssetNameByBlockId(BlockId{ (unsigned short)slot.BlockId,0 }) +" x"+std::to_string(slot.ItemCount) + "##") + + std::to_string(i)).c_str()); + }; ImGui::SetNextWindowPosCenter(); ImGui::Begin("Inventory", 0, windowFlags); Window& inventory = world->GameStatePtr()->playerInventory; - for (int i = 0; i < inventory.slots.size()+1; i++) { - SlotData slot; - if (i == inventory.slots.size()) - slot = inventory.handSlot; - else - slot = inventory.slots[i]; - - if (slot.BlockId == -1) { - ImGui::Button("Empty"); - continue; + //Hand and drop slots + if (renderSlot(inventory.handSlot, -1)) { + + } + ImGui::SameLine(); + if (ImGui::Button("Drop")) { + inventory.MakeClick(-1, true, true); + } + ImGui::SameLine(); + ImGui::Text("Hand slot and drop mode"); + ImGui::Separator(); + //Crafting + if (renderSlot(inventory.slots[1], 1)) { + inventory.MakeClick(1, true); + } + ImGui::SameLine(); + if (renderSlot(inventory.slots[2], 2)) { + inventory.MakeClick(2, true); + } + //Crafting result + ImGui::SameLine(); + ImGui::Text("Result"); + ImGui::SameLine(); + if (renderSlot(inventory.slots[0], 0)) { + inventory.MakeClick(0, true); + } + //Crafting second line + if (renderSlot(inventory.slots[3], 3)) { + inventory.MakeClick(3, true); + } + ImGui::SameLine(); + if (renderSlot(inventory.slots[4], 4)) { + inventory.MakeClick(4, true); + } + ImGui::Separator(); + //Armor and offhand + for (int i = 5; i < 8+1; i++) { + if (renderSlot(inventory.slots[i], i)) { + inventory.MakeClick(i, true); } - std::string slotName = AssetManager::Instance().GetAssetNameByBlockId(BlockId{(unsigned short) slot.BlockId,0 }); - if (ImGui::Button((slotName + "##"+std::to_string(i)).c_str())) { + ImGui::SameLine(); + } + if (renderSlot(inventory.slots[45], 45)) { + inventory.MakeClick(45, true); + } + ImGui::SameLine(); + ImGui::Text("Armor and offhand"); + ImGui::Separator(); + for (int i = 36; i < 44+1; i++) { + if (renderSlot(inventory.slots[i], i)) { + inventory.MakeClick(i, true); + } + ImGui::SameLine(); + } + ImGui::Text("Hotbar"); + ImGui::Separator(); + ImGui::Text("Main inventory"); + for (int i = 9; i < 17 + 1; i++) { + if (renderSlot(inventory.slots[i], i)) { + inventory.MakeClick(i, true); + } + ImGui::SameLine(); + } + ImGui::Text(""); + for (int i = 18; i < 26 + 1; i++) { + if (renderSlot(inventory.slots[i], i)) { + inventory.MakeClick(i, true); + } + ImGui::SameLine(); + } + ImGui::Text(""); + for (int i = 27; i < 35 + 1; i++) { + if (renderSlot(inventory.slots[i], i)) { inventory.MakeClick(i, true); - LOG(INFO) << "Clicked " << slotName << "("<<slot.BlockId<<") in slot " << i; } + ImGui::SameLine(); } ImGui::End(); } diff --git a/src/RendererSection.cpp b/src/RendererSection.cpp index 22acc61..8262cef 100644 --- a/src/RendererSection.cpp +++ b/src/RendererSection.cpp @@ -154,7 +154,7 @@ void swap(RendererSection & lhs, RendererSection & rhs) { void RendererSection::Render(RenderState &renderState) { renderState.SetActiveVao(Vao); - glDrawArraysInstanced(GL_TRIANGLES, 0, 6, numOfFaces); + glDrawArraysInstanced(GL_TRIANGLES, 0, 6, numOfFaces); glCheckError(); } diff --git a/src/RendererWidget.cpp b/src/RendererWidget.cpp deleted file mode 100644 index 6b732e3..0000000 --- a/src/RendererWidget.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include "RendererWidget.hpp" - -const GLfloat vertices[] = { - 0.0f,0.0f,0.0f, - 1.0f,1.0f,0.0f, - 0.0f,1.0f,0.0f, - - 0.0f,0.0f,0.0f, - 1.0f,0.0f,0.0f, - 1.0f,1.0f,0.0f, -}; - -const GLfloat uvs[] = { - 0.0f,0.0f, - 1.0f,1.0f, - 0.0f,1.0f, - - 0.0f,0.0f, - 1.0f,0.0f, - 1.0f,1.0f, -}; - -static GLuint VboVertices, VboUvs, Vao; -static Shader* guiShader = nullptr; - -RendererWidget::RendererWidget(RootWidget *widget) { - this->tree = widget; - - if (guiShader == nullptr) { - guiShader = new Shader("./shaders/gui.vs", "./shaders/gui.fs"); - guiShader->Use(); - glUniform1i(glGetUniformLocation(guiShader->Program, "textureAtlas"), 0); - - glGenBuffers(1, &VboVertices); - glBindBuffer(GL_ARRAY_BUFFER, VboVertices); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); - - glGenBuffers(1, &VboUvs); - glBindBuffer(GL_ARRAY_BUFFER, VboUvs); - glBufferData(GL_ARRAY_BUFFER, sizeof(uvs), uvs, GL_STATIC_DRAW); - - glGenVertexArrays(1, &Vao); - glBindVertexArray(Vao); - { - glBindBuffer(GL_ARRAY_BUFFER, VboVertices); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0); - glEnableVertexAttribArray(0); - - glBindBuffer(GL_ARRAY_BUFFER, VboUvs); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), (GLvoid*)0); - glEnableVertexAttribArray(1); - } - glBindVertexArray(0); - } -} - -RendererWidget::~RendererWidget() { - -} - -void RendererWidget::Render(RenderState &state) { - state.SetActiveVao(Vao); - state.SetActiveShader(guiShader->Program); - - auto toRender = tree->GetRenderList(); - for (auto& it : toRender) { - auto[x, y, w, h] = it->GetTexture(); - glUniform4f(glGetUniformLocation(guiShader->Program, "widgetTexture"), x, y, w, h); - - glUniform4f(glGetUniformLocation(guiShader->Program, "transform"), it->x, it->y, it->w, it->h); - - glDrawArrays(GL_TRIANGLES, 0, 36); - } - - glCheckError(); -}
\ No newline at end of file diff --git a/src/RendererWidget.hpp b/src/RendererWidget.hpp deleted file mode 100644 index a979c88..0000000 --- a/src/RendererWidget.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include "Renderer.hpp" -#include "Widget.hpp" -#include "Shader.hpp" - -class RendererWidget { - RootWidget *tree; - -public: - RendererWidget(RootWidget *widget); - ~RendererWidget(); - - void Render(RenderState &state); -};
\ No newline at end of file diff --git a/src/RendererWorld.cpp b/src/RendererWorld.cpp index 3e5868b..a641cf2 100644 --- a/src/RendererWorld.cpp +++ b/src/RendererWorld.cpp @@ -253,7 +253,7 @@ void RendererWorld::Render(RenderState & renderState) { } double lengthToSection = (VectorF(gs->g_PlayerX, gs->g_PlayerY, gs->g_PlayerZ) - VectorF(section.first.x*16,section.first.y*16,section.first.z*16)).GetLength(); - if (isBreak && lengthToSection > 30.0f && false) { + if (isBreak && lengthToSection > 30.0f) { sectionsMutex.lock(); continue; } diff --git a/src/Stream.cpp b/src/Stream.cpp index 665247d..6f93c9c 100644 --- a/src/Stream.cpp +++ b/src/Stream.cpp @@ -275,7 +275,12 @@ void StreamOutput::WriteSlot(SlotData value) { return; WriteByte(value.ItemCount); WriteShort(value.ItemDamage); - WriteUByte(0); + /*unsigned char nbt[] = { + //0x0a, 0x00, 0x02, 0x68, 0x69, 0x00, + 0x01, 0x04, 0xCA, 0xFE, 0xBA, 0xBE, + }; + WriteByteArray(std::vector<unsigned char>(nbt,nbt + sizeof(nbt)));*/ + WriteByte(0); } void StreamOutput::WriteNbtTag(std::vector<unsigned char> value) { diff --git a/src/Widget.cpp b/src/Widget.cpp deleted file mode 100644 index 1a522ca..0000000 --- a/src/Widget.cpp +++ /dev/null @@ -1,124 +0,0 @@ -#include "Widget.hpp" - -void RootWidget::AttachWidget(std::unique_ptr<Widget> widget, Widget * parent) -{ - parent->childs.push_back(widget.get()); - this->allWidgets.push_back(std::move(widget)); -} - -void RootWidget::AttachWidget(std::unique_ptr<Widget> widget) { - widget->parent = nullptr; - this->childs.push_back(widget.get()); - this->allWidgets.push_back(std::move(widget)); -} - -std::vector<Widget*> RootWidget::GetRenderList() -{ - std::vector<Widget*> renderList; - - std::function<void(Widget*)> treeWalker = [&](Widget* node) { - for (auto it : node->childs) - treeWalker(it); - renderList.push_back(node); - }; - - for (auto& it : this->childs) - treeWalker(it); - - return renderList; -} - -void RootWidget::UpdateEvents(double mouseX, double mouseY, bool mouseButton) { - - LOG(INFO) << mouseX << "x" << mouseY; - - auto testIsHover = [&](double x, double y, Widget* widget) { - bool isOnX = widget->x > x && widget->x + widget->w < x; - bool isOnY = widget->y > y && widget->y + widget->h < y; - if (mouseButton) - LOG(INFO) << "X: " << isOnX << " Y: " << isOnY; - return isOnX && isOnY; - }; - - std::function<void(Widget*)> treeWalker = [&](Widget* node) { - for (auto it : node->childs) - treeWalker(it); - - if (testIsHover(mouseX,mouseY,node)) { - if (node->onHover) - node->onHover(node); - if (mouseButton && !prevBut) - if (node->onPress) - node->onPress(node); - else if (!mouseButton && prevBut) - if (node->onRelease) - node->onRelease(node); - } - else { - if (testIsHover(prevX, prevY, node)) - if (node->onUnhover) - node->onUnhover(node); - } - - if (node->onUpdate) - node->onUpdate(node); - }; - - for (auto it : childs) - treeWalker(it); - - prevX = mouseX; - prevY = mouseY; - prevBut = mouseButton; -} - -WidgetButton::WidgetButton() -{ - this->state = WidgetState::Idle; - - onHover = [](Widget* widget) { - WidgetButton* w = dynamic_cast<WidgetButton*>(widget); - if (w->state != WidgetState::Pressed) - w->state = WidgetState::Hovering; - LOG(INFO) << "Hover"; - }; - - onPress = [](Widget* widget) { - WidgetButton* w = dynamic_cast<WidgetButton*>(widget); - w->state = WidgetState::Pressed; - LOG(INFO) << "Press"; - }; - - onRelease = [](Widget* widget) { - WidgetButton* w = dynamic_cast<WidgetButton*>(widget); - w->state = WidgetState::Idle; - w->onClick(w); - LOG(INFO) << "Release"; - }; - - onUnhover = [](Widget *widget) { - WidgetButton* w = dynamic_cast<WidgetButton*>(widget); - if (w->state!=WidgetState::Pressed) - w->state = WidgetState::Idle; - LOG(INFO) << "Unhover"; - }; - -} - -std::tuple<double, double, double, double> WidgetButton::GetTexture() -{ - double yOffset; - switch (this->state) { - case WidgetState::Idle: - yOffset = 0.2578; - break; - case WidgetState::Hovering: - yOffset = 0.3359; - break; - case WidgetState::Pressed: - yOffset = 0.1796; - } - - TextureCoordinates texture = AssetManager::Instance().GetTextureByAssetName("minecraft/textures/gui/widgets"); - return { texture.x,texture.y + texture.h * yOffset,texture.w * 0.7812,texture.h * 0.07812 }; -} diff --git a/src/Widget.hpp b/src/Widget.hpp deleted file mode 100644 index 6d78ebe..0000000 --- a/src/Widget.hpp +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once - -#include <vector> -#include <memory> -#include <functional> - -#include "AssetManager.hpp" - -class Widget; -class RootWidget { - std::vector<std::unique_ptr<Widget>> allWidgets; - - std::vector<Widget*> childs; - - double prevX, prevY; - bool prevBut; -public: - RootWidget() = default; - - ~RootWidget() = default; - - void AttachWidget(std::unique_ptr<Widget> widget, Widget* parent); - - void AttachWidget(std::unique_ptr<Widget> widget); - - std::vector<Widget*> GetRenderList(); - - void UpdateEvents(double mouseX, double mouseY, bool mouseButton); -}; - -struct Widget { - Widget() = default; - - virtual ~Widget() = default; - - Widget *parent; - - std::vector<Widget*> childs; - - double x, y, w, h; //In OGL screen-coordinates - - virtual std::tuple<double, double, double, double> GetTexture() = 0; - - - using Handler = std::function<void(Widget*)>; - - Handler onPress; - - Handler onRelease; - - Handler onHover; - - Handler onUnhover; - - Handler onUpdate; -}; - -struct WidgetButton : Widget { - WidgetButton(); - - ~WidgetButton() override = default; - - std::string Text; - - Handler onClick; - - std::tuple<double, double, double, double> GetTexture() override; - - enum class WidgetState { - Idle, - Hovering, - Pressed, - } state; -};
\ No newline at end of file diff --git a/src/Window.cpp b/src/Window.cpp index fbf9aaa..f3ad6d5 100644 --- a/src/Window.cpp +++ b/src/Window.cpp @@ -1,6 +1,32 @@ #include "Window.hpp" -void Window::MakeClick(short ClickedSlot, bool Lmb) { - PacketClickWindow packet(WindowId, ClickedSlot, Lmb? 0 : 1, actions++, 0, slots[ClickedSlot]); - this->pendingTransactions.push(packet); +void Window::MakeClick(short ClickedSlot, bool Lmb, bool dropMode) { + if (!dropMode) { + PacketClickWindow packet(WindowId, ClickedSlot, Lmb ? 0 : 1, actions++, 0, slots[ClickedSlot]); + this->pendingTransactions.push(packet); + std::swap(slots[ClickedSlot], handSlot); + transactions.push_back(std::make_pair(actions, std::make_pair(ClickedSlot, -1))); + } else { + PacketClickWindow packet(WindowId, ClickedSlot, Lmb ? 0 : 1, actions++, 0, SlotData()); + this->pendingTransactions.push(packet); + transactions.push_back(std::make_pair(actions, std::make_pair(ClickedSlot, -1))); + } +} + +void Window::ConfirmTransaction(PacketConfirmTransactionCB packet) { + if (!packet.Accepted) { + throw std::logic_error("Transaction failed"); + } + /*auto toDelete = transactions.begin(); + for (auto it = transactions.begin(); it != transactions.end(); ++it) { + if (it->first == packet.ActionNumber) { + toDelete = it; + if (!packet.Accepted) { + std::swap(slots[std::get<0>(it->second)], slots[std::get<1>(it->second)]); + } + break; + } + } + if (toDelete->first == packet.ActionNumber) + transactions.erase(toDelete);*/ }
\ No newline at end of file diff --git a/src/Window.hpp b/src/Window.hpp index 4dae294..a6bccd9 100644 --- a/src/Window.hpp +++ b/src/Window.hpp @@ -8,13 +8,17 @@ struct Window { unsigned char WindowId = 0; std::string type; - + SlotData handSlot; + const short HandSlotId = -1; std::vector<SlotData> slots; short actions = 1; - void MakeClick(short ClickedSlot, bool Lmb); + void MakeClick(short ClickedSlot, bool Lmb, bool dropMode = false); std::queue<PacketClickWindow> pendingTransactions; + std::vector<std::pair<short,std::pair<short,short>>> transactions; + + void ConfirmTransaction(PacketConfirmTransactionCB packet); };
\ No newline at end of file diff --git a/src/World.cpp b/src/World.cpp index 5b4bb03..8cff53a 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -173,7 +173,8 @@ void World::AddEntity(Entity entity) entitiesMutex.lock(); for (auto& it : entities) { if (it.entityId == entity.entityId) { - LOG(ERROR) << "Adding already existing entity" << entity.entityId; + LOG(ERROR) << "Adding already existing entity: " << entity.entityId; + entitiesMutex.unlock(); return; } } |