Botcraft 1.21.4
Loading...
Searching...
No Matches
RenderingManager.cpp
Go to the documentation of this file.
2
3#include <glad/glad.h>
4#include <GLFW/glfw3.h>
5
6#include <glm/glm.hpp>
7#include <glm/gtc/type_ptr.hpp>
8
9#ifdef USE_IMGUI
10#include <imgui.h>
11#include <imgui_impl_glfw.h>
12#include <imgui_impl_opengl3.h>
13#endif
14
15
24
28
32
35
38
39const std::vector<float> color_day({ 0.6f, 0.85f, 0.9f });
40const std::vector<float> color_night({0.1f, 0.1f, 0.1f});
41
42namespace Botcraft
43{
44 namespace Renderer
45 {
46 RenderingManager::RenderingManager(std::shared_ptr<World> world_, std::shared_ptr<InventoryManager> inventory_manager_,
47 std::shared_ptr<EntityManager> entity_manager_,
48 const unsigned int& window_width, const unsigned int& window_height,
49 const unsigned int section_height_, const bool headless)
50 {
51 world = world_;
52 inventory_manager = inventory_manager_;
53 entity_manager = entity_manager_;
54 local_player = nullptr;
55
56 for (int i = 0; i < is_key_pressed.size(); ++i)
57 {
58 is_key_pressed[i] = false;
59 }
60
61 inventory_open = false;
62 behaviour_open = false;
63 behaviour_renderer = std::make_unique<BehaviourRenderer>();
64
65 mouse_last_x = window_width / 2.0f;
66 mouse_last_y = window_height / 2.0f;
67 first_mouse = true;
68
69 deltaTime = 0.0f;
70 lastFrameTime = 0.0f;
71
72 current_window_width = window_width;
73 current_window_height = window_height;
74 has_proj_changed = true;
75
76 MouseCallback = [](double, double) {};
77 KeyboardCallback = [](std::array<bool, static_cast<int>(KEY_CODE::NUMBER_OF_KEYS)>, double) {};
78
79 world_renderer = std::make_unique<WorldRenderer>(section_height_);
80
81 take_screenshot = false;
82
83 day_time = 0.0f;
84
85 running = true;
86 rendering_thread = std::thread(&RenderingManager::Run, this, headless);
88 }
89
91 {
92 MouseCallback = [](double, double) {};
93 KeyboardCallback = [](std::array<bool, static_cast<int>(KEY_CODE::NUMBER_OF_KEYS)>, double) {};
94
95 running = false;
96
97 condition_update.notify_all();
98 if (thread_updating_renderable.joinable())
99 {
101 }
102
103 if (rendering_thread.joinable())
104 {
105 rendering_thread.join();
106 }
107 }
108
109 void RenderingManager::Run(const bool headless)
110 {
111 Logger::GetInstance().RegisterThread("RenderingLoop");
112 if (!Init(headless))
113 {
114 LOG_ERROR("Can't init rendering manager");
115 return;
116 }
117
118 my_shader->Use();
119 float real_fps = 1.0f;
120
121 while (!glfwWindowShouldClose(window))
122 {
123 double currentFrame = glfwGetTime();
124 auto start = std::chrono::steady_clock::now();
125
126 //Max 60 FPS
127 auto end = start + std::chrono::microseconds(1000000 / 60);
128
129 deltaTime = currentFrame - lastFrameTime;
130 lastFrameTime = currentFrame;
131
133
135 {
136#ifdef USE_IMGUI
137 ImGui_ImplOpenGL3_NewFrame();
138 ImGui_ImplGlfw_NewFrame();
139 ImGui::NewFrame();
140
141 {
142 if (local_player == nullptr)
143 {
144 local_player = entity_manager->GetLocalPlayer();
145 }
146 ImGui::SetNextWindowPos(ImVec2(0, 0));
147 ImGui::SetNextWindowSize(ImVec2(290, 70));
148 const Vector3<double> position = local_player == nullptr ? Vector3<double>(0.0) : local_player->GetPosition();
149 ImGui::Begin("Position", nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse);
150 ImGui::Text("%f, %f, %f", position.x, position.y, position.z);
151 ImGui::Text("Yaw: %f || ", local_player == nullptr ? 0.0 : local_player->GetYaw());
152 ImGui::SameLine();
153 ImGui::Text("Pitch: %f", local_player == nullptr ? 0.0 : local_player->GetPitch());
154 ImGui::End();
155 }
156 {
157 ImGui::SetNextWindowPos(ImVec2(0, 75));
158 ImGui::SetNextWindowSize(ImVec2(290, 70));
159 ImGui::Begin("Targeted cube", nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse);
160 Position raycasted_pos;
161 Position raycasted_normal;
162 const Blockstate* raycasted_blockstate =
163 world->Raycast(Vector3<double>(world_renderer->GetCamera()->GetPosition().x, world_renderer->GetCamera()->GetPosition().y, world_renderer->GetCamera()->GetPosition().z),
164 Vector3<double>(world_renderer->GetCamera()->GetFront().x, world_renderer->GetCamera()->GetFront().y, world_renderer->GetCamera()->GetFront().z),
165 6.0f, raycasted_pos, raycasted_normal);
166 if (raycasted_blockstate != nullptr)
167 {
168 ImGui::Text("Watching block at %i, %i, %i", raycasted_pos.x, raycasted_pos.y, raycasted_pos.z);
169 ImGui::Text("Block: %s", raycasted_blockstate->GetName().c_str());
170 if (ImGui::IsItemHovered(ImGuiHoveredFlags_::ImGuiHoveredFlags_AllowWhenDisabled))
171 {
172 ImGui::BeginTooltip();
173
174 ImGui::Text("Air: "); ImGui::SameLine(); raycasted_blockstate->IsAir() ? ImGui::TextColored(ImVec4(0.0, 1.0, 0.0, 1.0), "1") : ImGui::TextColored(ImVec4(1.0, 0.0, 0.0, 1.0), "0");
175 ImGui::Text("Solid: "); ImGui::SameLine(); raycasted_blockstate->IsSolid() ? ImGui::TextColored(ImVec4(0.0, 1.0, 0.0, 1.0), "1") : ImGui::TextColored(ImVec4(1.0, 0.0, 0.0, 1.0), "0");
176 ImGui::Text("Transparent: "); ImGui::SameLine(); raycasted_blockstate->IsTransparent() ? ImGui::TextColored(ImVec4(0.0, 1.0, 0.0, 1.0), "1") : ImGui::TextColored(ImVec4(1.0, 0.0, 0.0, 1.0), "0");
177 ImGui::Text("Lava: "); ImGui::SameLine(); raycasted_blockstate->IsLava() ? ImGui::TextColored(ImVec4(0.0, 1.0, 0.0, 1.0), "1") : ImGui::TextColored(ImVec4(1.0, 0.0, 0.0, 1.0), "0");
178 ImGui::Text("Water: "); ImGui::SameLine(); raycasted_blockstate->IsWater() ? ImGui::TextColored(ImVec4(0.0, 1.0, 0.0, 1.0), "1") : ImGui::TextColored(ImVec4(1.0, 0.0, 0.0, 1.0), "0");
179 ImGui::Text("Waterlogged: "); ImGui::SameLine(); raycasted_blockstate->IsWaterlogged() ? ImGui::TextColored(ImVec4(0.0, 1.0, 0.0, 1.0), "1") : ImGui::TextColored(ImVec4(1.0, 0.0, 0.0, 1.0), "0");
180 ImGui::Text("Fluid Falling: "); ImGui::SameLine(); raycasted_blockstate->IsFluidFalling() ? ImGui::TextColored(ImVec4(0.0, 1.0, 0.0, 1.0), "1") : ImGui::TextColored(ImVec4(1.0, 0.0, 0.0, 1.0), "0");
181 ImGui::Text("Climbable: "); ImGui::SameLine(); raycasted_blockstate->IsClimbable() ? ImGui::TextColored(ImVec4(0.0, 1.0, 0.0, 1.0), "1") : ImGui::TextColored(ImVec4(1.0, 0.0, 0.0, 1.0), "0");
182 ImGui::Text("Hazardous: "); ImGui::SameLine(); raycasted_blockstate->IsHazardous() ? ImGui::TextColored(ImVec4(0.0, 1.0, 0.0, 1.0), "1") : ImGui::TextColored(ImVec4(1.0, 0.0, 0.0, 1.0), "0");
183 ImGui::Text("Slime: "); ImGui::SameLine(); raycasted_blockstate->IsSlime() ? ImGui::TextColored(ImVec4(0.0, 1.0, 0.0, 1.0), "1") : ImGui::TextColored(ImVec4(1.0, 0.0, 0.0, 1.0), "0");
184 ImGui::Text("Bed: "); ImGui::SameLine(); raycasted_blockstate->IsBed() ? ImGui::TextColored(ImVec4(0.0, 1.0, 0.0, 1.0), "1") : ImGui::TextColored(ImVec4(1.0, 0.0, 0.0, 1.0), "0");
185 ImGui::Text("Soul Sand: "); ImGui::SameLine(); raycasted_blockstate->IsSoulSand() ? ImGui::TextColored(ImVec4(0.0, 1.0, 0.0, 1.0), "1") : ImGui::TextColored(ImVec4(1.0, 0.0, 0.0, 1.0), "0");
186 ImGui::Text("Honey: "); ImGui::SameLine(); raycasted_blockstate->IsHoney() ? ImGui::TextColored(ImVec4(0.0, 1.0, 0.0, 1.0), "1") : ImGui::TextColored(ImVec4(1.0, 0.0, 0.0, 1.0), "0");
187 ImGui::Text("Scaffolding: "); ImGui::SameLine(); raycasted_blockstate->IsScaffolding() ? ImGui::TextColored(ImVec4(0.0, 1.0, 0.0, 1.0), "1") : ImGui::TextColored(ImVec4(1.0, 0.0, 0.0, 1.0), "0");
188 ImGui::Text("Cobweb: "); ImGui::SameLine(); raycasted_blockstate->IsCobweb() ? ImGui::TextColored(ImVec4(0.0, 1.0, 0.0, 1.0), "1") : ImGui::TextColored(ImVec4(1.0, 0.0, 0.0, 1.0), "0");
189 ImGui::Text("UpBubbleColumn: "); ImGui::SameLine(); raycasted_blockstate->IsUpBubbleColumn() ? ImGui::TextColored(ImVec4(0.0, 1.0, 0.0, 1.0), "1") : ImGui::TextColored(ImVec4(1.0, 0.0, 0.0, 1.0), "0");
190 ImGui::Text("DownBubbleColumn: "); ImGui::SameLine(); raycasted_blockstate->IsDownBubbleColumn() ? ImGui::TextColored(ImVec4(0.0, 1.0, 0.0, 1.0), "1") : ImGui::TextColored(ImVec4(1.0, 0.0, 0.0, 1.0), "0");
191 ImGui::Text("Berry Bush: "); ImGui::SameLine(); raycasted_blockstate->IsBerryBush() ? ImGui::TextColored(ImVec4(0.0, 1.0, 0.0, 1.0), "1") : ImGui::TextColored(ImVec4(1.0, 0.0, 0.0, 1.0), "0");
192 ImGui::Text("Powder Snow: "); ImGui::SameLine(); raycasted_blockstate->IsPowderSnow() ? ImGui::TextColored(ImVec4(0.0, 1.0, 0.0, 1.0), "1") : ImGui::TextColored(ImVec4(1.0, 0.0, 0.0, 1.0), "0");
193 ImGui::Text("Fluid Height: "); ImGui::SameLine(); ImGui::TextUnformatted(std::to_string(raycasted_blockstate->GetFluidHeight()).data());
194 ImGui::Text("Hardness: "); ImGui::SameLine(); ImGui::TextUnformatted(std::to_string(raycasted_blockstate->GetHardness()).data());
195 ImGui::Text("Friction: "); ImGui::SameLine(); ImGui::TextUnformatted(std::to_string(raycasted_blockstate->GetFriction()).data());
196
197 ImGui::EndTooltip();
198 }
199 }
200 else
201 {
202 ImGui::Text("Watching block at");
203 ImGui::Text("Block: ");
204 }
205 ImGui::End();
206 }
207#endif
208 const float current_day_time = day_time;
209 std::vector<float> current_color(3);
210 for (int i = 0; i < 3; ++i)
211 {
212 current_color[i] = 2.0f * ((0.5f - std::abs(current_day_time - 0.5f)) * color_day[i] + (0.5f - std::min(std::abs(1.0f - current_day_time), current_day_time)) * color_night[i]);
213 }
214 glClearColor(current_color[0], current_color[1], current_color[2], 1.0f);
215 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
216
217 //Change view matrix
218 world_renderer->UpdateViewMatrix();
219
221 {
222 glm::mat4 projection = glm::perspective(glm::radians(45.0f), current_window_width / static_cast<float>(current_window_height), 0.1f, 200.0f);
223 my_shader->SetMat4("projection", projection);
224 world_renderer->SetCameraProjection(projection);
225 has_proj_changed = false;
226 }
227
228 world_renderer->UpdateFaces();
229
230 my_shader->Use();
231
232 //Draw all faces
233 world_renderer->UseAtlasTextureGL();
234
235#ifdef USE_IMGUI
236 int num_chunks, num_rendered_chunks, num_entities, num_rendered_entities, num_faces, num_rendered_faces;
237 world_renderer->RenderFaces(&num_chunks, &num_rendered_chunks, &num_entities, &num_rendered_entities, &num_faces, &num_rendered_faces);
238 {
239 ImGui::SetNextWindowPos(ImVec2(static_cast<float>(current_window_width), 0.0f), 0, ImVec2(1.0f, 0.0f));
240 ImGui::SetNextWindowSize(ImVec2(180.0f, 170.0f));
241 ImGui::Begin("Rendering", nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse);
242 ImGui::Text("Lim. FPS: %.1f (%.2fms)", 1.0 / deltaTime, deltaTime * 1000.0);
243 ImGui::Text("Real FPS: %.1f (%.2fms)", 1.0 / real_fps, real_fps * 1000.0);
244 ImGui::Text("Loaded sections: %i", num_chunks);
245 ImGui::Text("Rendered sections: %i", num_rendered_chunks);
246 ImGui::Text("Num entities: %i", num_entities);
247 ImGui::Text("Rendered entities: %i", num_rendered_entities);
248 ImGui::Text("Loaded faces: %i", num_faces);
249 ImGui::Text("Rendered faces: %i", num_rendered_faces);
250 ImGui::End();
251 }
252#else
253 world_renderer->RenderFaces();
254#endif
255
256 glBindVertexArray(0);
257 glBindTexture(GL_TEXTURE_2D, 0);
258
259#ifdef USE_IMGUI
260 // Draw the behaviour if it's open
261 if (behaviour_open)
262 {
263 const int blackboard_width = static_cast<int>((static_cast<float>(current_window_width) - 30.0f) / 4.0f);
264
265 ImGui::SetNextWindowPos(ImVec2(15.0f, 15.0f), 0, ImVec2(0.0f, 0.0f));
266 ImGui::SetNextWindowSize(ImVec2(blackboard_width, current_window_height - 30.0f));
267 ImGui::Begin("Blackboard", nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_NoCollapse);
268 behaviour_renderer->RenderBlackboard();
269 ImGui::End();
270
271 ImGui::SetNextWindowPos(ImVec2(15.0f + blackboard_width, 15.0f), 0, ImVec2(0.0f, 0.0f));
272 ImGui::SetNextWindowSize(ImVec2(current_window_width - blackboard_width - 30.0f, current_window_height - 30.0f));
273 ImGui::Begin("Behaviour", nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse);
274 behaviour_renderer->RenderNodes();
275 ImGui::End();
276 }
277
278 // Draw the inventory if it's open
279 if (inventory_open)
280 {
281 ImGui::SetNextWindowPos(ImVec2(static_cast<float>(current_window_width), static_cast<float>(current_window_height)), 0, ImVec2(1.0f, 1.0f));
282 ImGui::SetNextWindowSize(ImVec2(300.0f, current_window_height - 175.0f));
283 ImGui::Begin("Inventory", nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse);
284 if (inventory_manager && inventory_manager->GetPlayerInventory())
285 {
286 const std::map<short, ProtocolCraft::Slot>& slots = inventory_manager->GetPlayerInventory()->GetSlots();
287 for (short i = 0; i <= Window::INVENTORY_OFFHAND_INDEX; ++i)
288 {
289 auto it = slots.find(i);
290 if (it == slots.end())
291 {
292 continue;
293 }
295 {
296 ImGui::Text("Crafting output");
297 }
299 {
300 ImGui::Text("Crafting input");
301 }
302 else if (i == Window::INVENTORY_ARMOR_START)
303 {
304 ImGui::Text("Equiped Armor");
305 }
307 {
308 ImGui::Text("Inventory");
309 }
310 else if (i == Window::INVENTORY_HOTBAR_START)
311 {
312 ImGui::Text("Hotbar");
313 }
315 {
316 ImGui::Text("Offhand");
317 }
318 const std::string name = AssetsManager::getInstance().Items().at(it->second.GetItemId())->GetName();
319 if (name != "minecraft:air")
320 {
321 ImGui::Text(std::string(" (%i) " + name + " (x%i)").c_str(), i, it->second.GetItemCount());
322 }
323 }
324 }
325 ImGui::End();
326 }
327
328
329 ImGui::Render();
330
331 // Render ImGui
332 ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
333#endif
334 }
335
336 glfwSwapBuffers(window);
337 glfwPollEvents();
338
339 if (take_screenshot)
340 {
341 std::vector<unsigned char> pixels(current_window_height * current_window_width * 3);
342 glReadPixels(0, 0, current_window_width, current_window_height, GL_RGB, GL_UNSIGNED_BYTE, pixels.data());
343
345 take_screenshot = false;
346 }
347
348 real_fps = static_cast<float>(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - start).count() / 1e6);
349
350 //Wait to have 60 FPS
352 }
353
354 world_renderer.reset();
355 my_shader.reset();
356
357#ifdef USE_IMGUI
358 behaviour_renderer->CleanUp();
359 // ImGui cleaning
360 ImGui_ImplOpenGL3_Shutdown();
361 ImGui_ImplGlfw_Shutdown();
362 ImGui::DestroyContext();
363#endif
364
365 glfwDestroyWindow(window);
366 glfwTerminate();
367 }
368
370 {
371 glfwSetWindowShouldClose(window, true);
372 running = false;
373 }
374
375 void RenderingManager::SetMouseCallback(std::function<void(double, double)> callback)
376 {
377 MouseCallback = callback;
378 }
379
380 void RenderingManager::SetKeyboardCallback(std::function<void(std::array<bool, static_cast<int>(KEY_CODE::NUMBER_OF_KEYS)>, double)> callback)
381 {
382 KeyboardCallback = callback;
383 }
384
385 void RenderingManager::Screenshot(const std::string& path)
386 {
387 screenshot_path = path;
388 take_screenshot = true;
389 }
390
392 {
393 behaviour_renderer->SetCurrentBehaviourTree(root);
394 }
395
397 {
398 behaviour_renderer->ResetBehaviourState();
399 }
400
402 {
403 behaviour_renderer->BehaviourStartTick();
404 }
405
406 void RenderingManager::BehaviourEndTick(const bool b) const
407 {
408 behaviour_renderer->BehaviourEndTick(b);
409 }
410
411 void RenderingManager::BehaviourTickChild(const size_t i) const
412 {
413 behaviour_renderer->BehaviourTickChild(i);
414 }
415
417 {
418 return behaviour_renderer->IsBehaviourPaused();
419 }
420
422 {
423 behaviour_renderer->ResetBlackboard();
424 }
425
426 void RenderingManager::UpdateBlackboardValue(const std::string& key, const std::any& value) const
427 {
428 behaviour_renderer->UpdateBlackboardValue(key, value);
429 }
430
431 void RenderingManager::RemoveBlackboardValue(const std::string& key) const
432 {
433 behaviour_renderer->RemoveBlackboardValue(key);
434 }
435
436 bool RenderingManager::Init(const bool headless)
437 {
438 glfwInit();
439 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
440 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
441 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
442#ifdef __APPLE__
443 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
444#endif
445
446 if (headless)
447 {
448 glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
449 }
450
451 window = glfwCreateWindow(current_window_width, current_window_height, "RenderingManager", NULL, NULL);
452 if (window == NULL)
453 {
454 LOG_ERROR("Failed to create GLFW window");
455 glfwTerminate();
456 return false;
457 }
458 glfwMakeContextCurrent(window);
459 //set the user pointer of the window to this object to pass it to the callbacks
460 glfwSetWindowUserPointer(window, this);
461 glfwSetFramebufferSizeCallback(window, &RenderingManager::ResizeCallback);
462 glfwSetCursorPosCallback(window, &RenderingManager::InternalMouseCallback);
463
464 glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
465
466 // glad: load all OpenGL function pointers
467 // ---------------------------------------
468 if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
469 {
470 LOG_ERROR("Failed to initialize GLAD");
471 return false;
472 }
473
474#ifdef USE_IMGUI
475 // imgui: setup context
476 // ---------------------------------------
477 IMGUI_CHECKVERSION();
478 ImGui::CreateContext();
479
480 behaviour_renderer->Init();
481
482 ImGuiIO& io = ImGui::GetIO();
483 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
484
485 // Style
486 ImGui::StyleColorsDark();
487
488 // Setup platform/renderer
489 ImGui_ImplGlfw_InitForOpenGL(window, true);
490 ImGui_ImplOpenGL3_Init("#version 330");
491#endif
492
493 my_shader = std::make_unique<Shader>();
494
495 glEnable(GL_DEPTH_TEST);
496 //glEnable(GL_CULL_FACE);
497 glEnable(GL_BLEND);
498 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
499
500 //Set an uniform buffer for view matrix
501 unsigned int uniform_view_block_index = glGetUniformBlockIndex(my_shader->Program(), "MatriceView");
502 glUniformBlockBinding(my_shader->Program(), uniform_view_block_index, 0);
503
504 world_renderer->InitGL();
505
506 return true;
507 }
508
509 void RenderingManager::ResizeCallback(GLFWwindow *window, int width, int height)
510 {
511 RenderingManager *this_object = static_cast<RenderingManager*>(glfwGetWindowUserPointer(window));
512 this_object->current_window_width = width;
513 this_object->current_window_height = height;
514 glViewport(0, 0, width, height);
515 this_object->has_proj_changed = true;
516 }
517
518 void RenderingManager::InternalMouseCallback(GLFWwindow *window, double xpos, double ypos)
519 {
520 RenderingManager *this_object = static_cast<RenderingManager*>(glfwGetWindowUserPointer(window));
521
522 if (this_object->first_mouse)
523 {
524 this_object->mouse_last_x = xpos;
525 this_object->mouse_last_y = ypos;
526 this_object->first_mouse = false;
527 }
528
529 double xoffset = xpos - this_object->mouse_last_x;
530 double yoffset = this_object->mouse_last_y - ypos;
531
532 this_object->mouse_last_x = xpos;
533 this_object->mouse_last_y = ypos;
534
535 if (this_object->inventory_open || this_object->behaviour_open)
536 {
537 return;
538 }
539
540 this_object->MouseCallback(xoffset, yoffset);
541 }
542
544 {
545 is_key_pressed[static_cast<int>(KEY_CODE::FORWARD)] = glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS;
546 is_key_pressed[static_cast<int>(KEY_CODE::BACKWARD)] = glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS;
547 is_key_pressed[static_cast<int>(KEY_CODE::RIGHT)] = glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS;
548 is_key_pressed[static_cast<int>(KEY_CODE::LEFT)] = glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS;
549 is_key_pressed[static_cast<int>(KEY_CODE::SPACE)] = glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS;
550 is_key_pressed[static_cast<int>(KEY_CODE::SHIFT)] = glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS;
551 is_key_pressed[static_cast<int>(KEY_CODE::CTRL)] = glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS;
552 is_key_pressed[static_cast<int>(KEY_CODE::ESC)] = glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS;
553 is_key_pressed[static_cast<int>(KEY_CODE::MOUSE_LEFT)] = glfwGetKey(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS;
554 const bool is_inventory_key_pressed = glfwGetKey(window, GLFW_KEY_E) == GLFW_PRESS;
555
556 // Toggle inventory if E was not pressed during previous frame and is during this one
557 const bool toggle_inventory = (!is_key_pressed[static_cast<int>(KEY_CODE::INVENTORY)] && is_inventory_key_pressed);
558 // Save current value just like others
559 is_key_pressed[static_cast<int>(KEY_CODE::INVENTORY)] = is_inventory_key_pressed;
560
561
562 const bool is_behaviour_key_pressed = glfwGetKey(window, GLFW_KEY_B) == GLFW_PRESS;
563
564 // Toggle behaviour if B was not pressed during previous frame and is during this one
565 const bool toggle_behaviour = (!is_key_pressed[static_cast<int>(KEY_CODE::BEHAVIOUR)] && is_behaviour_key_pressed);
566 // Save current value just like others
567 is_key_pressed[static_cast<int>(KEY_CODE::BEHAVIOUR)] = is_behaviour_key_pressed;
568
569#ifdef USE_IMGUI
570 if (toggle_inventory)
571 {
573 }
574
575 if (toggle_behaviour)
576 {
578 }
579
581 {
582 glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
583 }
584 else
585 {
586 glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
587 }
588#endif
589
590 if (glfwGetKey(window, GLFW_KEY_F2) == GLFW_PRESS)
591 {
592 screenshot_path = "screenshot.png";
593 take_screenshot = true;
594 }
595
597 }
598
599 void RenderingManager::AddChunkToUpdate(const int x, const int z)
600 {
601 const std::vector<Position> chunk_pos = { {Position(x, 0, z), Position(x - 1, 0, z),
602 Position(x + 1, 0 , z), Position(x, 0, z - 1), Position(x, 0, z + 1)} };
603
604 std::lock_guard<std::mutex> guard_rendering(mutex_updating);
605 for (int i = 0; i < chunk_pos.size(); ++i)
606 {
607 chunks_to_udpate.insert(chunk_pos[i]);
608 }
609 condition_update.notify_all();
610 }
611
613 {
614 std::lock_guard<std::mutex> guard_rendering(mutex_updating);
615 entities_to_update.insert(id);
616 condition_update.notify_all();
617 }
618
619 void RenderingManager::SetPosOrientation(const double x_, const double y_, const double z_, const float yaw_, const float pitch_)
620 {
621 if (world_renderer)
622 {
623 world_renderer->SetPosOrientation(x_, y_, z_, yaw_, pitch_);
624 }
625 }
626
628 {
629 Logger::GetInstance().RegisterThread("RenderingDataUpdate");
630 while (running)
631 {
632 {
633 std::unique_lock<std::mutex> lck(mutex_updating);
634 condition_update.wait(lck);
635 }
636
637 while (!chunks_to_udpate.empty())
638 {
639 Position pos;
640 mutex_updating.lock();
641 if (!chunks_to_udpate.empty())
642 {
643 auto posIterator = chunks_to_udpate.begin();
644 pos = *posIterator;
645 chunks_to_udpate.erase(posIterator);
646 }
647 mutex_updating.unlock();
648
649 std::optional<Botcraft::Chunk> chunk;
650 // Get the new values in the world
651 bool has_chunk_been_modified = world->HasChunkBeenModified(pos.x, pos.z);
652 if (has_chunk_been_modified)
653 {
654 chunk = world->ResetChunkModificationState(pos.x, pos.z);
655 }
656
657 if (has_chunk_been_modified)
658 {
659 world_renderer->UpdateChunk(pos.x, pos.z, chunk);
660 }
661
662 // If we left the game, we don't need to process
663 // the rest of the data, just discard them
664 if (!running)
665 {
666 mutex_updating.lock();
667 chunks_to_udpate.clear();
668 mutex_updating.unlock();
669 break;
670 }
671 }
672
673 while (!entities_to_update.empty())
674 {
675 int entity_id = -1;
676 mutex_updating.lock();
677 if (!entities_to_update.empty())
678 {
679 auto eid_it = entities_to_update.begin();
680 entity_id = *eid_it;
681 entities_to_update.erase(eid_it);
682 }
683 mutex_updating.unlock();
684
685 std::vector<Face> faces;
686 // Get the new values
687 std::shared_ptr<Botcraft::Entity> entity = entity_manager->GetEntity(entity_id);
688 bool should_update = false;
689 if (entity == nullptr)
690 {
691 should_update = true;
692 }
693 else if (!entity->GetAreRenderedFacesUpToDate())
694 {
695 faces = entity->GetFaces(true);
696 should_update = true;
697 }
698
699 if (should_update)
700 {
701 world_renderer->UpdateEntity(entity_id, faces);
702 }
703
704 // If we left the game, we don't need to process
705 // the rest of the data, just discard them
706 if (!running)
707 {
708 mutex_updating.lock();
709 entities_to_update.clear();
710 mutex_updating.unlock();
711 break;
712 }
713 }
714 }
715 }
716
717 /*
718 * Packet handling methods
719 */
720
722 {
723 Position chunk_coords = Botcraft::Chunk::BlockCoordsToChunkCoords(msg.GetPos());
724 AddChunkToUpdate(chunk_coords.x, chunk_coords.z);
725 }
726
728 {
729#if PROTOCOL_VERSION < 737 /* < 1.16.2 */
730 AddChunkToUpdate(msg.GetChunkX(), msg.GetChunkZ());
731#else
732 AddChunkToUpdate(msg.GetSectionPos() >> 42, msg.GetSectionPos() << 22 >> 42);
733#endif
734 }
735
737 {
738#if PROTOCOL_VERSION < 764 /* < 1.20.2 */
739 AddChunkToUpdate(msg.GetX(), msg.GetZ());
740#else
741 AddChunkToUpdate(msg.GetPos().GetX(), msg.GetPos().GetZ());
742#endif
743 }
744
745#if PROTOCOL_VERSION < 757 /* < 1.18 */
746 void RenderingManager::Handle(ProtocolCraft::ClientboundLevelChunkPacket& msg)
747#else
749#endif
750 {
751 AddChunkToUpdate(msg.GetX(), msg.GetZ());
752 }
753
758
759#if PROTOCOL_VERSION < 759 /* < 1.19 */
760 void RenderingManager::Handle(ProtocolCraft::ClientboundAddMobPacket& msg)
761 {
762 AddEntityToUpdate(msg.GetEntityId());
763 }
764#endif
765
766#if PROTOCOL_VERSION < 721 /* < 1.16 */
767 void RenderingManager::Handle(ProtocolCraft::ClientboundAddGlobalEntityPacket& msg)
768 {
769 AddEntityToUpdate(msg.GetEntityId());
770 }
771#endif
772
773#if PROTOCOL_VERSION < 764 /* < 1.20.2 */
774 void RenderingManager::Handle(ProtocolCraft::ClientboundAddPlayerPacket& msg)
775 {
776 AddEntityToUpdate(msg.GetEntityId());
777 }
778#endif
779
784
785#if PROTOCOL_VERSION < 755 /* < 1.17 */
786 void RenderingManager::Handle(ProtocolCraft::ClientboundMoveEntityPacket& msg)
787 {
788 AddEntityToUpdate(msg.GetEntityId());
789 }
790#endif
791
796
801
806
808 {
809 std::shared_ptr<LocalPlayer> local_player = entity_manager->GetLocalPlayer();
810 if (local_player != nullptr && local_player->GetEntityID() == msg.GetEntityId())
811 {
812 return;
813 }
814 AddEntityToUpdate(msg.GetEntityId());
815 }
816
817#if PROTOCOL_VERSION == 755 /* 1.17 */
818 void RenderingManager::Handle(ProtocolCraft::ClientboundRemoveEntityPacket& msg)
819 {
820 AddEntityToUpdate(msg.GetEntityId());
821 }
822#else
824 {
825 for (auto id: msg.GetEntityIds())
826 {
828 }
829 }
830#endif
831
833 {
834 day_time = ((msg.GetDayTime() + 6000) % 24000) / 24000.0f;
835 }
836
841 } // Renderer
842} // Botcraft
#define LOG_ERROR(osstream)
Definition Logger.hpp:45
const std::vector< float > color_day({ 0.6f, 0.85f, 0.9f })
const std::vector< float > color_night({0.1f, 0.1f, 0.1f})
const std::unordered_map< ItemId, std::unique_ptr< Item > > & Items() const
static AssetsManager & getInstance()
bool IsHazardous() const
bool IsBerryBush() const
const std::string & GetName() const
bool IsCobweb() const
bool IsDownBubbleColumn() const
bool IsTransparent() const
bool IsClimbable() const
float GetHardness() const
bool IsFluidFalling() const
bool IsPowderSnow() const
bool IsUpBubbleColumn() const
bool IsWaterlogged() const
float GetFriction() const
float GetFluidHeight() const
Get fluid height for this block.
bool IsScaffolding() const
bool IsSoulSand() const
static Position BlockCoordsToChunkCoords(const Position &pos)
Definition Chunk.cpp:73
void RegisterThread(const std::string &name)
Register the current thread in the map.
Definition Logger.cpp:104
static Logger & GetInstance()
Definition Logger.cpp:36
void BehaviourTickChild(const size_t i) const
RenderingManager(std::shared_ptr< World > world_, std::shared_ptr< InventoryManager > inventory_manager_, std::shared_ptr< EntityManager > entity_manager_, const unsigned int &window_width, const unsigned int &window_height, const unsigned int section_height_=16, const bool headless=false)
std::unordered_set< int > entities_to_update
std::unique_ptr< BehaviourRenderer > behaviour_renderer
void InternalProcessInput(GLFWwindow *window)
void SetKeyboardCallback(std::function< void(std::array< bool, static_cast< int >(KEY_CODE::NUMBER_OF_KEYS)>, double)> callback)
std::function< void(double, double)> MouseCallback
void Screenshot(const std::string &path)
std::shared_ptr< LocalPlayer > local_player
void AddChunkToUpdate(const int x, const int z)
void SetCurrentBehaviourTree(const BaseNode *root) const
static void ResizeCallback(GLFWwindow *window, int width, int height)
std::unique_ptr< WorldRenderer > world_renderer
std::unordered_set< Position > chunks_to_udpate
std::shared_ptr< EntityManager > entity_manager
void RemoveBlackboardValue(const std::string &key) const
static void InternalMouseCallback(GLFWwindow *window, double xpos, double ypos)
void UpdateBlackboardValue(const std::string &key, const std::any &value) const
void SetMouseCallback(std::function< void(double, double)> callback)
void BehaviourEndTick(const bool b) const
virtual void Handle(ProtocolCraft::ClientboundBlockUpdatePacket &msg) override
std::function< void(std::array< bool, static_cast< int >(KEY_CODE::NUMBER_OF_KEYS)>, double)> KeyboardCallback
std::shared_ptr< InventoryManager > inventory_manager
std::array< bool, static_cast< int >(KEY_CODE::NUMBER_OF_KEYS)> is_key_pressed
void SetPosOrientation(const double x_, const double y_, const double z_, const float yaw_, const float pitch_)
static constexpr short INVENTORY_HOTBAR_START
Definition Window.hpp:26
static constexpr short INVENTORY_CRAFTING_INPUT_START
Definition Window.hpp:19
static constexpr short INVENTORY_ARMOR_START
Definition Window.hpp:20
static constexpr short INVENTORY_CRAFTING_OUTPUT_INDEX
Definition Window.hpp:18
static constexpr short INVENTORY_STORAGE_START
Definition Window.hpp:25
static constexpr short INVENTORY_OFFHAND_INDEX
Definition Window.hpp:27
void WriteImage(const std::string &path, const int height, const int width, const int depth, const unsigned char *data, const bool vertical_revert=true)
void SleepUntil(const std::chrono::steady_clock::time_point &end)
Vector3< int > Position
Definition Vector3.hpp:282