summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt4
-rw-r--r--include/AssetManager.hpp (renamed from src/core/AssetManager.hpp)0
-rw-r--r--include/Core.hpp79
-rw-r--r--include/GameState.hpp (renamed from src/world/GameState.hpp)0
-rw-r--r--include/Nbt.hpp (renamed from src/Nbt.hpp)0
-rw-r--r--include/Utility.hpp55
-rw-r--r--include/Vector.hpp116
-rw-r--r--include/graphics/Gui.hpp7
-rw-r--r--include/graphics/RenderSection.hpp42
-rw-r--r--include/graphics/Shader.hpp (renamed from src/graphics/Shader.hpp)0
-rw-r--r--include/graphics/Texture.hpp14
-rw-r--r--include/graphics/Widget.hpp (renamed from src/graphics/Widget.hpp)0
-rw-r--r--include/network/Network.hpp (renamed from src/network/Network.hpp)0
-rw-r--r--include/network/NetworkClient.hpp (renamed from src/network/NetworkClient.hpp)0
-rw-r--r--include/network/Packet.hpp (renamed from src/network/Packet.hpp)0
-rw-r--r--include/network/Socket.hpp (renamed from src/network/Socket.hpp)0
-rw-r--r--include/network/Stream.hpp (renamed from src/network/Stream.hpp)0
-rw-r--r--include/world/Block.hpp (renamed from src/world/Block.hpp)0
-rw-r--r--include/world/Collision.hpp (renamed from src/world/Collision.hpp)0
-rw-r--r--include/world/Section.hpp (renamed from src/world/Section.hpp)3
-rw-r--r--include/world/World.hpp (renamed from src/world/World.hpp)0
-rw-r--r--old/Nbt.hpp516
-rw-r--r--old/Utility.hpp59
-rw-r--r--old/Vector.hpp116
-rw-r--r--old/core/AssetManager.cpp181
-rw-r--r--old/core/AssetManager.hpp75
-rw-r--r--old/core/Core.cpp457
-rw-r--r--old/core/Core.hpp (renamed from src/core/Core.hpp)12
-rw-r--r--old/core/Event.cpp (renamed from src/core/Event.cpp)2
-rw-r--r--old/core/Event.hpp (renamed from src/core/Event.hpp)2
-rw-r--r--old/graphics/Gui.cpp1
-rw-r--r--old/graphics/Gui.hpp (renamed from src/graphics/Gui.hpp)0
-rw-r--r--old/graphics/RenderSection.cpp356
-rw-r--r--old/graphics/RenderSection.hpp (renamed from src/graphics/RenderSection.hpp)6
-rw-r--r--old/graphics/Shader.cpp115
-rw-r--r--old/graphics/Shader.hpp24
-rw-r--r--old/graphics/Texture.cpp37
-rw-r--r--old/graphics/Texture.hpp (renamed from src/graphics/Texture.hpp)0
-rw-r--r--old/graphics/Widget.cpp1
-rw-r--r--old/graphics/Widget.hpp8
-rw-r--r--old/main.cpp35
-rw-r--r--old/network/Network.cpp224
-rw-r--r--old/network/Network.hpp26
-rw-r--r--old/network/NetworkClient.cpp93
-rw-r--r--old/network/NetworkClient.hpp26
-rw-r--r--old/network/Packet.hpp521
-rw-r--r--old/network/Socket.cpp29
-rw-r--r--old/network/Socket.hpp46
-rw-r--r--old/network/Stream.cpp348
-rw-r--r--old/network/Stream.hpp107
-rw-r--r--old/world/Block.cpp17
-rw-r--r--old/world/Block.hpp15
-rw-r--r--old/world/Collision.cpp28
-rw-r--r--old/world/Collision.hpp8
-rw-r--r--old/world/GameState.cpp383
-rw-r--r--old/world/GameState.hpp71
-rw-r--r--old/world/Section.cpp147
-rw-r--r--old/world/Section.hpp51
-rw-r--r--old/world/World.cpp129
-rw-r--r--old/world/World.hpp38
-rw-r--r--src/AssetManager.cpp185
-rw-r--r--src/AssetManager.hpp77
-rw-r--r--src/Block.cpp17
-rw-r--r--src/Block.hpp15
-rw-r--r--src/Collision.cpp28
-rw-r--r--src/Collision.hpp8
-rw-r--r--src/Core.cpp59
-rw-r--r--src/Core.hpp23
-rw-r--r--src/Event.cpp100
-rw-r--r--src/Event.hpp116
-rw-r--r--src/GameState.cpp383
-rw-r--r--src/GameState.hpp71
-rw-r--r--src/Network.cpp224
-rw-r--r--src/Network.hpp26
-rw-r--r--src/NetworkClient.cpp93
-rw-r--r--src/NetworkClient.hpp26
-rw-r--r--src/Packet.hpp521
-rw-r--r--src/Render.cpp137
-rw-r--r--src/Render.hpp32
-rw-r--r--src/Renderer.cpp15
-rw-r--r--src/Renderer.hpp18
-rw-r--r--src/RendererSection.cpp348
-rw-r--r--src/RendererSection.hpp49
-rw-r--r--src/RendererWorld.cpp1
-rw-r--r--src/RendererWorld.hpp7
-rw-r--r--src/Section.cpp147
-rw-r--r--src/Section.hpp51
-rw-r--r--src/Shader.cpp115
-rw-r--r--src/Shader.hpp24
-rw-r--r--src/Socket.cpp29
-rw-r--r--src/Socket.hpp46
-rw-r--r--src/Stream.cpp348
-rw-r--r--src/Stream.hpp107
-rw-r--r--src/Texture.cpp37
-rw-r--r--src/Texture.hpp14
-rw-r--r--src/Utility.cpp73
-rw-r--r--src/Utility.hpp65
-rw-r--r--src/World.cpp129
-rw-r--r--src/World.hpp39
-rw-r--r--src/core/AssetManager.cpp2
-rw-r--r--src/core/Core.cpp166
-rw-r--r--src/graphics/RenderSection.cpp54
-rw-r--r--src/main.cpp7
-rw-r--r--src/network/Network.cpp8
-rw-r--r--src/network/Stream.cpp9
-rw-r--r--src/world/GameState.cpp2
-rw-r--r--src/world/Section.cpp50
107 files changed, 8440 insertions, 291 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f165a67..8483add 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -11,9 +11,7 @@ include(externalProject)
file(GLOB_RECURSE SOURCES "./src/*.cpp")
file(GLOB_RECURSE HEADERS "./src/*.hpp")
-add_executable(AltCraft ${HEADERS} ${SOURCES})
-
-target_include_directories(AltCraft PUBLIC src/)
+add_executable(AltCraft ${HEADERS} ${SOURCES} src/Core.cpp src/Core.hpp src/Utility.cpp src/Render.cpp src/Render.hpp src/RendererWorld.cpp src/RendererWorld.hpp src/Renderer.cpp src/Renderer.hpp)
################
# CONFIGURATION
diff --git a/src/core/AssetManager.hpp b/include/AssetManager.hpp
index 26c7eca..26c7eca 100644
--- a/src/core/AssetManager.hpp
+++ b/include/AssetManager.hpp
diff --git a/include/Core.hpp b/include/Core.hpp
new file mode 100644
index 0000000..3cad094
--- /dev/null
+++ b/include/Core.hpp
@@ -0,0 +1,79 @@
+#pragma once
+
+#include <iomanip>
+#include <tuple>
+
+#include <easylogging++.h>
+#include <SFML/Window.hpp>
+#include <GL/glew.h>
+#include <glm/gtc/type_ptr.hpp>
+
+#include <GameState.hpp>
+#include <AssetManager.hpp>
+#include <graphics/Shader.hpp>
+#include <graphics/Gui.hpp>
+#include <graphics/RenderSection.hpp>
+#include <network/NetworkClient.hpp>
+
+class Core {
+ GameState *gameState;
+ NetworkClient *client;
+ sf::Window *window;
+ AssetManager *assetManager;
+ bool isMouseCaptured = false;
+ bool isRunning = true;
+ enum {
+ MainMenu,
+ Loading,
+ Playing,
+ PauseMenu,
+ } currentState = Playing;
+ float mouseXDelta, mouseYDelta;
+ float deltaTime;
+ float absTime;
+
+ void RenderWorld();
+
+ void HandleMouseCapture();
+
+ void HandleEvents();
+
+ void InitSfml(unsigned int WinWidth, unsigned int WinHeight, std::string WinTitle);
+
+ void InitGlew();
+
+ void SetMouseCapture(bool IsCaptured);
+
+ void PrepareToRendering();
+
+ void RenderFrame();
+
+ unsigned int width();
+
+ unsigned int height();
+
+ void UpdateChunksToRender();
+
+ void UpdateGameState();
+
+ std::thread gameStateLoopThread;
+
+ Shader *shader;
+ //Cube verticies, Cube VAO, Cube UVs, TextureIndexes UboTextureIndexes, TextureData UboTextureIndexes, TextureData2 UboTextureIndexes, Blocks VBO, Models VBO, Line VAO, Lines VBO
+ GLuint UboTextureIndexes, UboTextureData;
+ std::vector<Vector> toRender;
+ std::map<Vector, RenderSection> availableChunks;
+
+ int ChunkDistance = 1;
+
+ RenderState renderState;
+
+ double tickRate = 0;
+
+public:
+ Core();
+
+ ~Core();
+
+ void Exec();
+};
diff --git a/src/world/GameState.hpp b/include/GameState.hpp
index 6741882..6741882 100644
--- a/src/world/GameState.hpp
+++ b/include/GameState.hpp
diff --git a/src/Nbt.hpp b/include/Nbt.hpp
index 03f5af0..03f5af0 100644
--- a/src/Nbt.hpp
+++ b/include/Nbt.hpp
diff --git a/include/Utility.hpp b/include/Utility.hpp
new file mode 100644
index 0000000..92e924f
--- /dev/null
+++ b/include/Utility.hpp
@@ -0,0 +1,55 @@
+#pragma once
+
+#include <algorithm>
+
+#include <GL/glew.h>
+
+template<class T>
+void endswap(T *objp) {
+ unsigned char *memp = reinterpret_cast<unsigned char *>(objp);
+ std::reverse(memp, memp + sizeof(T));
+}
+
+template<class T>
+void endswap(T &obj) {
+ unsigned char *raw = reinterpret_cast<unsigned char *>(&obj);
+ std::reverse(raw, raw + sizeof(T));
+}
+
+inline void endswap(unsigned char *arr, size_t arrLen) {
+ std::reverse(arr, arr + arrLen);
+}
+
+inline GLenum glCheckError_(const char *file, int line) {
+ GLenum errorCode;
+ while ((errorCode = glGetError()) != GL_NO_ERROR) {
+ std::string error;
+ switch (errorCode) {
+ case GL_INVALID_ENUM:
+ error = "INVALID_ENUM";
+ break;
+ case GL_INVALID_VALUE:
+ error = "INVALID_VALUE";
+ break;
+ case GL_INVALID_OPERATION:
+ error = "INVALID_OPERATION";
+ break;
+ case GL_STACK_OVERFLOW:
+ error = "STACK_OVERFLOW";
+ break;
+ case GL_STACK_UNDERFLOW:
+ error = "STACK_UNDERFLOW";
+ break;
+ case GL_OUT_OF_MEMORY:
+ error = "OUT_OF_MEMORY";
+ break;
+ case GL_INVALID_FRAMEBUFFER_OPERATION:
+ error = "INVALID_FRAMEBUFFER_OPERATION";
+ break;
+ }
+ LOG(ERROR) << "OpenGL error: " << error << " at " << file << ":" << line;
+ }
+ return errorCode;
+}
+
+#define glCheckError() glCheckError_(__FILE__, __LINE__) \ No newline at end of file
diff --git a/include/Vector.hpp b/include/Vector.hpp
new file mode 100644
index 0000000..a2d5c6a
--- /dev/null
+++ b/include/Vector.hpp
@@ -0,0 +1,116 @@
+#pragma once
+
+#include <ostream>
+#include <cmath>
+#include <tuple>
+
+#include <glm/vec3.hpp>
+
+template<class T>
+class Vector3 {
+ T x, y, z;
+public:
+ Vector3(T X = 0, T Y = 0, T Z = 0) : x(X), y(Y), z(Z) {}
+
+ Vector3(const Vector3 &rhs) : x(rhs.x), y(rhs.y), z(rhs.z) {}
+
+ ~Vector3() = default;
+
+ void SetX(T X) { x = X; }
+
+ void SetY(T Y) { y = Y; }
+
+ void SetZ(T Z) { z = Z; }
+
+ T GetX() const { return x; }
+
+ T GetY() const { return y; }
+
+ T GetZ() const { return z; }
+
+ double GetMagnitude() const { return std::sqrt(std::pow(x, 2) + std::pow(y, 2) + std::pow(z, 2)); }
+
+ operator glm::vec3() const {
+ return glm::vec3(x, y, z);
+ }
+
+ void swap(Vector3 &rhs) {
+ std::swap(x, rhs.x);
+ std::swap(y, rhs.y);
+ std::swap(z, rhs.z);
+ }
+
+ Vector3 &operator=(Vector3 rhs) {
+ rhs.swap(*this);
+ return *this;
+ }
+
+ Vector3 operator*(T rhs) const {
+ return Vector3<T>(
+ x * rhs,
+ y * rhs,
+ z * rhs
+ );
+ }
+
+ Vector3 operator/(T rhs) const {
+ return Vector3<T>(
+ x / rhs,
+ y / rhs,
+ z / rhs
+ );
+ }
+
+ Vector3 operator+(const Vector3 &rhs) const {
+ return Vector3<T>(
+ x + rhs.x,
+ y + rhs.y,
+ z + rhs.z
+ );
+ }
+
+ Vector3 operator-(const Vector3 &rhs) const {
+ return Vector3<T>(
+ x - rhs.x,
+ y - rhs.y,
+ z - rhs.z
+ );
+ }
+
+ Vector3 operator*(const Vector3 &rhs) const {
+ return Vector3<T>(
+ x * rhs.x,
+ y * rhs.y,
+ z * rhs.z
+ );
+ }
+
+ Vector3 operator/(const Vector3 &rhs) const {
+ return Vector3<T>(
+ x / rhs.x,
+ y / rhs.y,
+ z / rhs.z
+ );
+ }
+
+ bool operator==(const Vector3 &rhs) const {
+ return (x == rhs.x && y == rhs.y && z == rhs.z);
+ }
+
+ bool operator!=(const Vector3 &rhs) const {
+ return !(*this == rhs);
+ }
+
+ bool operator<(const Vector3 &rhs) const {
+ return std::tie(x, y, z) < std::tie(rhs.x, rhs.y, rhs.z);
+ }
+
+
+ friend std::ostream &operator<<(std::ostream &os, const Vector3 &vector3) {
+ os << vector3.x << ", " << vector3.y << ", " << vector3.z;
+ return os;
+ }
+};
+
+typedef Vector3<double> VectorF;
+typedef Vector3<signed long long> Vector; \ No newline at end of file
diff --git a/include/graphics/Gui.hpp b/include/graphics/Gui.hpp
new file mode 100644
index 0000000..641b941
--- /dev/null
+++ b/include/graphics/Gui.hpp
@@ -0,0 +1,7 @@
+#pragma once
+
+class Gui {
+
+public:
+ int WHY=0;
+};
diff --git a/include/graphics/RenderSection.hpp b/include/graphics/RenderSection.hpp
new file mode 100644
index 0000000..953d7ea
--- /dev/null
+++ b/include/graphics/RenderSection.hpp
@@ -0,0 +1,42 @@
+#pragma once
+
+#include <GL/glew.h>
+#include <glm/detail/type_mat.hpp>
+#include <glm/vec2.hpp>
+#include <glm/detail/type_mat4x4.hpp>
+#include <glm/gtx/transform.hpp>
+#include <easylogging++.h>
+
+#include <AssetManager.hpp>
+#include <world/Section.hpp>
+#include <world/World.hpp>
+
+class RenderState {
+ GLuint ActiveVao;
+ GLuint ActiveShader;
+public:
+ void SetActiveVao(GLuint Vao);
+ void SetActiveShader(GLuint Shader);
+};
+
+class RenderSection {
+ Vector sectionPosition;
+ World *world;
+ GLuint Vao, VboTextures, VboModels, VboColors;
+
+ static GLuint VboVertices, VboUvs;
+ static std::map<GLuint, int> refCounterVbo;
+ static std::map<GLuint, int> refCounterVao;
+
+ size_t numOfFaces;
+
+public:
+ RenderSection(World *world, Vector position);
+ RenderSection(const RenderSection &other);
+ ~RenderSection();
+
+ void UpdateState(const std::map<BlockTextureId, glm::vec4> &textureAtlas);
+ void Render(RenderState &state);
+
+ Section *GetSection();
+}; \ No newline at end of file
diff --git a/src/graphics/Shader.hpp b/include/graphics/Shader.hpp
index 17a434e..17a434e 100644
--- a/src/graphics/Shader.hpp
+++ b/include/graphics/Shader.hpp
diff --git a/include/graphics/Texture.hpp b/include/graphics/Texture.hpp
new file mode 100644
index 0000000..277806a
--- /dev/null
+++ b/include/graphics/Texture.hpp
@@ -0,0 +1,14 @@
+#pragma once
+
+#include <SFML/Graphics.hpp>
+#include <easylogging++.h>
+#include <GL/glew.h>
+
+class Texture {
+ Texture(Texture&);
+ Texture&operator=(Texture&);
+public:
+ GLuint texture;
+ Texture(std::string filename, GLenum textureWrapping = GL_CLAMP_TO_BORDER, GLenum textureFiltering = GL_NEAREST);
+ ~Texture();
+}; \ No newline at end of file
diff --git a/src/graphics/Widget.hpp b/include/graphics/Widget.hpp
index c4d5dc1..c4d5dc1 100644
--- a/src/graphics/Widget.hpp
+++ b/include/graphics/Widget.hpp
diff --git a/src/network/Network.hpp b/include/network/Network.hpp
index 1281289..1281289 100644
--- a/src/network/Network.hpp
+++ b/include/network/Network.hpp
diff --git a/src/network/NetworkClient.hpp b/include/network/NetworkClient.hpp
index 22b1b22..22b1b22 100644
--- a/src/network/NetworkClient.hpp
+++ b/include/network/NetworkClient.hpp
diff --git a/src/network/Packet.hpp b/include/network/Packet.hpp
index 685e3da..685e3da 100644
--- a/src/network/Packet.hpp
+++ b/include/network/Packet.hpp
diff --git a/src/network/Socket.hpp b/include/network/Socket.hpp
index 48bcad9..48bcad9 100644
--- a/src/network/Socket.hpp
+++ b/include/network/Socket.hpp
diff --git a/src/network/Stream.hpp b/include/network/Stream.hpp
index a24dfbe..a24dfbe 100644
--- a/src/network/Stream.hpp
+++ b/include/network/Stream.hpp
diff --git a/src/world/Block.hpp b/include/world/Block.hpp
index 2f823fe..2f823fe 100644
--- a/src/world/Block.hpp
+++ b/include/world/Block.hpp
diff --git a/src/world/Collision.hpp b/include/world/Collision.hpp
index b88fbf7..b88fbf7 100644
--- a/src/world/Collision.hpp
+++ b/include/world/Collision.hpp
diff --git a/src/world/Section.hpp b/include/world/Section.hpp
index 2df0cfe..139b5b5 100644
--- a/src/world/Section.hpp
+++ b/include/world/Section.hpp
@@ -3,7 +3,6 @@
#include <vector>
#include <map>
#include <condition_variable>
-#include <functional>
#include <easylogging++.h>
@@ -46,6 +45,4 @@ public:
Section(const Section &other);
Vector GetPosition();
-
- size_t GetHash();
}; \ No newline at end of file
diff --git a/src/world/World.hpp b/include/world/World.hpp
index 6b09f1f..6b09f1f 100644
--- a/src/world/World.hpp
+++ b/include/world/World.hpp
diff --git a/old/Nbt.hpp b/old/Nbt.hpp
new file mode 100644
index 0000000..a90464d
--- /dev/null
+++ b/old/Nbt.hpp
@@ -0,0 +1,516 @@
+#pragma once
+
+#include <cstddef>
+#include <vector>
+#include <fstream>
+#include <zlib.h>
+
+#include "Utility.hpp"
+
+namespace nbt {
+ enum TagType {
+ End, //nullptr
+ Byte, //int8_t
+ Short, //int16_t
+ Int, //int32_t
+ Long, //int64_t
+ Float, //float
+ Double, //double
+ ByteArray, //std::vector<signed char>
+ String, //std::string
+ List, //std::vector<NbtTag>
+ Compound, //std::vector<NbtTag>
+ IntArray, //std::vector<int32_t>
+ Unknown, //dummy value
+ };
+
+ class NbtTag;
+
+ typedef std::vector<NbtTag> compound_t;
+
+ typedef std::string string_t;
+
+ typedef std::vector<signed char> byteArray_t;
+
+ typedef std::vector<int> intArray_t;
+
+ class NbtTag {
+ TagType type = Unknown;
+ string_t name = "";
+ unsigned char *data = nullptr;
+ public:
+ NbtTag(TagType type, string_t name) : type(type), name(name) {
+ switch (type) {
+ case End:
+ data = nullptr;
+ break;
+ case Compound:
+ data = (unsigned char *) new compound_t;
+ break;
+ case String:
+ data = (unsigned char *) new string_t;
+ break;
+ case Int:
+ data = (unsigned char *) new int32_t;
+ break;
+ case Long:
+ data = (unsigned char *) new int64_t;
+ break;
+ case Byte:
+ data = (unsigned char *) new int8_t;
+ break;
+ case Short:
+ data = (unsigned char *) new int16_t;
+ break;
+ case Float:
+ data = (unsigned char *) new float;
+ break;
+ case Double:
+ data = (unsigned char *) new double;
+ break;
+ case ByteArray:
+ data = (unsigned char *) new byteArray_t;
+ break;
+ case List:
+ data = (unsigned char *) new compound_t;
+ break;
+ case IntArray:
+ data = (unsigned char *) new intArray_t;
+ }
+ }
+
+ NbtTag(const NbtTag &other) : type(other.type), name(other.name) {
+ switch (type) {
+ case Byte:
+ data = (unsigned char *) new int8_t;
+ *((int8_t *) data) = *((int8_t *) other.data);
+ break;
+ case Short:
+ data = (unsigned char *) new int16_t;
+ *((int16_t *) data) = *((int16_t *) other.data);
+ break;
+ case Int:
+ data = (unsigned char *) new int32_t;
+ *((int32_t *) data) = *((int32_t *) other.data);
+ break;
+ case Long:
+ data = (unsigned char *) new int64_t;
+ *((int64_t *) data) = *((int64_t *) other.data);
+ break;
+ case Float:
+ data = (unsigned char *) new float;
+ *((float *) data) = *((float *) other.data);
+ break;
+ case Double:
+ data = (unsigned char *) new double;
+ *((double *) data) = *((double *) other.data);
+ break;
+ case ByteArray:
+ data = (unsigned char *) new byteArray_t;
+ *((std::vector<signed char> *) data) = *((std::vector<signed char> *) other.data);
+ break;
+ case String:
+ data = (unsigned char *) new string_t;
+ *((std::string *) data) = *((std::string *) other.data);
+ break;
+ case List:
+ data = (unsigned char *) new compound_t;
+ *((std::vector<NbtTag> *) data) = *((std::vector<NbtTag> *) other.data);
+ break;
+ case Compound:
+ data = (unsigned char *) new compound_t;
+ *((std::vector<NbtTag> *) data) = *((std::vector<NbtTag> *) other.data);
+ break;
+ case IntArray:
+ data = (unsigned char *) new intArray_t;
+ *((std::vector<int> *) data) = *((std::vector<int> *) other.data);
+ break;
+ }
+ }
+
+ ~NbtTag() {
+ switch (type) {
+ case Byte:
+ delete ((int8_t *) data);
+ break;
+ case Short:
+ delete ((int16_t *) data);
+ break;
+ case Int:
+ delete ((int32_t *) data);
+ break;
+ case Long:
+ delete ((int64_t *) data);
+ break;
+ case Float:
+ delete ((float *) data);
+ break;
+ case Double:
+ delete ((double *) data);
+ break;
+ case ByteArray:
+ delete ((std::vector<signed char> *) data);
+ break;
+ case String:
+ delete ((std::string *) data);
+ break;
+ case List:
+ delete ((std::vector<NbtTag> *) data);
+ break;
+ case Compound:
+ delete ((std::vector<NbtTag> *) data);
+ break;
+ case IntArray:
+ delete ((std::vector<int> *) data);
+ break;
+ }
+ };
+
+ void swap(NbtTag &other) {
+ std::swap(other.data, data);
+ std::swap(other.name, name);
+ std::swap(other.type, type);
+ }
+
+ NbtTag &operator=(NbtTag other) {
+ other.swap(*this);
+ return *this;
+ }
+
+ TagType GetType() const {
+ return type;
+ }
+
+ string_t GetName() const {
+ return name;
+ }
+
+
+ string_t &GetString() {
+ string_t &val = *reinterpret_cast<std::string *>(data);
+ return val;
+ }
+
+ compound_t &GetCompound() {
+ std::vector<NbtTag> &val = *reinterpret_cast<std::vector<NbtTag> *>(data);
+ return val;
+ }
+
+ compound_t &GetList() {
+ std::vector<NbtTag> &val = *reinterpret_cast<std::vector<NbtTag> *>(data);
+ return val;
+ }
+
+ int64_t &GetLong() {
+ int64_t &val = *reinterpret_cast<int64_t *>(data);
+ return val;
+ }
+
+ float &GetFloat() {
+ float &val = *reinterpret_cast<float *>(data);
+ return val;
+ }
+
+ double &GetDouble() {
+ double &val = *reinterpret_cast<double *>(data);
+ return val;
+ }
+
+ byteArray_t &GetByteArray() {
+ auto &val = *reinterpret_cast<byteArray_t *>(data);
+ return val;
+ }
+
+ intArray_t &GetIntArray() {
+ auto &val = *reinterpret_cast<intArray_t *>(data);
+ return val;
+ }
+
+ int16_t &GetShort() {
+ auto &val = *reinterpret_cast<int16_t *>(data);
+ return val;
+ }
+
+ int32_t &GetInt() {
+ auto &val = *reinterpret_cast<int32_t *>(data);
+ return val;
+ }
+
+ int8_t &GetByte() {
+ auto &val = *reinterpret_cast<int8_t *>(data);
+ return val;
+ }
+ };
+
+ NbtTag ParseTag(unsigned char *data, size_t &size, TagType listItemType = Unknown) {
+ size = 0;
+ TagType type;
+ if (listItemType == Unknown) {
+ type = (TagType) *data;
+ data += 1;
+ size += 1;
+ } else
+ type = listItemType;
+ string_t name;
+ if (listItemType == Unknown && type != End) {
+ short nameLen = *((short *) data);
+ data += 2;
+ size += 2;
+ endswap(&nameLen);
+ name = std::string((char *) data, nameLen);
+ data += nameLen;
+ size += nameLen;
+ }
+ NbtTag tag(type, name);
+ switch (type) {
+ case Compound: {
+ do {
+ size_t s;
+ tag.GetCompound().push_back(ParseTag(data, s));
+ data += s;
+ size += s;
+ } while (tag.GetCompound().back().GetType() != End);
+ tag.GetCompound().pop_back();
+ return tag;
+ }
+ case String: {
+ short len = *((short *) data);
+ data += 2;
+ size += 2;
+ endswap(&len);
+ string_t str((char *) data, len);
+ data += len;
+ size += len;
+ tag.GetString() = str;
+ return tag;
+ }
+ case End:
+ return tag;
+ case Long:
+ tag.GetLong() = *((int64_t *) data);
+ endswap(&tag.GetLong());
+ data += 8;
+ size += 8;
+ return tag;
+ case Short:
+ tag.GetShort() = *((int16_t *) data);
+ endswap(&tag.GetShort());
+ data += 2;
+ size += 2;
+ return tag;
+ case Float:
+ tag.GetFloat() = *((float *) data);
+ endswap(&tag.GetFloat());
+ data += 4;
+ size += 4;
+ return tag;
+ case Double:
+ tag.GetDouble() = *((double *) data);
+ endswap(&tag.GetDouble());
+ data += 8;
+ size += 8;
+ return tag;
+ case Byte:
+ tag.GetByte() = *((int8_t *) data);
+ endswap(&tag.GetByte());
+ data += 1;
+ size += 1;
+ return tag;
+ case Int:
+ tag.GetInt() = *((int32_t *) data);
+ endswap(&tag.GetInt());
+ data += 4;
+ size += 4;
+ return tag;
+ case List: {
+ TagType listType = *((TagType *) data);
+ data += 1;
+ size += 1;
+ int32_t listLength = *((int32_t *) data);
+ endswap(&listLength);
+ data += 4;
+ size += 4;
+ for (int i = 0; i < listLength; i++) {
+ size_t s = 0;
+ std::vector<NbtTag> &vec = tag.GetCompound();
+ vec.push_back(ParseTag(data, s, listType));
+ data += s;
+ size += s;
+ }
+ return tag;
+ }
+ case ByteArray: {
+ int32_t arrLength = *((int32_t *) data);
+ endswap(&arrLength);
+ data += 4;
+ size += 4;
+ for (int i = 0; i < arrLength; i++) {
+ signed char val = (signed char) data[i];
+ std::vector<signed char> &vec = tag.GetByteArray();
+ vec.push_back(val);
+ }
+ data += arrLength;
+ size += arrLength;
+ return tag;
+ }
+ default:
+ throw 13;
+ }
+ }
+
+ NbtTag ParseTag(unsigned char *data, size_t *optionalSize = nullptr) {
+ size_t s = 0;
+ size_t &size = (optionalSize ? *optionalSize : s);
+ return ParseTag(data, size);
+ }
+
+ std::vector<unsigned char> Decompress(unsigned char *data, size_t dataLen) {
+ const size_t decompBuffSize = 1024 * 16;
+ unsigned char *decompBuff = new unsigned char[decompBuffSize];
+ std::vector<unsigned char> uncompressed;
+ for (int i = 0; i < decompBuffSize; i++)
+ decompBuff[i] = 0;
+
+
+ z_stream stream;
+ stream.zalloc = Z_NULL;
+ stream.zfree = Z_NULL;
+ stream.opaque = Z_NULL;
+ stream.next_in = data;
+ stream.avail_in = dataLen;
+ stream.next_out = decompBuff;
+ stream.avail_out = decompBuffSize;
+
+ if (inflateInit2(&stream, 15 + 32) != Z_OK) {
+ delete[] decompBuff;
+ throw 171;
+ }
+
+ int res;
+ do {
+ stream.avail_out = decompBuffSize;
+
+ switch ((res = inflate(&stream, Z_NO_FLUSH))) {
+ case Z_MEM_ERROR:
+ throw 172;
+ case Z_DATA_ERROR:
+ throw 173;
+ case Z_NEED_DICT:
+ throw 174;
+ }
+
+ uncompressed.resize(uncompressed.size() + decompBuffSize);
+ std::copy(decompBuff, decompBuff + decompBuffSize, uncompressed.end() - decompBuffSize);
+ } while (stream.avail_out == 0);
+ if (res != Z_STREAM_END)
+ throw 175;
+ if (inflateEnd(&stream) != Z_OK)
+ throw 176;
+ delete[] decompBuff;
+ return uncompressed;
+ }
+
+ NbtTag ParseCompressed(unsigned char *data, size_t dataLen) {
+ auto uncompressed = Decompress(data, dataLen);
+ NbtTag root = ParseTag(uncompressed.data());
+ return root;
+ }
+
+ NbtTag Parse(unsigned char *data, size_t dataLen) {
+ bool isCompressed = *data != 10;
+ if (isCompressed)
+ return ParseCompressed(data, dataLen);
+ else
+ return ParseTag(data);
+ }
+
+ void PrintTree(NbtTag &tree, int deepness = 0, std::ostream &ostream = std::cout) {
+ ostream << std::string(deepness, '\t') << "Tag ";
+ switch (tree.GetType()) {
+ case Byte:
+ ostream << "byte";
+ break;
+ case Short:
+ ostream << "short";
+ break;
+ case Int:
+ ostream << "int";
+ break;
+ case Long:
+ ostream << "long";
+ break;
+ case Float:
+ ostream << "float";
+ break;
+ case Double:
+ ostream << "double";
+ break;
+ case ByteArray:
+ ostream << "byte array";
+ break;
+ case String:
+ ostream << "string";
+ break;
+ case List:
+ ostream << "list";
+ break;
+ case Compound:
+ ostream << "compound";
+ break;
+ case IntArray:
+ ostream << "int array";
+ break;
+ case End:
+ ostream << "end";
+ break;
+ }
+ if (tree.GetName().length() > 0)
+ ostream << " (" << tree.GetName() << ")";
+ ostream << ": ";
+
+ if (tree.GetType() == Compound || tree.GetType() == List) {
+ std::vector<NbtTag> &vec = (tree.GetType() == Compound ? tree.GetCompound() : tree.GetList());
+ ostream << vec.size() << " entries {" << std::endl;
+ for (auto it = vec.begin(); it != vec.end(); ++it) {
+ PrintTree(*it, deepness + 1, std::cout);
+ }
+ ostream << std::string(deepness, '\t') << "}" << std::endl;
+ return;
+ } else {
+ switch (tree.GetType()) {
+ case Int:
+ ostream << tree.GetInt();
+ break;
+ case String:
+ ostream << "\"" << tree.GetString() << "\"";
+ break;
+ case Double:
+ ostream << tree.GetDouble();
+ break;
+ case Float:
+ ostream << tree.GetFloat();
+ break;
+ case Short:
+ ostream << tree.GetShort();
+ break;
+ case Byte:
+ ostream << (int) tree.GetByte();
+ break;
+ case Long:
+ ostream << tree.GetLong();
+ break;
+ case ByteArray:
+ ostream << "[" << tree.GetByteArray().size() << " bytes]: ";
+ for (int i = 0; i < (tree.GetByteArray().size() > 10 ? 10 : tree.GetByteArray().size()); i++) {
+ ostream << std::hex << "0x" << (tree.GetByteArray()[i] > 15 ? "" : "0")
+ << (int) tree.GetByteArray()[i]
+ << std::dec << " ";
+ }
+ break;
+ case IntArray:
+ break;
+ }
+ ostream << std::endl;
+ }
+ }
+} \ No newline at end of file
diff --git a/old/Utility.hpp b/old/Utility.hpp
new file mode 100644
index 0000000..11b4ff7
--- /dev/null
+++ b/old/Utility.hpp
@@ -0,0 +1,59 @@
+#pragma once
+
+#include <algorithm>
+
+#include <GL/glew.h>
+
+template<class T>
+void endswap(T *objp) {
+ unsigned char *memp = reinterpret_cast<unsigned char *>(objp);
+ std::reverse(memp, memp + sizeof(T));
+}
+
+template<class T>
+void endswap(T &obj) {
+ unsigned char *raw = reinterpret_cast<unsigned char *>(&obj);
+ std::reverse(raw, raw + sizeof(T));
+}
+
+inline void endswap(unsigned char *arr, size_t arrLen) {
+ std::reverse(arr, arr + arrLen);
+}
+
+inline GLenum glCheckError_(const char *file, int line) {
+ GLenum errorCode;
+ while ((errorCode = glGetError()) != GL_NO_ERROR) {
+ std::string error;
+ switch (errorCode) {
+ case GL_INVALID_ENUM:
+ error = "INVALID_ENUM";
+ break;
+ case GL_INVALID_VALUE:
+ error = "INVALID_VALUE";
+ break;
+ case GL_INVALID_OPERATION:
+ error = "INVALID_OPERATION";
+ break;
+ case GL_STACK_OVERFLOW:
+ error = "STACK_OVERFLOW";
+ break;
+ case GL_STACK_UNDERFLOW:
+ error = "STACK_UNDERFLOW";
+ break;
+ case GL_OUT_OF_MEMORY:
+ error = "OUT_OF_MEMORY";
+ break;
+ case GL_INVALID_FRAMEBUFFER_OPERATION:
+ error = "INVALID_FRAMEBUFFER_OPERATION";
+ break;
+ }
+ static int t = 0;
+ t++;
+ if (t>10)
+ LOG(FATAL);
+ LOG(ERROR) << "OpenGL error: " << error << " at " << file << ":" << line;
+ }
+ return errorCode;
+}
+
+#define glCheckError() glCheckError_(__FILE__, __LINE__) \ No newline at end of file
diff --git a/old/Vector.hpp b/old/Vector.hpp
new file mode 100644
index 0000000..a2d5c6a
--- /dev/null
+++ b/old/Vector.hpp
@@ -0,0 +1,116 @@
+#pragma once
+
+#include <ostream>
+#include <cmath>
+#include <tuple>
+
+#include <glm/vec3.hpp>
+
+template<class T>
+class Vector3 {
+ T x, y, z;
+public:
+ Vector3(T X = 0, T Y = 0, T Z = 0) : x(X), y(Y), z(Z) {}
+
+ Vector3(const Vector3 &rhs) : x(rhs.x), y(rhs.y), z(rhs.z) {}
+
+ ~Vector3() = default;
+
+ void SetX(T X) { x = X; }
+
+ void SetY(T Y) { y = Y; }
+
+ void SetZ(T Z) { z = Z; }
+
+ T GetX() const { return x; }
+
+ T GetY() const { return y; }
+
+ T GetZ() const { return z; }
+
+ double GetMagnitude() const { return std::sqrt(std::pow(x, 2) + std::pow(y, 2) + std::pow(z, 2)); }
+
+ operator glm::vec3() const {
+ return glm::vec3(x, y, z);
+ }
+
+ void swap(Vector3 &rhs) {
+ std::swap(x, rhs.x);
+ std::swap(y, rhs.y);
+ std::swap(z, rhs.z);
+ }
+
+ Vector3 &operator=(Vector3 rhs) {
+ rhs.swap(*this);
+ return *this;
+ }
+
+ Vector3 operator*(T rhs) const {
+ return Vector3<T>(
+ x * rhs,
+ y * rhs,
+ z * rhs
+ );
+ }
+
+ Vector3 operator/(T rhs) const {
+ return Vector3<T>(
+ x / rhs,
+ y / rhs,
+ z / rhs
+ );
+ }
+
+ Vector3 operator+(const Vector3 &rhs) const {
+ return Vector3<T>(
+ x + rhs.x,
+ y + rhs.y,
+ z + rhs.z
+ );
+ }
+
+ Vector3 operator-(const Vector3 &rhs) const {
+ return Vector3<T>(
+ x - rhs.x,
+ y - rhs.y,
+ z - rhs.z
+ );
+ }
+
+ Vector3 operator*(const Vector3 &rhs) const {
+ return Vector3<T>(
+ x * rhs.x,
+ y * rhs.y,
+ z * rhs.z
+ );
+ }
+
+ Vector3 operator/(const Vector3 &rhs) const {
+ return Vector3<T>(
+ x / rhs.x,
+ y / rhs.y,
+ z / rhs.z
+ );
+ }
+
+ bool operator==(const Vector3 &rhs) const {
+ return (x == rhs.x && y == rhs.y && z == rhs.z);
+ }
+
+ bool operator!=(const Vector3 &rhs) const {
+ return !(*this == rhs);
+ }
+
+ bool operator<(const Vector3 &rhs) const {
+ return std::tie(x, y, z) < std::tie(rhs.x, rhs.y, rhs.z);
+ }
+
+
+ friend std::ostream &operator<<(std::ostream &os, const Vector3 &vector3) {
+ os << vector3.x << ", " << vector3.y << ", " << vector3.z;
+ return os;
+ }
+};
+
+typedef Vector3<double> VectorF;
+typedef Vector3<signed long long> Vector; \ No newline at end of file
diff --git a/old/core/AssetManager.cpp b/old/core/AssetManager.cpp
new file mode 100644
index 0000000..258f5d9
--- /dev/null
+++ b/old/core/AssetManager.cpp
@@ -0,0 +1,181 @@
+#include "AssetManager.hpp"
+
+namespace fs = std::experimental::filesystem;
+
+//const fs::path pathToAssets = "./assets/";
+//const fs::path pathToAssetsList = "./items.json";
+//const fs::path pathToTextureIndex = "./textures.json";
+const std::string pathToAssetsList = "./items.json";
+const std::string pathToTextureIndex = "./textures.json";
+
+AssetManager::AssetManager() {
+ LoadIds();
+ LoadTextureResources();
+}
+
+void AssetManager::LoadIds() {
+ std::ifstream in(pathToAssetsList);
+ nlohmann::json index;
+ in >> index;
+ for (auto &it:index) {
+ int id = it["type"].get<int>();
+ int state = it["meta"].get<int>();
+ std::string blockName = it["text_type"].get<std::string>();
+ assetIds[blockName] = Block(id, state);
+ }
+ LOG(INFO) << "Loaded " << assetIds.size() << " ids";
+}
+
+AssetManager::~AssetManager() {
+ delete textureAtlas;
+}
+
+//TODO: This function must be replaced with runtime texture atlas generating
+void AssetManager::LoadTextureResources() {
+ std::ifstream in(pathToTextureIndex);
+ nlohmann::json index;
+ in >> index;
+ std::string filename = index["meta"]["image"].get<std::string>();
+ float textureWidth = index["meta"]["size"]["w"].get<int>();
+ float textureHeight = index["meta"]["size"]["h"].get<int>();
+ for (auto &it:index["frames"]) {
+ auto frame = it["frame"];
+ TextureCoordinates coord;
+ coord.x = frame["x"].get<int>() / textureWidth;
+ coord.y = frame["y"].get<int>() / textureHeight;
+ coord.w = frame["w"].get<int>() / textureWidth;
+ coord.h = frame["h"].get<int>() / textureHeight;
+ std::string assetName = it["filename"].get<std::string>();
+ assetName.insert(0, "minecraft/textures/");
+ assetName.erase(assetName.length() - 4);
+ assetTextures[assetName] = coord;
+ }
+
+ textureAtlas = new Texture(filename);
+ LOG(INFO) << "Texture atlas id is " << textureAtlas->texture;
+}
+
+TextureCoordinates AssetManager::GetTextureByAssetName(std::string AssetName) {
+ if (assetTextures.find(AssetName) != assetTextures.end())
+ return assetTextures[AssetName];
+ else
+ return TextureCoordinates{-1, -1, -1, -1};
+}
+
+std::string AssetManager::GetTextureAssetNameByBlockId(BlockTextureId block) {
+ //Block sides: 0 - bottom, 1 - top, 2 - north, 3 - south, 4 - west, 5 - east 6 - every side
+ const std::map<BlockTextureId, std::string> lookupTable = {
+ {BlockTextureId(0, 0), "minecraft/textures/blocks/air"},
+ {BlockTextureId(1, 0), "minecraft/textures/blocks/stone"},
+ {BlockTextureId(1, 1), "minecraft/textures/blocks/stone_granite"},
+
+ {BlockTextureId(2, 0, 0), "minecraft/textures/blocks/dirt"},
+ {BlockTextureId(2, 0, 1), "minecraft/textures/blocks/grass_top"},
+ {BlockTextureId(2, 0, 2), "minecraft/textures/blocks/grass_side"},
+ {BlockTextureId(2, 0, 3), "minecraft/textures/blocks/grass_side"},
+ {BlockTextureId(2, 0, 4), "minecraft/textures/blocks/grass_side"},
+ {BlockTextureId(2, 0, 5), "minecraft/textures/blocks/grass_side"},
+
+ {BlockTextureId(3, 0), "minecraft/textures/blocks/dirt"},
+ {BlockTextureId(4, 0), "minecraft/textures/blocks/cobblestone"},
+ {BlockTextureId(5, 0), "minecraft/textures/blocks/planks"},
+
+ {BlockTextureId(7, 0), "minecraft/textures/blocks/bedrock"},
+
+ {BlockTextureId(17, 0, 0), "minecraft/textures/blocks/log_oak_top"},
+ {BlockTextureId(17, 0, 1), "minecraft/textures/blocks/log_oak_top"},
+ {BlockTextureId(17, 0, 2), "minecraft/textures/blocks/log_oak"},
+ {BlockTextureId(17, 0, 3), "minecraft/textures/blocks/log_oak"},
+ {BlockTextureId(17, 0, 4), "minecraft/textures/blocks/log_oak"},
+ {BlockTextureId(17, 0, 5), "minecraft/textures/blocks/log_oak"},
+
+ {BlockTextureId(17, 1, 0), "minecraft/textures/blocks/log_spruce_top"},
+ {BlockTextureId(17, 1, 1), "minecraft/textures/blocks/log_spruce_top"},
+ {BlockTextureId(17, 1, 2), "minecraft/textures/blocks/log_spruce"},
+ {BlockTextureId(17, 1, 3), "minecraft/textures/blocks/log_spruce"},
+ {BlockTextureId(17, 1, 4), "minecraft/textures/blocks/log_spruce"},
+ {BlockTextureId(17, 1, 5), "minecraft/textures/blocks/log_spruce"},
+
+ {BlockTextureId(17, 2, 0), "minecraft/textures/blocks/log_birch_top"},
+ {BlockTextureId(17, 2, 1), "minecraft/textures/blocks/log_birch_top"},
+ {BlockTextureId(17, 2, 2), "minecraft/textures/blocks/log_birch"},
+ {BlockTextureId(17, 2, 3), "minecraft/textures/blocks/log_birch"},
+ {BlockTextureId(17, 2, 4), "minecraft/textures/blocks/log_birch"},
+ {BlockTextureId(17, 2, 5), "minecraft/textures/blocks/log_birch"},
+
+ {BlockTextureId(17, 3, 0), "minecraft/textures/blocks/log_jungle_top"},
+ {BlockTextureId(17, 3, 1), "minecraft/textures/blocks/log_jungle_top"},
+ {BlockTextureId(17, 3, 2), "minecraft/textures/blocks/log_jungle"},
+ {BlockTextureId(17, 3, 3), "minecraft/textures/blocks/log_jungle"},
+ {BlockTextureId(17, 3, 4), "minecraft/textures/blocks/log_jungle"},
+ {BlockTextureId(17, 3, 5), "minecraft/textures/blocks/log_jungle"},
+
+ {BlockTextureId(18, 0), "minecraft/textures/blocks/leaves_oak"},
+ {BlockTextureId(18, 1), "minecraft/textures/blocks/leaves_spruce"},
+ {BlockTextureId(18, 2), "minecraft/textures/blocks/leaves_birch"},
+ {BlockTextureId(18, 3), "minecraft/textures/blocks/leaves_jungle"},
+
+ {BlockTextureId(61, 0, 0), "minecraft/textures/blocks/furnace_side"},
+ {BlockTextureId(61, 0, 1), "minecraft/textures/blocks/furnace_top"},
+ {BlockTextureId(61, 0, 2), "minecraft/textures/blocks/furnace_front_off"},
+ {BlockTextureId(61, 0, 3), "minecraft/textures/blocks/furnace_side"},
+ {BlockTextureId(61, 0, 4), "minecraft/textures/blocks/furnace_side"},
+ {BlockTextureId(61, 0, 5), "minecraft/textures/blocks/furnace_side"},
+
+ {BlockTextureId(62, 0, 0), "minecraft/textures/blocks/furnace_side"},
+ {BlockTextureId(62, 0, 1), "minecraft/textures/blocks/furnace_top"},
+ {BlockTextureId(62, 0, 2), "minecraft/textures/blocks/furnace_front_on"},
+ {BlockTextureId(62, 0, 3), "minecraft/textures/blocks/furnace_side"},
+ {BlockTextureId(62, 0, 4), "minecraft/textures/blocks/furnace_side"},
+ {BlockTextureId(62, 0, 5), "minecraft/textures/blocks/furnace_side"},
+
+
+ {BlockTextureId(31, 0), "minecraft/textures/blocks/deadbush"},
+ {BlockTextureId(31, 1), "minecraft/textures/blocks/tallgrass"},
+ {BlockTextureId(31, 2), "minecraft/textures/blocks/fern"},
+ };
+ auto ret = lookupTable.find(block);
+ if (ret == lookupTable.end())
+ return "";
+ else
+ return ret->second;
+}
+
+GLuint AssetManager::GetTextureAtlas() {
+ return textureAtlas->texture;
+}
+
+TextureCoordinates AssetManager::GetTextureByBlock(BlockTextureId block) {
+ std::string assetName = this->GetTextureAssetNameByBlockId(block);
+ return this->GetTextureByAssetName(assetName);
+}
+
+const std::map<BlockTextureId, glm::vec4> &AssetManager::GetTextureAtlasIndexes() {
+ if (!textureAtlasIndexes.empty())
+ return textureAtlasIndexes;
+
+ LOG(INFO) << "Initializing texture atlas...";
+ for (int id = 1; id < 128; id++) {
+ for (int state = 0; state < 16; state++) {
+ BlockTextureId blockTextureId(id, state, 6);
+ if (!this->GetTextureByBlock(blockTextureId) &&
+ !this->GetTextureByBlock(BlockTextureId(id, state, 0))) {
+ continue;
+ }
+ if (this->GetTextureByBlock(blockTextureId)) {
+ for (int i = 0; i < 6; i++) {
+ TextureCoordinates tc = this->GetTextureByBlock(BlockTextureId(id, state, 6));
+ textureAtlasIndexes[BlockTextureId(id, state, i)] = glm::vec4(tc.x, tc.y, tc.w, tc.h);
+ }
+ } else {
+ for (int i = 0; i < 6; i++) {
+ TextureCoordinates tc = this->GetTextureByBlock(BlockTextureId(id, state, i));
+ textureAtlasIndexes[BlockTextureId(id, state, i)] = glm::vec4(tc.x, tc.y, tc.w, tc.h);
+ }
+ }
+ }
+ }
+ LOG(INFO) << "Created " << textureAtlasIndexes.size() << " texture indexes";
+
+ return textureAtlasIndexes;
+}
diff --git a/old/core/AssetManager.hpp b/old/core/AssetManager.hpp
new file mode 100644
index 0000000..667140a
--- /dev/null
+++ b/old/core/AssetManager.hpp
@@ -0,0 +1,75 @@
+#pragma once
+
+#include <experimental/filesystem>
+#include <map>
+
+#include <GL/glew.h>
+#include <glm/vec4.hpp>
+#include <nlohmann/json.hpp>
+
+#include "../world/Block.hpp"
+#include "../graphics/Texture.hpp"
+
+struct TextureCoordinates {
+ TextureCoordinates(float x = -1, float y = -1, float w = -1, float h = -1) : x(x), y(y), w(w), h(h) {}
+
+ bool operator==(const TextureCoordinates &rhs) const {
+ return x == rhs.x &&
+ y == rhs.y &&
+ w == rhs.w &&
+ h == rhs.h;
+ }
+
+ explicit operator bool() const {
+ return !(*this == TextureCoordinates(-1, -1, -1, -1));
+ }
+
+ float x, y, w, h;
+};
+
+struct BlockTextureId {
+ //Block sides: 0 - bottom, 1 - top, 2 - north, 3 - south, 4 - west, 5 - east 6 - every side
+ BlockTextureId(int id = 0, int state = 0, int side = 6) : id(id), state(state), side(side) {}
+
+ int id:9;
+ int state:4;
+ int side:3;
+
+
+ bool operator<(const BlockTextureId &rhs) const {
+ if (id < rhs.id)
+ return true;
+ if (rhs.id < id)
+ return false;
+ if (state < rhs.state)
+ return true;
+ if (rhs.state < state)
+ return false;
+ return side < rhs.side;
+ }
+};
+
+class AssetManager {
+ Texture *textureAtlas;
+ std::map<std::string, Block> assetIds;
+ std::map<std::string, TextureCoordinates> assetTextures;
+ std::map<BlockTextureId,glm::vec4> textureAtlasIndexes;
+public:
+ AssetManager();
+
+ ~AssetManager();
+
+ void LoadTextureResources();
+
+ TextureCoordinates GetTextureByAssetName(std::string AssetName);
+
+ std::string GetTextureAssetNameByBlockId(BlockTextureId block);
+
+ GLuint GetTextureAtlas();
+
+ const std::map<BlockTextureId,glm::vec4> &GetTextureAtlasIndexes();
+
+ void LoadIds();
+
+ TextureCoordinates GetTextureByBlock(BlockTextureId block);
+};
diff --git a/old/core/Core.cpp b/old/core/Core.cpp
new file mode 100644
index 0000000..e98d204
--- /dev/null
+++ b/old/core/Core.cpp
@@ -0,0 +1,457 @@
+#include "Core.hpp"
+
+//Core::Core():toRenderMutex("toRender"),availableChunksMutex("availableChunks") {
+Core::Core() {
+ LOG(INFO) << "Core initializing...";
+ InitSfml(900, 450, "AltCraft");
+ glCheckError();
+ InitGlew();
+ glCheckError();
+ client = new NetworkClient("127.0.0.1", 25565, "HelloOne", isRunning);
+ gameState = new GameState(client, isRunning);
+ gameStateLoopThread = std::thread(&Core::UpdateGameState, this);
+ sectionUpdateLoopThread = std::thread(&Core::UpdateSections, this);
+ assetManager = new AssetManager;
+ PrepareToRendering();
+ LOG(INFO) << "Core is initialized";
+ glCheckError();
+}
+
+Core::~Core() {
+ LOG(INFO) << "Core stopping...";
+ gameStateLoopThread.join();
+ sectionUpdateLoopThread.join();
+ delete shader;
+ delete gameState;
+ delete client;
+ delete assetManager;
+ delete window;
+ LOG(INFO) << "Core is stopped";
+}
+
+void Core::Exec() {
+ LOG(INFO) << "Main loop is executing!";
+ isRunning = true;
+ while (isRunning) {
+ static sf::Clock clock, clock1;
+ deltaTime = clock.getElapsedTime().asSeconds();
+ absTime = clock1.getElapsedTime().asSeconds();
+ clock.restart();
+
+ static bool alreadyDone = false;
+ if (gameState->g_IsGameStarted && !alreadyDone) {
+ alreadyDone = true;
+ UpdateChunksToRender();
+ }
+
+ std::ostringstream toWindow;
+ auto camPos = gameState->Position();
+ auto velPos = glm::vec3(gameState->g_PlayerVelocityX, gameState->g_PlayerVelocityY,
+ gameState->g_PlayerVelocityZ);
+ toWindow << std::setprecision(2) << std::fixed;
+ toWindow << "Pos: " << camPos.x << ", " << camPos.y << ", " << camPos.z << "; ";
+ toWindow << "Health: " << gameState->g_PlayerHealth << "; ";
+ //toWindow << "OG: " << gameState->g_OnGround << "; ";
+ toWindow << "Vel: " << velPos.x << ", " << velPos.y << ", " << velPos.z << "; ";
+ toWindow << "FPS: " << (1.0f / deltaTime) << " ";
+ toWindow << " (" << deltaTime * 1000 << "ms); ";
+ toWindow << "Tickrate: " << tickRate << " (" << (1.0 / tickRate * 1000) << "ms); ";
+ toWindow << "Sections: " << sectionRate << " (" << (1.0 / sectionRate * 1000) << "ms); ";
+ window->setTitle(toWindow.str());
+
+ HandleEvents();
+ if (isMouseCaptured) HandleMouseCapture();
+ glCheckError();
+
+ RenderFrame();
+ if (isRendersShouldBeCreated) {
+ availableChunksMutex.lock();
+ for (auto &it:renders) {
+ auto pair = std::make_pair(it, RenderSection(&gameState->world, it));
+ availableChunks.insert(pair);
+ }
+ renders.clear();
+ availableChunksMutex.unlock();
+ isRendersShouldBeCreated = false;
+ waitRendersCreated.notify_all();
+ }
+
+ }
+}
+
+void Core::RenderFrame() {
+ glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ switch (currentState) {
+ case MainMenu:
+ //RenderGui(MenuScreen);
+ break;
+ case Loading:
+ //RenderGui(LoadingScreen);
+ break;
+ case Playing:
+ RenderWorld();
+ //RenderGui(HUD);
+ break;
+ case PauseMenu:
+ RenderWorld();
+ //RenderGui(PauseGui);
+ break;
+ }
+
+ window->display();
+}
+
+void Core::InitSfml(unsigned int WinWidth, unsigned int WinHeight, std::string WinTitle) {
+ LOG(INFO) << "Creating window: " << WinWidth << "x" << WinHeight << " \"" << WinTitle << "\"";
+ sf::ContextSettings contextSetting;
+ contextSetting.majorVersion = 3;
+ contextSetting.minorVersion = 3;
+ contextSetting.attributeFlags = contextSetting.Core;
+ contextSetting.depthBits = 24;
+ window = new sf::Window(sf::VideoMode(WinWidth, WinHeight), WinTitle, sf::Style::Default, contextSetting);
+ glCheckError();
+ //window->setVerticalSyncEnabled(true);
+ //window->setPosition(sf::Vector2i(sf::VideoMode::getDesktopMode().width / 2, sf::VideoMode::getDesktopMode().height / 2));
+ window->setPosition(sf::Vector2i(sf::VideoMode::getDesktopMode().width / 2 - window->getSize().x / 2,
+ sf::VideoMode::getDesktopMode().height / 2 - window->getSize().y / 2));
+
+ SetMouseCapture(false);
+}
+
+void Core::InitGlew() {
+ LOG(INFO) << "Initializing GLEW";
+ glewExperimental = GL_TRUE;
+ GLenum glewStatus = glewInit();
+ glCheckError();
+ if (glewStatus != GLEW_OK) {
+ LOG(FATAL) << "Failed to initialize GLEW: " << glewGetErrorString(glewStatus);
+ }
+ glViewport(0, 0, width(), height());
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_BACK);
+ glFrontFace(GL_CCW);
+ //glEnable(GL_BLEND);
+ //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glCheckError();
+}
+
+unsigned int Core::width() {
+ return window->getSize().x;
+}
+
+unsigned int Core::height() {
+ return window->getSize().y;
+}
+
+void Core::HandleEvents() {
+ sf::Event event;
+ while (window->pollEvent(event)) {
+ switch (event.type) {
+ case sf::Event::Closed:
+ LOG(INFO) << "Received close event by window closing";
+ isRunning = false;
+ break;
+ case sf::Event::Resized:
+ glViewport(0, 0, width(), height());
+ break;
+ case sf::Event::KeyPressed:
+ if (!window->hasFocus()) break;
+ switch (event.key.code) {
+ case sf::Keyboard::Escape:
+ LOG(INFO) << "Received close event by esc";
+ isRunning = false;
+ break;
+ case sf::Keyboard::T:
+ SetMouseCapture(!isMouseCaptured);
+ break;
+ case sf::Keyboard::L:
+ ChunkDistance++;
+ LOG(INFO) << "Increased render distance: " << ChunkDistance;
+ break;
+ case sf::Keyboard::K:
+ if (ChunkDistance > 1) {
+ ChunkDistance--;
+ LOG(INFO) << "Decreased render distance: " << ChunkDistance;
+ }
+ break;
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ if (window->hasFocus()) {
+ if (sf::Keyboard::isKeyPressed(sf::Keyboard::W)) gameState->HandleMovement(GameState::FORWARD, deltaTime);
+ if (sf::Keyboard::isKeyPressed(sf::Keyboard::S)) gameState->HandleMovement(GameState::BACKWARD, deltaTime);
+ if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) gameState->HandleMovement(GameState::LEFT, deltaTime);
+ if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) gameState->HandleMovement(GameState::RIGHT, deltaTime);
+ if (sf::Keyboard::isKeyPressed(sf::Keyboard::Space)) gameState->HandleMovement(GameState::JUMP, deltaTime);
+ UpdateChunksToRender();
+ }
+}
+
+void Core::HandleMouseCapture() {
+ sf::Vector2i mousePos = sf::Mouse::getPosition(*window);
+ sf::Vector2i center = sf::Vector2i(window->getSize().x / 2, window->getSize().y / 2);
+ sf::Mouse::setPosition(center, *window);
+ mouseXDelta = (mousePos - center).x, mouseYDelta = (center - mousePos).y;
+ const float Sensetivity = 0.7f;
+ gameState->HandleRotation(mouseXDelta * Sensetivity, mouseYDelta * Sensetivity);
+ //camera.ProcessMouseMovement(mouseXDelta, mouseYDelta);
+}
+
+void Core::RenderWorld() {
+ shader->Use();
+ glCheckError();
+
+ GLint projectionLoc = glGetUniformLocation(shader->Program, "projection");
+ GLint viewLoc = glGetUniformLocation(shader->Program, "view");
+ GLint timeLoc = glGetUniformLocation(shader->Program, "time");
+ glm::mat4 projection = glm::perspective(45.0f, (float) width() / (float) height(), 0.1f, 10000000.0f);
+ glm::mat4 view = gameState->GetViewMatrix();
+ glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection));
+ glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
+ glUniform1f(timeLoc, absTime);
+ glUniform2f(glGetUniformLocation(shader->Program, "windowSize"), width(), height());
+
+ glCheckError();
+
+ toRenderMutex.lock();
+ for (auto &render : toRender) {
+ availableChunksMutex.lock();
+ auto iterator = availableChunks.find(render);
+ if (iterator == availableChunks.end()) {
+ availableChunksMutex.unlock();
+ continue;
+ }
+ /*Section &section = *iterator->second.GetSection();
+ //availableChunksMutex.unlock();
+
+ std::vector<Vector> sectionCorners = {
+ Vector(0, 0, 0),
+ Vector(0, 0, 16),
+ Vector(0, 16, 0),
+ Vector(0, 16, 16),
+ Vector(16, 0, 0),
+ Vector(16, 0, 16),
+ Vector(16, 16, 0),
+ Vector(16, 16, 16),
+ };
+ bool isBreak = true;
+ glm::mat4 vp = projection * view;
+ for (auto &it:sectionCorners) {
+ glm::vec3 point(section.GetPosition().GetX() * 16 + it.GetX(),
+ section.GetPosition().GetY() * 16 + it.GetY(),
+ section.GetPosition().GetZ() * 16 + it.GetZ());
+ glm::vec4 p = vp * glm::vec4(point, 1);
+ glm::vec3 res = glm::vec3(p) / p.w;
+ if (res.x < 1 && res.x > -1 && res.y < 1 && res.y > -1 && res.z > 0) {
+ isBreak = false;
+ break;
+ }
+ }
+ if (isBreak && glm::length(gameState->Position() -
+ glm::vec3(section.GetPosition().GetX() * 16,
+ section.GetPosition().GetY() * 16,
+ section.GetPosition().GetZ() * 16)) > 30.0f) {
+ availableChunksMutex.unlock();
+ continue;
+ }
+ //availableChunksMutex.lock();*/
+ iterator->second.Render(renderState);
+ availableChunksMutex.unlock();
+ }
+ toRenderMutex.unlock();
+ glCheckError();
+}
+
+void Core::SetMouseCapture(bool IsCaptured) {
+ window->setMouseCursorVisible(!isMouseCaptured);
+ sf::Mouse::setPosition(sf::Vector2i(window->getSize().x / 2, window->getSize().y / 2), *window);
+ isMouseCaptured = IsCaptured;
+ window->setMouseCursorVisible(!IsCaptured);
+}
+
+void Core::PrepareToRendering() {
+ shader = new Shader("./shaders/face.vs", "./shaders/face.fs");
+ shader->Use();
+
+ //TextureAtlas texture
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, assetManager->GetTextureAtlas());
+ glUniform1i(glGetUniformLocation(shader->Program, "textureAtlas"), 0);
+}
+
+void Core::UpdateChunksToRender() {
+ return;
+ Vector playerChunk = Vector(floor(gameState->g_PlayerX / 16.0f), 0, floor(gameState->g_PlayerZ / 16.0f));
+ static Vector previousPlayerChunk = playerChunk;
+ static bool firstTime = true;
+ static int previousRenderDistance = ChunkDistance;
+ if (previousPlayerChunk == playerChunk && !firstTime && ChunkDistance == previousRenderDistance) {
+ return;
+ }
+ previousPlayerChunk = playerChunk;
+ previousRenderDistance = ChunkDistance;
+ toRender.clear();
+ for (auto &it:gameState->world.GetSectionsList()) {
+ Vector chunkPosition = it;
+ chunkPosition.SetY(0);
+ Vector delta = chunkPosition - playerChunk;
+ if (delta.GetMagnitude() > ChunkDistance) continue;
+ toRender.push_back(it);
+ }
+ for (auto &it:toRender) {
+ if (availableChunks.find(it) == availableChunks.end()) {
+ auto pair = std::make_pair(it, RenderSection(&gameState->world, it));
+ pair.second.UpdateState(assetManager->GetTextureAtlasIndexes());
+ availableChunks.insert(pair);
+ } else {
+ //availableChunks.find(it)->second.UpdateState();
+ }
+ }
+ if (firstTime) LOG(INFO) << "Chunks to render: " << toRender.size() << " of " << availableChunks.size();
+ firstTime = false;
+}
+
+void Core::UpdateGameState() {
+ el::Helpers::setThreadName("Game");
+ LOG(INFO) << "GameState thread is started";
+ sf::Clock delta;
+ while (isRunning) {
+ float deltaTime = delta.getElapsedTime().asSeconds();
+ delta.restart();
+ gameState->Update(deltaTime);
+ const double targetDelta = 1 / 60.0;
+ std::chrono::duration<double, std::ratio<1, 1>> timeToSleep(targetDelta - delta.getElapsedTime().asSeconds());
+ std::this_thread::sleep_for(timeToSleep);
+ tickRate = 1 / delta.getElapsedTime().asSeconds();
+ }
+ LOG(INFO) << "GameState thread is stopped";
+}
+
+void Core::UpdateSections() {
+ glm::vec3 playerPosition = gameState->Position();
+ float playerPitch = gameState->Pitch();
+ float playerYaw = gameState->Yaw();
+ sf::Clock delta;
+ std::vector<Vector> chunksToRender;
+ auto currentSectionIterator = chunksToRender.begin();
+ while (isRunning) {
+ delta.restart();
+ if (glm::length(glm::distance(gameState->Position(), playerPosition)) > 5.0f) {
+ chunksToRender.clear();
+ playerPosition = gameState->Position();
+ Vector playerChunk = Vector(floor(playerPosition.x / 16.0f), 0, floor(playerPosition.z / 16.0f));
+ for (auto &it:gameState->world.GetSectionsList()) {
+ Vector chunkPosition = it;
+ chunkPosition.SetY(0);
+ Vector delta = chunkPosition - playerChunk;
+ if (delta.GetMagnitude() > ChunkDistance) continue;
+ chunksToRender.push_back(it);
+ }
+ std::sort(chunksToRender.begin(), chunksToRender.end(), [playerChunk](auto first, auto second) {
+ glm::vec3 fDistance = first - playerChunk;
+ glm::vec3 sDistance = second - playerChunk;
+ return glm::length(fDistance) < glm::length(sDistance);
+ });
+ for (auto &it:chunksToRender) {
+ availableChunksMutex.lock();
+ if (availableChunks.find(it) == availableChunks.end()) {
+ availableChunksMutex.unlock();
+ renders.push_back(it);
+ } else
+ availableChunksMutex.unlock();
+ }
+ if (!renders.empty()) {
+ std::mutex mutex;
+ std::unique_lock<std::mutex> lock(mutex);
+ isRendersShouldBeCreated = true;
+ while (isRendersShouldBeCreated)
+ waitRendersCreated.wait(lock);
+ }
+ currentSectionIterator = chunksToRender.begin();
+ toRenderMutex.lock();
+ toRender = chunksToRender;
+ toRenderMutex.unlock();
+ }
+ if (currentSectionIterator != chunksToRender.end()) {
+ availableChunksMutex.lock();
+ auto iterator = availableChunks.find(*currentSectionIterator);
+ if (iterator != availableChunks.end() && iterator->second.IsNeedUpdate()) {
+ RenderSection rs = std::move(iterator->second);
+ availableChunks.erase(iterator);
+ auto pair = std::make_pair(*currentSectionIterator, rs);
+ availableChunksMutex.unlock();
+
+ pair.second.UpdateState(assetManager->GetTextureAtlasIndexes());
+
+ availableChunksMutex.lock();
+ availableChunks.insert(pair);
+ }
+ availableChunksMutex.unlock();
+ currentSectionIterator = std::next(currentSectionIterator);
+ }
+ if (gameState->Pitch() != playerPitch || gameState->Yaw() != playerYaw) {
+ playerPitch = gameState->Pitch();
+ playerYaw = gameState->Yaw();
+ const std::vector<Vector> sectionCorners = {
+ Vector(0, 0, 0),
+ Vector(0, 0, 16),
+ Vector(0, 16, 0),
+ Vector(0, 16, 16),
+ Vector(16, 0, 0),
+ Vector(16, 0, 16),
+ Vector(16, 16, 0),
+ Vector(16, 16, 16),
+ };
+ const glm::mat4 projection = glm::perspective(45.0f, (float)width() / (float)height(), 0.1f, 10000000.0f);
+ const glm::mat4 view = gameState->GetViewMatrix();
+ const glm::mat4 vp = projection * view;
+ for (auto& section: toRender) {
+ bool isCulled = true;
+ for (auto &it : sectionCorners) {
+ glm::vec3 point(section.GetX() * 16 + it.GetX(),
+ section.GetY() * 16 + it.GetY(),
+ section.GetZ() * 16 + it.GetZ());
+ glm::vec4 p = vp * glm::vec4(point, 1);
+ glm::vec3 res = glm::vec3(p) / p.w;
+ if (res.x < 1 && res.x > -1 && res.y < 1 && res.y > -1 && res.z > 0) {
+ isCulled = false;
+ break;
+ }
+ }
+ bool isVisible = !isCulled || glm::length(gameState->Position() -
+ glm::vec3(section.GetX() * 16, section.GetY() * 16, section.GetZ() * 16)) < 30.0f;
+ availableChunksMutex.lock();
+ auto iter = availableChunks.find(section);
+ if (iter != availableChunks.end())
+ iter->second.SetEnabled(isVisible);
+ availableChunksMutex.unlock();
+
+ }
+ }
+ using namespace std::chrono_literals;
+ std::this_thread::sleep_for(5ms);
+ sectionRate = delta.getElapsedTime().asSeconds();
+ delta.restart();
+ }
+}
+
+MyMutex::MyMutex(std::string name) {
+ str = name;
+}
+
+void MyMutex::lock() {
+ LOG(WARNING) << "Thread " << std::this_thread::get_id() << " locked mutex " << str;
+ mtx.lock();
+}
+
+void MyMutex::unlock() {
+ LOG(WARNING) << "Thread " << std::this_thread::get_id() << " unlocked mutex " << str;
+ mtx.unlock();
+} \ No newline at end of file
diff --git a/src/core/Core.hpp b/old/core/Core.hpp
index 039b3a3..aaa143f 100644
--- a/src/core/Core.hpp
+++ b/old/core/Core.hpp
@@ -8,12 +8,12 @@
#include <glm/gtc/type_ptr.hpp>
#include <SFML/Window.hpp>
-#include <world/GameState.hpp>
-#include <core/AssetManager.hpp>
-#include <graphics/Shader.hpp>
-#include <graphics/Gui.hpp>
-#include <graphics/RenderSection.hpp>
-#include <network/NetworkClient.hpp>
+#include "../world/GameState.hpp"
+#include "AssetManager.hpp"
+#include "../graphics/Shader.hpp"
+#include "../graphics/Gui.hpp"
+#include "../graphics/RenderSection.hpp"
+#include "../network/NetworkClient.hpp"
struct MyMutex {
std::mutex mtx;
diff --git a/src/core/Event.cpp b/old/core/Event.cpp
index 10b2eaa..3b2cc7f 100644
--- a/src/core/Event.cpp
+++ b/old/core/Event.cpp
@@ -1,4 +1,4 @@
-#include <core/Event.hpp>
+#include "Event.hpp"
#include <easylogging++.h>
std::queue <Event> EventAgregator::eventsToHandle;
diff --git a/src/core/Event.hpp b/old/core/Event.hpp
index cfa990a..a8de1f3 100644
--- a/src/core/Event.hpp
+++ b/old/core/Event.hpp
@@ -9,7 +9,7 @@
#include <variant>
#include <functional>
-#include <Vector.hpp>
+#include "../Vector.hpp"
enum class EventType {
Echo,
diff --git a/old/graphics/Gui.cpp b/old/graphics/Gui.cpp
new file mode 100644
index 0000000..9e18549
--- /dev/null
+++ b/old/graphics/Gui.cpp
@@ -0,0 +1 @@
+#include "Gui.hpp" \ No newline at end of file
diff --git a/src/graphics/Gui.hpp b/old/graphics/Gui.hpp
index e22a0a7..e22a0a7 100644
--- a/src/graphics/Gui.hpp
+++ b/old/graphics/Gui.hpp
diff --git a/old/graphics/RenderSection.cpp b/old/graphics/RenderSection.cpp
new file mode 100644
index 0000000..8ebd2c0
--- /dev/null
+++ b/old/graphics/RenderSection.cpp
@@ -0,0 +1,356 @@
+#include "RenderSection.hpp"
+#include <thread>
+
+const GLfloat vertices[] = {
+ 0, 0, 0,
+ 1, 0, 1,
+ 1, 0, 0,
+
+ 0, 0, 0,
+ 0, 0, 1,
+ 1, 0, 1,
+};
+
+const GLfloat uv_coords[] = {
+ 0.0f, 0.0f,
+ 1.0f, 1.0f,
+ 0.0f, 1.0f,
+
+ 0.0f, 0.0f,
+ 1.0f, 0.0f,
+ 1.0f, 1.0f,
+};
+
+void RenderState::SetActiveVao(GLuint Vao) {
+ if (Vao != ActiveVao) {
+ glBindVertexArray(Vao);
+ ActiveVao = Vao;
+ }
+}
+
+void RenderState::SetActiveShader(GLuint Shader) {
+ if (Shader != ActiveShader) {
+ glUseProgram(Shader);
+ ActiveShader = Shader;
+ }
+}
+
+const GLuint magicUniqueConstant = 88375;
+GLuint RenderSection::VboVertices = magicUniqueConstant;
+GLuint RenderSection::VboUvs = magicUniqueConstant;
+std::map<GLuint, int> RenderSection::refCounterVbo;
+std::map<GLuint, int> RenderSection::refCounterVao;
+
+
+RenderSection::RenderSection(World *world, Vector position) : sectionPosition(position), world(world) {
+ if (VboVertices == magicUniqueConstant) {
+ glGenBuffers(1, &VboVertices);
+ glGenBuffers(1, &VboUvs);
+
+ //Cube vertices
+ glBindBuffer(GL_ARRAY_BUFFER, VboVertices);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
+
+ //Cube UVs
+ glBindBuffer(GL_ARRAY_BUFFER, VboUvs);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(uv_coords), uv_coords, GL_STATIC_DRAW);
+
+ LOG(INFO) << "Created VBOs with vertices (" << VboVertices << ") and UVs (" << VboUvs
+ << ") for ordinary blocks";
+ }
+
+ glGenBuffers(1, &VboTextures);
+ if (refCounterVbo.find(VboTextures) == refCounterVbo.end())
+ refCounterVbo[VboTextures] = 0;
+ refCounterVbo[VboTextures]++;
+
+ glGenBuffers(1, &VboModels);
+ if (refCounterVbo.find(VboModels) == refCounterVbo.end())
+ refCounterVbo[VboModels] = 0;
+ refCounterVbo[VboModels]++;
+
+ glGenBuffers(1, &VboColors);
+ if (refCounterVbo.find(VboColors) == refCounterVbo.end())
+ refCounterVbo[VboColors] = 0;
+ refCounterVbo[VboColors]++;
+
+ glGenVertexArrays(1, &Vao);
+ if (refCounterVao.find(Vao) == refCounterVao.end())
+ refCounterVao[Vao] = 0;
+ refCounterVao[Vao]++;
+
+ glBindVertexArray(Vao);
+ {
+ //Cube vertices
+ GLuint VertAttribPos = 0;
+ glBindBuffer(GL_ARRAY_BUFFER, VboVertices);
+ glVertexAttribPointer(VertAttribPos, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), nullptr);
+ glEnableVertexAttribArray(VertAttribPos);
+
+ //Cube UVs
+ GLuint UvAttribPos = 2;
+ glBindBuffer(GL_ARRAY_BUFFER, VboUvs);
+ glVertexAttribPointer(UvAttribPos, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), nullptr);
+ glEnableVertexAttribArray(UvAttribPos);
+
+ //Textures
+ GLuint textureAttribPos = 7;
+ glBindBuffer(GL_ARRAY_BUFFER, VboTextures);
+ glVertexAttribPointer(textureAttribPos, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), nullptr);
+ glEnableVertexAttribArray(textureAttribPos);
+ glVertexAttribDivisor(textureAttribPos, 1);
+ glCheckError();
+
+ //Blocks models
+ GLuint matAttribPos = 8;
+ size_t sizeOfMat4 = 4 * 4 * sizeof(GLfloat);
+ glBindBuffer(GL_ARRAY_BUFFER, VboModels);
+ glVertexAttribPointer(matAttribPos + 0, 4, GL_FLOAT, GL_FALSE, sizeOfMat4, nullptr);
+ glVertexAttribPointer(matAttribPos + 1, 4, GL_FLOAT, GL_FALSE, sizeOfMat4, (void *) (1 * 4 * sizeof(GLfloat)));
+ glVertexAttribPointer(matAttribPos + 2, 4, GL_FLOAT, GL_FALSE, sizeOfMat4, (void *) (2 * 4 * sizeof(GLfloat)));
+ glVertexAttribPointer(matAttribPos + 3, 4, GL_FLOAT, GL_FALSE, sizeOfMat4, (void *) (3 * 4 * sizeof(GLfloat)));
+ glEnableVertexAttribArray(matAttribPos + 0);
+ glEnableVertexAttribArray(matAttribPos + 1);
+ glEnableVertexAttribArray(matAttribPos + 2);
+ glEnableVertexAttribArray(matAttribPos + 3);
+ glVertexAttribDivisor(matAttribPos + 0, 1);
+ glVertexAttribDivisor(matAttribPos + 1, 1);
+ glVertexAttribDivisor(matAttribPos + 2, 1);
+ glVertexAttribDivisor(matAttribPos + 3, 1);
+
+ //Color
+ GLuint colorAttribPos = 12;
+ glBindBuffer(GL_ARRAY_BUFFER, VboColors);
+ glVertexAttribPointer(colorAttribPos, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), nullptr);
+ glEnableVertexAttribArray(colorAttribPos);
+ glVertexAttribDivisor(colorAttribPos, 1);
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ }
+ glBindVertexArray(0);
+ glCheckError();
+}
+
+RenderSection::~RenderSection() {
+ refCounterVbo[VboTextures]--;
+ refCounterVbo[VboModels]--;
+ refCounterVbo[VboColors]--;
+ refCounterVao[Vao]--;
+ if (refCounterVbo[VboTextures] <= 0)
+ glDeleteBuffers(1, &VboTextures);
+
+ if (refCounterVbo[VboModels] <= 0)
+ glDeleteBuffers(1, &VboTextures);
+ if (refCounterVbo[VboColors] <= 0)
+ glDeleteBuffers(1, &VboColors);
+
+ if (refCounterVao[Vao] <= 0)
+ glDeleteVertexArrays(1, &Vao);
+}
+
+void RenderSection::UpdateState(const std::map<BlockTextureId, glm::vec4> &textureAtlas) {
+ Section &section = world->GetSection(sectionPosition);
+ models.clear();
+ textures.clear();
+ colors.clear();
+ for (int y = 0; y < 16; y++) {
+ for (int z = 0; z < 16; z++) {
+ for (int x = 0; x < 16; x++) {
+ Vector blockPos = Vector(x, y, z) + (sectionPosition * 16);
+ Block &block = world->GetBlock(blockPos);
+ if (block.id == 0)
+ continue;
+
+ auto checkBlockVisibility = [&](Vector block) -> bool {
+ return section.GetBlock(block).id == 0 ||
+ section.GetBlock(block).id == 31 ||
+ section.GetBlock(block).id == 18;
+ };
+
+ unsigned char isVisible = 0;
+ if (x == 0 || x == 15 || y == 0 || y == 15 || z == 0 || z == 15) {
+ isVisible = 0b1111'1111; //All faces is visible
+ } else {
+ isVisible |= checkBlockVisibility(Vector(x - 1, y, z)) << 0;
+ isVisible |= checkBlockVisibility(Vector(x + 1, y, z)) << 1;
+ isVisible |= checkBlockVisibility(Vector(x, y + 1, z)) << 2;
+ isVisible |= checkBlockVisibility(Vector(x, y - 1, z)) << 3;
+ isVisible |= checkBlockVisibility(Vector(x, y, z - 1)) << 4;
+ isVisible |= checkBlockVisibility(Vector(x, y, z + 1)) << 5;
+ }
+
+ if (isVisible == 0x00)
+ continue;
+
+ glm::mat4 transform;
+ transform = glm::translate(transform, glm::vec3(sectionPosition.GetX() * 16,
+ sectionPosition.GetY() * 16,
+ sectionPosition.GetZ() * 16));
+ transform = glm::translate(transform, glm::vec3(x, y, z));
+ glm::vec3 biomeColor(0.275, 0.63, 0.1);
+ glm::vec3 color(0.0f, 0.0f, 0.0f);
+ if (block.id == 31 || block.id == 18)
+ color = biomeColor;
+
+ if (block.id == 31) { //X-cross like blocks rendering
+ auto texture = textureAtlas.find(BlockTextureId(block.id, block.state, 2));
+ for (int i = 0; i < 4; i++) {
+ textures.push_back(texture->second);
+ colors.push_back(color);
+ }
+ glm::mat4 faceTransform = glm::translate(transform, glm::vec3(0.15f, 0, 0.15f));
+ faceTransform = glm::scale(faceTransform, glm::vec3(1.0f, 0.9f, 1.0f));
+ faceTransform = glm::rotate(faceTransform, glm::radians(90.0f), glm::vec3(0, 0.0f, 1.0f));
+ faceTransform = glm::rotate(faceTransform, glm::radians(45.0f), glm::vec3(1.0f, 0.0f, 0));
+ for (int i = 0; i < 4; i++) {
+ models.push_back(faceTransform);
+ faceTransform = glm::translate(faceTransform, glm::vec3(0.0f, 0.0f, 0.5f));
+ faceTransform = glm::rotate(faceTransform, glm::radians(90.0f), glm::vec3(1.0f, 0.0f, 0.0f));
+ faceTransform = glm::translate(faceTransform, glm::vec3(0.0f, 0.0f, -0.5f));
+ }
+ continue;
+ }
+
+ if (isVisible >> 0 & 0x1) { //east side of block (X+)
+ glm::mat4 faceTransform = glm::translate(transform, glm::vec3(0, 0, 0));
+ faceTransform = glm::rotate(faceTransform, glm::radians(90.0f), glm::vec3(0, 0.0f, 1.0f));
+ models.push_back(faceTransform);
+ auto texture = textureAtlas.find(BlockTextureId(block.id, block.state, 2));
+ if (texture != textureAtlas.end())
+ textures.push_back(texture->second);
+ else
+ textures.push_back(glm::vec4(0.0546875, 0.00442477876106194690,
+ 0.0078125, 0.00442477876106194690)); //Fallback TNT texture
+ colors.push_back(color);
+ }
+ if (isVisible >> 1 & 0x1) { //west side X-
+ glm::mat4 faceTransform = glm::translate(transform, glm::vec3(1, 0, 0));
+ faceTransform = glm::rotate(faceTransform, glm::radians(90.0f), glm::vec3(0, 0.0f, 1.0f));
+ faceTransform = glm::rotate(faceTransform, glm::radians(180.0f), glm::vec3(1.0f, 0.0f, 0.0f));
+ faceTransform = glm::translate(faceTransform, glm::vec3(0, 0, -1));
+ models.push_back(faceTransform);
+ auto texture = textureAtlas.find(BlockTextureId(block.id, block.state, 3));
+ if (texture != textureAtlas.end())
+ textures.push_back(texture->second);
+ else
+ textures.push_back(glm::vec4(0.0546875, 0.00442477876106194690,
+ 0.0078125, 0.00442477876106194690)); //Fallback TNT texture
+ colors.push_back(color);
+ }
+ if (isVisible >> 2 & 0x1) { //Top side Y+
+ glm::mat4 faceTransform = glm::translate(transform, glm::vec3(0, 1, 0));
+ models.push_back(faceTransform);
+ auto texture = textureAtlas.find(BlockTextureId(block.id, block.state, 1));
+ if (texture != textureAtlas.end())
+ textures.push_back(texture->second);
+ else
+ textures.push_back(glm::vec4(0.0546875, 0.00442477876106194690,
+ 0.0078125, 0.00442477876106194690)); //Fallback TNT texture
+ if (block.id != 2)
+ colors.push_back(color);
+ else
+ colors.push_back(biomeColor);
+ }
+ if (isVisible >> 3 & 0x1) { //Bottom side Y-
+ glm::mat4 faceTransform = glm::translate(transform, glm::vec3(0, 0, 0));
+ faceTransform = glm::rotate(faceTransform, glm::radians(180.0f), glm::vec3(1.0f, 0, 0));
+ faceTransform = glm::translate(faceTransform, glm::vec3(0, 0, -1));
+ models.push_back(faceTransform);
+ auto texture = textureAtlas.find(BlockTextureId(block.id, block.state, 0));
+ if (texture != textureAtlas.end())
+ textures.push_back(texture->second);
+ else
+ textures.push_back(glm::vec4(0.0546875, 0.00442477876106194690,
+ 0.0078125, 0.00442477876106194690)); //Fallback TNT texture
+ colors.push_back(color);
+ }
+ if (isVisible >> 4 & 0x1) { //south side Z+
+ glm::mat4 faceTransform = glm::translate(transform, glm::vec3(1, 0, 0));
+ faceTransform = glm::rotate(faceTransform, glm::radians(90.0f), glm::vec3(-1.0f, 0.0f, 0.0f));
+ faceTransform = glm::rotate(faceTransform, glm::radians(90.0f), glm::vec3(0.0f, -1.0f, 0.0f));
+ models.push_back(faceTransform);
+ auto texture = textureAtlas.find(BlockTextureId(block.id, block.state, 3));
+ if (texture != textureAtlas.end())
+ textures.push_back(texture->second);
+ else
+ textures.push_back(glm::vec4(0.0546875, 0.00442477876106194690,
+ 0.0078125, 0.00442477876106194690)); //Fallback TNT texture
+ colors.push_back(color);
+ }
+ if (isVisible >> 5 & 0x1) { //north side Z-
+ glm::mat4 faceTransform = glm::translate(transform, glm::vec3(0, 0, 1));
+ faceTransform = glm::rotate(faceTransform, glm::radians(90.0f), glm::vec3(-1.0f, 0.0f, 0.0f));
+ faceTransform = glm::rotate(faceTransform, glm::radians(90.0f), glm::vec3(0.0f, -1.0f, 0.0f));
+ faceTransform = glm::translate(faceTransform, glm::vec3(0, 0, -1));
+ faceTransform = glm::rotate(faceTransform, glm::radians(180.0f), glm::vec3(1, 0, 0.0f));
+ faceTransform = glm::translate(faceTransform, glm::vec3(0, 0, -1.0f));
+ models.push_back(faceTransform);
+ auto texture = textureAtlas.find(BlockTextureId(block.id, block.state, 4));
+ if (texture != textureAtlas.end())
+ textures.push_back(texture->second);
+ else
+ textures.push_back(glm::vec4(0.0546875, 0.00442477876106194690,
+ 0.0078125, 0.00442477876106194690)); //Fallback TNT texture
+ colors.push_back(color);
+ }
+ }
+ }
+ }
+ numOfFaces = textures.size();
+ hash = section.GetHash();
+}
+
+void RenderSection::Render(RenderState &state) {
+ if (!isEnabled) return;
+ if (!models.empty()) {
+ glBindBuffer(GL_ARRAY_BUFFER, VboTextures);
+ glBufferData(GL_ARRAY_BUFFER, textures.size() * sizeof(glm::vec4), textures.data(), GL_DYNAMIC_DRAW);
+ textures.clear();
+
+ glBindBuffer(GL_ARRAY_BUFFER, VboModels);
+ glBufferData(GL_ARRAY_BUFFER, models.size() * sizeof(glm::mat4), models.data(), GL_DYNAMIC_DRAW);
+ models.clear();
+
+ glBindBuffer(GL_ARRAY_BUFFER, VboColors);
+ glBufferData(GL_ARRAY_BUFFER, colors.size() * sizeof(glm::vec3), colors.data(), GL_DYNAMIC_DRAW);
+ colors.clear();
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ }
+ state.SetActiveVao(Vao);
+ glDrawArraysInstanced(GL_TRIANGLES, 0, 6, numOfFaces);
+ glCheckError();
+}
+
+Section *RenderSection::GetSection() {
+ return &world->GetSection(sectionPosition);
+}
+
+RenderSection::RenderSection(const RenderSection &other) {
+ this->world = other.world;
+ this->VboModels = other.VboModels;
+ this->VboTextures = other.VboTextures;
+ this->VboColors = other.VboColors;
+ this->sectionPosition = other.sectionPosition;
+ this->Vao = other.Vao;
+ this->numOfFaces = other.numOfFaces;
+ this->models = other.models;
+ this->textures = other.textures;
+ this->colors = other.colors;
+ this->hash = other.hash;
+
+ refCounterVbo[VboTextures]++;
+ refCounterVbo[VboModels]++;
+ refCounterVbo[VboColors]++;
+ refCounterVao[Vao]++;
+}
+
+void RenderSection::SetEnabled(bool isEnabled) {
+ this->isEnabled = isEnabled;
+}
+
+bool RenderSection::IsNeedUpdate() {
+ size_t currentHash = world->GetSection(sectionPosition).GetHash();
+ bool isNeedUpdate = currentHash != hash;
+ return isNeedUpdate;
+} \ No newline at end of file
diff --git a/src/graphics/RenderSection.hpp b/old/graphics/RenderSection.hpp
index 5973909..7f97624 100644
--- a/src/graphics/RenderSection.hpp
+++ b/old/graphics/RenderSection.hpp
@@ -7,9 +7,9 @@
#include <glm/gtx/transform.hpp>
#include <easylogging++.h>
-#include <core/AssetManager.hpp>
-#include <world/Section.hpp>
-#include <world/World.hpp>
+#include "../core/AssetManager.hpp"
+#include "../world/Section.hpp"
+#include "../world/World.hpp"
class RenderState {
GLuint ActiveVao;
diff --git a/old/graphics/Shader.cpp b/old/graphics/Shader.cpp
new file mode 100644
index 0000000..cf43115
--- /dev/null
+++ b/old/graphics/Shader.cpp
@@ -0,0 +1,115 @@
+#include "Shader.hpp"
+
+Shader::Shader(const GLchar *vertexPath, const GLchar *fragmentPath, const GLchar *geometryPath) {
+ vertex = vertexPath;
+ fragment = fragmentPath;
+ // 1. Получаем исходный код шейдера из filePath
+ std::string vertexCode;
+ std::string fragmentCode;
+ std::string geometryCode;
+ std::ifstream vShaderFile;
+ std::ifstream fShaderFile;
+ std::ifstream gShaderFile;
+ // Удостоверимся, что ifstream объекты могут выкидывать исключения
+ vShaderFile.exceptions(std::ifstream::failbit);
+ fShaderFile.exceptions(std::ifstream::failbit);
+ gShaderFile.exceptions(std::ifstream::failbit);
+ try {
+ // Открываем файлы
+ vShaderFile.open(vertexPath);
+ fShaderFile.open(fragmentPath);
+ if (geometryPath != nullptr)
+ gShaderFile.open(geometryPath);
+ std::stringstream vShaderStream, fShaderStream, gShaderStream;
+ // Считываем данные в потоки
+ vShaderStream << vShaderFile.rdbuf();
+ fShaderStream << fShaderFile.rdbuf();
+ if (geometryPath != nullptr)
+ gShaderStream << gShaderFile.rdbuf();
+ // Закрываем файлы
+ vShaderFile.close();
+ fShaderFile.close();
+ if (geometryPath != nullptr)
+ gShaderFile.close();
+ // Преобразовываем потоки в массив GLchar
+ vertexCode = vShaderStream.str();
+ fragmentCode = fShaderStream.str();
+ if (geometryPath != nullptr)
+ geometryCode = gShaderStream.str();
+ }
+ catch (std::ifstream::failure e) {
+ LOG(ERROR) << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ";
+ }
+ const GLchar *vShaderCode = vertexCode.c_str();
+ const GLchar *fShaderCode = fragmentCode.c_str();
+ const GLchar *gShaderCode = geometryCode.c_str();
+
+ // 2. Сборка шейдеров
+ GLuint vertex, fragment, geometry;
+ GLint success;
+ GLchar infoLog[512];
+
+ // Вершинный шейдер
+ vertex = glCreateShader(GL_VERTEX_SHADER);
+ glShaderSource(vertex, 1, &vShaderCode, NULL);
+ glCompileShader(vertex);
+ // Если есть ошибки - вывести их
+ glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
+ if (!success) {
+ glGetShaderInfoLog(vertex, 512, NULL, infoLog);
+ LOG(ERROR) << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog;
+ };
+
+ // Вершинный шейдер
+ fragment = glCreateShader(GL_FRAGMENT_SHADER);
+ glShaderSource(fragment, 1, &fShaderCode, NULL);
+ glCompileShader(fragment);
+ // Если есть ошибки - вывести их
+ glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
+ if (!success) {
+ glGetShaderInfoLog(fragment, 512, NULL, infoLog);
+ LOG(ERROR) << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog;
+ };
+
+ if (geometryPath != nullptr) {
+ geometry = glCreateShader(GL_GEOMETRY_SHADER);
+ glShaderSource(geometry, 1, &gShaderCode, NULL);
+ glCompileShader(geometry);
+ // Если есть ошибки - вывести их
+ glGetShaderiv(geometry, GL_COMPILE_STATUS, &success);
+ if (!success) {
+ glGetShaderInfoLog(geometry, 512, NULL, infoLog);
+ LOG(ERROR) << "ERROR::SHADER::GEOMETRY::COMPILATION_FAILED\n" << infoLog;
+ };
+ }
+
+ // Шейдерная программа
+ this->Program = glCreateProgram();
+ glAttachShader(this->Program, vertex);
+ glAttachShader(this->Program, fragment);
+ if (geometryPath != nullptr)
+ glAttachShader(this->Program, geometry);
+ glLinkProgram(this->Program);
+ //Если есть ошибки - вывести их
+ glGetProgramiv(this->Program, GL_LINK_STATUS, &success);
+ if (!success) {
+ glGetProgramInfoLog(this->Program, 512, NULL, infoLog);
+ LOG(FATAL) << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog;
+ }
+
+ // Удаляем шейдеры, поскольку они уже в программу и нам больше не нужны.
+ glDeleteShader(vertex);
+ glDeleteShader(fragment);
+}
+
+void Shader::Use() {
+ glUseProgram(this->Program);
+}
+
+void Shader::Reload() {
+ const GLchar *vertexPath = vertex;
+ const GLchar *fragmentPath = fragment;
+ this->~Shader();
+ new(this) Shader(vertexPath, fragmentPath);
+ LOG(INFO) << "Shader is realoded!";
+}
diff --git a/old/graphics/Shader.hpp b/old/graphics/Shader.hpp
new file mode 100644
index 0000000..17a434e
--- /dev/null
+++ b/old/graphics/Shader.hpp
@@ -0,0 +1,24 @@
+#pragma once
+
+#include <string>
+#include <fstream>
+#include <sstream>
+
+#include <easylogging++.h>
+#include <GL/glew.h>
+
+class Shader
+{
+private:
+ const GLchar *vertex;
+ const GLchar *fragment;
+public:
+ // Идентификатор программы
+ GLuint Program;
+ // Конструктор считывает и собирает шейдер
+ Shader(const GLchar* vertexPath, const GLchar* fragmentPath, const GLchar* geometryPath = nullptr);
+ // Использование программы
+ void Use();
+
+ void Reload();
+}; \ No newline at end of file
diff --git a/old/graphics/Texture.cpp b/old/graphics/Texture.cpp
new file mode 100644
index 0000000..5d183c3
--- /dev/null
+++ b/old/graphics/Texture.cpp
@@ -0,0 +1,37 @@
+#include "Texture.hpp"
+
+Texture::Texture(std::string filename, GLenum textureWrapping, GLenum textureFiltering) {
+ glGenTextures(1, &texture);
+ glBindTexture(GL_TEXTURE_2D, texture);
+
+ //Texture options
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, textureWrapping);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, textureWrapping);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, textureFiltering);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ //Image load
+ sf::Image image;
+ if (!image.loadFromFile(filename)) {
+ LOG(ERROR) << "Can't open image " << filename;
+ throw 201;
+ }
+ if (image.getPixelsPtr() == nullptr) {
+ LOG(ERROR) << "Image data is corrupted!";
+ throw 202;
+ }
+ image.flipVertically();
+
+
+ //Creating texture
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.getSize().x, image.getSize().y, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ (GLvoid *) image.getPixelsPtr());
+ glGenerateMipmap(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+}
+
+Texture::~Texture() {
+ glDeleteTextures(1, &texture);
+}
diff --git a/src/graphics/Texture.hpp b/old/graphics/Texture.hpp
index 5b2afcf..5b2afcf 100644
--- a/src/graphics/Texture.hpp
+++ b/old/graphics/Texture.hpp
diff --git a/old/graphics/Widget.cpp b/old/graphics/Widget.cpp
new file mode 100644
index 0000000..278af55
--- /dev/null
+++ b/old/graphics/Widget.cpp
@@ -0,0 +1 @@
+#include "Widget.hpp" \ No newline at end of file
diff --git a/old/graphics/Widget.hpp b/old/graphics/Widget.hpp
new file mode 100644
index 0000000..c4d5dc1
--- /dev/null
+++ b/old/graphics/Widget.hpp
@@ -0,0 +1,8 @@
+#pragma once
+
+class Widget {
+ unsigned int x,y,w,h;
+public:
+ Widget(Widget *parent);
+ ~Widget();
+};
diff --git a/old/main.cpp b/old/main.cpp
new file mode 100644
index 0000000..0f93420
--- /dev/null
+++ b/old/main.cpp
@@ -0,0 +1,35 @@
+#include "core/Core.hpp"
+#include "core/Event.hpp"
+
+const char *getTimeSinceProgramStart(void) {
+ static auto initialTime = std::chrono::steady_clock().now();
+ auto now = std::chrono::steady_clock().now();
+ std::chrono::duration<double> seconds = now-initialTime;
+ static char buffer[30];
+ sprintf(buffer, "%.2f", seconds.count());
+ return buffer;
+}
+
+INITIALIZE_EASYLOGGINGPP
+
+int main_old() {
+ el::Configurations loggerConfiguration;
+ el::Helpers::installCustomFormatSpecifier(
+ el::CustomFormatSpecifier("%startTime", std::bind(getTimeSinceProgramStart)));
+ std::string format = "[%startTime][%level][%thread][%fbase]: %msg";
+ loggerConfiguration.set(el::Level::Info, el::ConfigurationType::Format, format);
+ loggerConfiguration.set(el::Level::Error, el::ConfigurationType::Format, format);
+ loggerConfiguration.set(el::Level::Fatal, el::ConfigurationType::Format, format);
+ loggerConfiguration.set(el::Level::Warning, el::ConfigurationType::Format, format);
+ el::Helpers::setThreadName("Render");
+ el::Loggers::reconfigureAllLoggers(loggerConfiguration);
+ el::Loggers::addFlag(el::LoggingFlag::ColoredTerminalOutput);
+ LOG(INFO) << "Logger is configured";
+
+ LOG(WARNING)<<"Sizeof EventData is "<<sizeof(EventData);
+
+ Core core;
+ core.Exec();
+
+ return 0;
+} \ No newline at end of file
diff --git a/old/network/Network.cpp b/old/network/Network.cpp
new file mode 100644
index 0000000..dcdda10
--- /dev/null
+++ b/old/network/Network.cpp
@@ -0,0 +1,224 @@
+#include "Network.hpp"
+
+Network::Network(std::string address, unsigned short port) {
+ try {
+ socket = new Socket(address, port);
+ stream = new StreamSocket(socket);
+ } catch (std::exception &e) {
+ LOG(FATAL)<<e.what();
+ }
+}
+
+Network::~Network() {
+ delete stream;
+ delete socket;
+}
+
+std::shared_ptr<Packet> Network::ReceivePacket(ConnectionState state) {
+ int packetSize = stream->ReadVarInt();
+ auto packetData = stream->ReadByteArray(packetSize);
+ StreamBuffer streamBuffer(packetData.data(), packetData.size());
+ int packetId = streamBuffer.ReadVarInt();
+ auto packet = ReceivePacketByPacketId(packetId, state, streamBuffer);
+ return packet;
+}
+
+void Network::SendPacket(Packet &packet) {
+ StreamCounter packetSize;
+ packetSize.WriteVarInt(packet.GetPacketId());
+ packet.ToStream(&packetSize);
+ stream->WriteVarInt(packetSize.GetCountedSize());
+ stream->WriteVarInt(packet.GetPacketId());
+ packet.ToStream(stream);
+}
+
+std::shared_ptr<Packet> Network::ReceivePacketByPacketId(int packetId, ConnectionState state, StreamInput &stream) {
+ std::shared_ptr<Packet> packet(nullptr);
+ switch (state) {
+ case Handshaking:
+ switch (packetId) {
+ case PacketNameHandshakingCB::Handshake:
+ packet = std::make_shared<PacketHandshake>();
+ break;
+ }
+ case Login:
+ switch (packetId) {
+ case PacketNameLoginCB::LoginSuccess:
+ packet = std::make_shared<PacketLoginSuccess>();
+ break;
+ }
+ break;
+ case Play:
+ packet = ParsePacketPlay((PacketNamePlayCB) packetId);
+ break;
+ case Status:
+ break;
+ }
+ if (packet.get() != nullptr)
+ packet->FromStream(&stream);
+ return packet;
+}
+
+std::shared_ptr<Packet> Network::ParsePacketPlay(PacketNamePlayCB id) {
+ switch (id) {
+ case SpawnObject:
+ break;
+ case SpawnExperienceOrb:
+ break;
+ case SpawnGlobalEntity:
+ break;
+ case SpawnMob:
+ break;
+ case SpawnPainting:
+ break;
+ case SpawnPlayer:
+ break;
+ case AnimationCB:
+ break;
+ case Statistics:
+ break;
+ case BlockBreakAnimation:
+ break;
+ case UpdateBlockEntity:
+ break;
+ case BlockAction:
+ break;
+ case BlockChange:
+ break;
+ case BossBar:
+ break;
+ case ServerDifficulty:
+ break;
+ case TabCompleteCB:
+ break;
+ case ChatMessageCB:
+ break;
+ case MultiBlockChange:
+ break;
+ case ConfirmTransactionCB:
+ break;
+ case CloseWindowCB:
+ break;
+ case OpenWindow:
+ break;
+ case WindowItems:
+ break;
+ case WindowProperty:
+ break;
+ case SetSlot:
+ break;
+ case SetCooldown:
+ break;
+ case PluginMessageCB:
+ break;
+ case NamedSoundEffect:
+ break;
+ case DisconnectPlay:
+ return std::make_shared<PacketDisconnectPlay>();
+ case EntityStatus:
+ break;
+ case Explosion:
+ break;
+ case UnloadChunk:
+ break;
+ case ChangeGameState:
+ break;
+ case KeepAliveCB:
+ return std::make_shared<PacketKeepAliveCB>();
+ case ChunkData:
+ return std::make_shared<PacketChunkData>();
+ case Effect:
+ break;
+ case Particle:
+ break;
+ case JoinGame:
+ return std::make_shared<PacketJoinGame>();
+ case Map:
+ break;
+ case EntityRelativeMove:
+ break;
+ case EntityLookAndRelativeMove:
+ break;
+ case EntityLook:
+ break;
+ case Entity:
+ break;
+ case VehicleMove:
+ break;
+ case OpenSignEditor:
+ break;
+ case PlayerAbilitiesCB:
+ break;
+ case CombatEvent:
+ break;
+ case PlayerListItem:
+ break;
+ case PlayerPositionAndLookCB:
+ return std::make_shared<PacketPlayerPositionAndLookCB>();
+ case UseBed:
+ break;
+ case DestroyEntities:
+ break;
+ case RemoveEntityEffect:
+ break;
+ case ResourcePackSend:
+ break;
+ case Respawn:
+ break;
+ case EntityHeadLook:
+ break;
+ case WorldBorder:
+ break;
+ case Camera:
+ break;
+ case HeldItemChangeCB:
+ break;
+ case DisplayScoreboard:
+ break;
+ case EntityMetadata:
+ break;
+ case AttachEntity:
+ break;
+ case EntityVelocity:
+ break;
+ case EntityEquipment:
+ break;
+ case SetExperience:
+ break;
+ case UpdateHealth:
+ return std::make_shared<PacketUpdateHealth>();
+ case ScoreboardObjective:
+ break;
+ case SetPassengers:
+ break;
+ case Teams:
+ break;
+ case UpdateScore:
+ break;
+ case SpawnPosition:
+ return std::make_shared<PacketSpawnPosition>();
+ case TimeUpdate:
+ break;
+ case Title:
+ break;
+ case SoundEffect:
+ break;
+ case PlayerListHeaderAndFooter:
+ break;
+ case CollectItem:
+ break;
+ case EntityTeleport:
+ break;
+ case EntityProperties:
+ break;
+ case EntityEffect:
+ break;
+ case UnlockRecipes:
+ break;
+ case SelectAdvancementTab:
+ break;
+ case Advancements:
+ break;
+ }
+ return nullptr;
+}
diff --git a/old/network/Network.hpp b/old/network/Network.hpp
new file mode 100644
index 0000000..1281289
--- /dev/null
+++ b/old/network/Network.hpp
@@ -0,0 +1,26 @@
+#pragma once
+
+#include <memory>
+#include "Socket.hpp"
+#include "Packet.hpp"
+
+enum ConnectionState {
+ Handshaking,
+ Login,
+ Play,
+ Status,
+};
+
+class Network {
+ Socket *socket;
+ StreamSocket *stream;
+
+ std::shared_ptr<Packet> ReceivePacketByPacketId(int packetId, ConnectionState state, StreamInput &stream);
+public:
+ Network(std::string address, unsigned short port);
+ ~Network();
+
+ std::shared_ptr<Packet> ReceivePacket(ConnectionState state = Play);
+ void SendPacket(Packet &packet);
+ std::shared_ptr<Packet> ParsePacketPlay(PacketNamePlayCB id);
+}; \ No newline at end of file
diff --git a/old/network/NetworkClient.cpp b/old/network/NetworkClient.cpp
new file mode 100644
index 0000000..0b759e6
--- /dev/null
+++ b/old/network/NetworkClient.cpp
@@ -0,0 +1,93 @@
+#include "NetworkClient.hpp"
+
+NetworkClient::NetworkClient(std::string address, unsigned short port, std::string username, bool &quit)
+ : network(address, port), isRunning(quit) {
+ state = Handshaking;
+
+ PacketHandshake handshake;
+ handshake.protocolVersion = 335;
+ handshake.serverAddress = "127.0.0.1";
+ handshake.serverPort = 25565;
+ handshake.nextState = 2;
+ network.SendPacket(handshake);
+ state = Login;
+
+ PacketLoginStart loginStart;
+ loginStart.Username = "HelloOne";
+ network.SendPacket(loginStart);
+
+ auto response = std::static_pointer_cast<PacketLoginSuccess>(network.ReceivePacket(Login));
+ if (response->Username != username) {
+ throw std::logic_error("Received username is not sended username");
+ }
+
+ state = Play;
+
+ isActive = true;
+ std::thread thread(&NetworkClient::NetworkLoop, this);
+ std::swap(networkThread, thread);
+}
+
+NetworkClient::~NetworkClient() {
+ isActive = false;
+ networkThread.join();
+}
+
+std::shared_ptr<Packet> NetworkClient::ReceivePacket() {
+ if (toReceive.empty())
+ return std::shared_ptr<Packet>(nullptr);
+ toReceiveMutex.lock();
+ auto ret = toReceive.front();
+ toReceive.pop();
+ toReceiveMutex.unlock();
+ return ret;
+}
+
+void NetworkClient::SendPacket(std::shared_ptr<Packet> packet) {
+ toSendMutex.lock();
+ toSend.push(packet);
+ toSendMutex.unlock();
+}
+
+void NetworkClient::NetworkLoop() {
+ auto timeOfLastKeepAlivePacket = std::chrono::steady_clock::now();
+ el::Helpers::setThreadName("Network");
+ LOG(INFO) << "Network thread is started";
+ try {
+ while (isActive) {
+ toSendMutex.lock();
+ while (!toSend.empty()) {
+ if (toSend.front()!=nullptr)
+ network.SendPacket(*toSend.front());
+ toSend.pop();
+ }
+ toSendMutex.unlock();
+ auto packet = network.ReceivePacket(state);
+ if (packet.get() != nullptr) {
+ if (packet->GetPacketId() != PacketNamePlayCB::KeepAliveCB) {
+ toReceiveMutex.lock();
+ toReceive.push(packet);
+ toReceiveMutex.unlock();
+ } else {
+ timeOfLastKeepAlivePacket = std::chrono::steady_clock::now();
+ auto packetKeepAlive = std::static_pointer_cast<PacketKeepAliveCB>(packet);
+ auto packetKeepAliveSB = std::make_shared<PacketKeepAliveSB>(packetKeepAlive->KeepAliveId);
+ network.SendPacket(*packetKeepAliveSB);
+ }
+ }
+ using namespace std::chrono_literals;
+ if (std::chrono::steady_clock::now() - timeOfLastKeepAlivePacket > 20s) {
+ auto disconnectPacket = std::make_shared<PacketDisconnectPlay>();
+ disconnectPacket->Reason = "Timeout";
+ toReceiveMutex.lock();
+ toReceive.push(disconnectPacket);
+ toReceiveMutex.unlock();
+ break;
+ }
+ }
+ } catch (std::exception &e) {
+ LOG(ERROR) << "Exception catched in NetworkLoop: " << e.what();
+ isRunning = false;
+ }
+ LOG(INFO) << "Network thread is stopped";
+}
diff --git a/old/network/NetworkClient.hpp b/old/network/NetworkClient.hpp
new file mode 100644
index 0000000..cf41f91
--- /dev/null
+++ b/old/network/NetworkClient.hpp
@@ -0,0 +1,26 @@
+#pragma once
+
+#include <thread>
+#include <queue>
+#include <mutex>
+
+#include "Network.hpp"
+
+class NetworkClient {
+ Network network;
+ std::thread networkThread;
+ std::mutex toSendMutex;
+ std::mutex toReceiveMutex;
+ std::queue <std::shared_ptr<Packet>> toSend;
+ std::queue <std::shared_ptr<Packet>> toReceive;
+ bool isActive=true;
+ bool &isRunning;
+ ConnectionState state;
+ void NetworkLoop();
+public:
+ NetworkClient(std::string address, unsigned short port, std::string username, bool &quit);
+ ~NetworkClient();
+
+ std::shared_ptr <Packet> ReceivePacket();
+ void SendPacket(std::shared_ptr<Packet> packet);
+}; \ No newline at end of file
diff --git a/old/network/Packet.hpp b/old/network/Packet.hpp
new file mode 100644
index 0000000..d615332
--- /dev/null
+++ b/old/network/Packet.hpp
@@ -0,0 +1,521 @@
+#pragma once
+
+#include <easylogging++.h>
+
+#include "Stream.hpp"
+
+enum PacketNameLoginSB {
+ LoginStart = 0x00,
+ EncryptionResponse = 0x01,
+};
+enum PacketNamePlaySB {
+ TeleportConfirm,
+ PrepareCraftingGrid,
+ TabCompleteSB,
+ ChatMessageSB,
+ ClientStatus,
+ ClientSettings,
+ ConfirmTransactionSB,
+ EnchantItem,
+ ClickWindow,
+ CloseWindowSB,
+ PluginMessageSB,
+ UseEntity,
+ KeepAliveSB,
+ Player,
+ PlayerPosition,
+ PlayerPositionAndLookSB,
+ PlayerLook,
+ VehicleMoveSB,
+ SteerBoat,
+ PlayerAbilitiesSB,
+ PlayerDigging,
+ EntityAction,
+ SteerVehicle,
+ CraftingBookData,
+ ResourcePackStatus,
+ AdvancementTab,
+ HeldItemChangeSB,
+ CreativeInventoryAction,
+ UpdateSign,
+ AnimationSB,
+ Spectate,
+ PlayerBlockPlacement,
+ UseItem,
+};
+
+enum PacketNameHandshakingCB {
+ Handshake = 0x00,
+};
+enum PacketNameLoginCB {
+ Disconnect = 0x00,
+ EncryptionRequest = 0x01,
+ LoginSuccess = 0x02,
+ SetCompression = 0x03,
+};
+enum PacketNamePlayCB {
+ SpawnObject = 0x00,
+ SpawnExperienceOrb,
+ SpawnGlobalEntity,
+ SpawnMob,
+ SpawnPainting,
+ SpawnPlayer,
+ AnimationCB,
+ Statistics,
+ BlockBreakAnimation,
+ UpdateBlockEntity,
+ BlockAction,
+ BlockChange,
+ BossBar,
+ ServerDifficulty,
+ TabCompleteCB,
+ ChatMessageCB,
+ MultiBlockChange,
+ ConfirmTransactionCB,
+ CloseWindowCB,
+ OpenWindow,
+ WindowItems,
+ WindowProperty,
+ SetSlot,
+ SetCooldown,
+ PluginMessageCB,
+ NamedSoundEffect,
+ DisconnectPlay,
+ EntityStatus,
+ Explosion,
+ UnloadChunk,
+ ChangeGameState,
+ KeepAliveCB,
+ ChunkData,
+ Effect,
+ Particle,
+ JoinGame,
+ Map,
+ EntityRelativeMove,
+ EntityLookAndRelativeMove,
+ EntityLook,
+ Entity,
+ VehicleMove,
+ OpenSignEditor,
+ PlayerAbilitiesCB,
+ CombatEvent,
+ PlayerListItem,
+ PlayerPositionAndLookCB,
+ UseBed,
+ UnlockRecipes,
+ DestroyEntities,
+ RemoveEntityEffect,
+ ResourcePackSend,
+ Respawn,
+ EntityHeadLook,
+ SelectAdvancementTab,
+ WorldBorder,
+ Camera,
+ HeldItemChangeCB,
+ DisplayScoreboard,
+ EntityMetadata,
+ AttachEntity,
+ EntityVelocity,
+ EntityEquipment,
+ SetExperience,
+ UpdateHealth,
+ ScoreboardObjective,
+ SetPassengers,
+ Teams,
+ UpdateScore,
+ SpawnPosition,
+ TimeUpdate,
+ Title,
+ SoundEffect,
+ PlayerListHeaderAndFooter,
+ CollectItem,
+ EntityTeleport,
+ Advancements,
+ EntityProperties,
+ EntityEffect,
+};
+
+struct Packet {
+ virtual ~Packet() = default;
+ virtual void ToStream(StreamOutput *stream) = 0;
+ virtual void FromStream(StreamInput *stream) = 0;
+ virtual int GetPacketId() = 0;
+};
+
+struct PacketHandshake : Packet {
+ void ToStream(StreamOutput *stream) override {
+ stream->WriteVarInt(protocolVersion);
+ stream->WriteString(serverAddress);
+ stream->WriteUShort(serverPort);
+ stream->WriteVarInt(nextState);
+ }
+
+ void FromStream(StreamInput *stream) override {
+ protocolVersion = stream->ReadVarInt();
+ serverAddress = stream->ReadString();
+ serverPort = stream->ReadUShort();
+ nextState = stream->ReadVarInt();
+ }
+
+ int GetPacketId() override {
+ return PacketNameHandshakingCB::Handshake;
+ }
+
+ int protocolVersion;
+ std::string serverAddress;
+ unsigned short serverPort;
+ int nextState;
+};
+
+struct PacketLoginStart : Packet {
+ void ToStream(StreamOutput *stream) override {
+ stream->WriteString(Username);
+ }
+
+ void FromStream(StreamInput *stream) override {
+ Username = stream->ReadString();
+ }
+
+ int GetPacketId() override {
+ return PacketNameLoginSB::LoginStart;
+ }
+
+ std::string Username;
+};
+
+struct PacketLoginSuccess : Packet {
+ void ToStream(StreamOutput *stream) override {
+ stream->WriteString(Uuid);
+ stream->WriteString(Username);
+ }
+
+ void FromStream(StreamInput *stream) override {
+ Uuid = stream->ReadString();
+ Username = stream->ReadString();
+ }
+
+ int GetPacketId() override {
+ return PacketNameLoginCB::LoginSuccess;
+ }
+
+ std::string Uuid;
+ std::string Username;
+};
+
+struct PacketJoinGame : Packet {
+ void ToStream(StreamOutput *stream) override {
+ stream->WriteInt(EntityId);
+ stream->WriteUByte(Gamemode);
+ stream->WriteInt(Dimension);
+ stream->WriteUByte(Difficulty);
+ stream->WriteUByte(MaxPlayers);
+ stream->WriteString(LevelType);
+ stream->WriteBool(ReducedDebugInfo);
+ }
+
+ void FromStream(StreamInput *stream) override {
+ EntityId = stream->ReadInt();
+ Gamemode = stream->ReadUByte();
+ Dimension = stream->ReadInt();
+ Difficulty = stream->ReadUByte();
+ MaxPlayers = stream->ReadUByte();
+ LevelType = stream->ReadString();
+ ReducedDebugInfo = stream->ReadBool();
+ }
+
+ int GetPacketId() override {
+ return PacketNamePlayCB::JoinGame;
+ }
+
+ int EntityId;
+ unsigned char Gamemode;
+ int Dimension;
+ unsigned char Difficulty;
+ unsigned char MaxPlayers;
+ std::string LevelType;
+ bool ReducedDebugInfo;
+};
+
+struct PacketDisconnectPlay : Packet {
+ void ToStream(StreamOutput *stream) override {
+ stream->WriteString(Reason); //TODO: Implement chat-wrapper
+ }
+
+ void FromStream(StreamInput *stream) override {
+ Reason = stream->ReadChat();
+ }
+
+ int GetPacketId() override {
+ return PacketNamePlayCB::DisconnectPlay;
+ }
+
+ std::string Reason;
+};
+
+struct PacketSpawnPosition : Packet {
+ void ToStream(StreamOutput *stream) override {
+ stream->WritePosition(Location);
+ }
+
+ void FromStream(StreamInput *stream) override {
+ Location = stream->ReadPosition();
+ }
+
+ int GetPacketId() override {
+ return PacketNamePlayCB::SpawnPosition;
+ }
+
+ Vector Location;
+};
+
+struct PacketKeepAliveCB : Packet {
+ void ToStream(StreamOutput *stream) override {
+ stream->WriteVarInt(KeepAliveId);
+ }
+
+ void FromStream(StreamInput *stream) override {
+ KeepAliveId = stream->ReadVarInt();
+ }
+
+ int GetPacketId() override {
+ return PacketNamePlayCB::KeepAliveCB;
+ }
+
+ int KeepAliveId;
+};
+
+struct PacketKeepAliveSB : Packet {
+ void ToStream(StreamOutput *stream) override {
+ stream->WriteVarInt(KeepAliveId);
+ }
+
+ void FromStream(StreamInput *stream) override {
+ KeepAliveId = stream->ReadVarInt();
+ }
+
+ int GetPacketId() override {
+ return PacketNamePlaySB::KeepAliveSB;
+ }
+
+ int KeepAliveId;
+
+ PacketKeepAliveSB(int KeepAliveId) : KeepAliveId(KeepAliveId) {}
+};
+
+struct PacketPlayerPositionAndLookCB : Packet {
+ void ToStream(StreamOutput *stream) override {
+ stream->WriteDouble(X);
+ stream->WriteDouble(Y);
+ stream->WriteDouble(Z);
+ stream->WriteFloat(Yaw);
+ stream->WriteFloat(Pitch);
+ stream->WriteUByte(Flags);
+ stream->WriteVarInt(TeleportId);
+ }
+
+ void FromStream(StreamInput *stream) override {
+ X = stream->ReadDouble();
+ Y = stream->ReadDouble();
+ Z = stream->ReadDouble();
+ Yaw = stream->ReadFloat();
+ Pitch = stream->ReadFloat();
+ Flags = stream->ReadUByte();
+ TeleportId = stream->ReadVarInt();
+ }
+
+ int GetPacketId() override {
+ return PacketNamePlayCB::PlayerPositionAndLookCB;
+ }
+
+ double X;
+ double Y;
+ double Z;
+ float Yaw;
+ float Pitch;
+ unsigned char Flags;
+ int TeleportId;
+};
+
+struct PacketTeleportConfirm : Packet {
+ void ToStream(StreamOutput *stream) override {
+ stream->WriteVarInt(TeleportId);
+ }
+
+ void FromStream(StreamInput *stream) override {
+ TeleportId = stream->ReadVarInt();
+ }
+
+ int GetPacketId() override {
+ return PacketNamePlaySB::TeleportConfirm;
+ }
+
+ int TeleportId;
+
+ PacketTeleportConfirm(int TeleportId) : TeleportId(TeleportId) {}
+};
+
+struct PacketClientStatus : Packet {
+ void ToStream(StreamOutput *stream) override {
+ stream->WriteVarInt(ActionId);
+ }
+
+ void FromStream(StreamInput *stream) override {
+ ActionId = stream->ReadVarInt();
+ }
+
+ int GetPacketId() override {
+ return PacketNamePlaySB::ClientStatus;
+ }
+
+ int ActionId;
+
+ PacketClientStatus(int ActionId) : ActionId(ActionId) {}
+};
+
+struct PacketPlayerPositionAndLookSB : Packet {
+ void ToStream(StreamOutput *stream) override {
+ stream->WriteDouble(X);
+ stream->WriteDouble(FeetY);
+ stream->WriteDouble(Z);
+ stream->WriteFloat(Yaw);
+ stream->WriteFloat(Pitch);
+ stream->WriteBool(OnGround);
+ }
+
+ void FromStream(StreamInput *stream) override {
+ X = stream->ReadDouble();
+ FeetY = stream->ReadDouble();
+ Z = stream->ReadDouble();
+ Yaw = stream->ReadFloat();
+ Pitch = stream->ReadFloat();
+ OnGround = stream->ReadBool();
+ }
+
+ int GetPacketId() override {
+ return PacketNamePlaySB::PlayerPositionAndLookSB;
+ }
+
+
+ double X;
+ double FeetY;
+ double Z;
+ float Yaw;
+ float Pitch;
+ bool OnGround;
+
+ PacketPlayerPositionAndLookSB(double X, double FeetY, double Z,
+ float Yaw, float Pitch, bool OnGround) : X(X), FeetY(FeetY), Z(Z), Yaw(Yaw),
+ Pitch(Pitch), OnGround(OnGround) {}
+};
+
+struct PacketChunkData : Packet {
+ void ToStream(StreamOutput *stream) override {
+ stream->WriteInt(ChunkX);
+ stream->WriteInt(ChunkZ);
+ stream->WriteBool(GroundUpContinuous);
+ stream->WriteInt(PrimaryBitMask);
+ stream->WriteVarInt(Data.size());
+ stream->WriteByteArray(Data);
+ stream->WriteVarInt(BlockEntities.size());
+ LOG(FATAL) << "Serializing unimplemented packet";
+ }
+
+ void FromStream(StreamInput *stream) override {
+ ChunkX = stream->ReadInt();
+ ChunkZ = stream->ReadInt();
+ GroundUpContinuous = stream->ReadBool();
+ PrimaryBitMask = stream->ReadVarInt();
+ int Size = stream->ReadVarInt();
+ Data = stream->ReadByteArray(Size);
+ int NumberOfBlockEntities = stream->ReadVarInt(); //TODO: Need NBT
+ for (int i = 0; i < NumberOfBlockEntities; i++) {
+ //BlockEntities[i] = stream->ReadNbt();
+ }
+ }
+
+ int GetPacketId() override {
+ return PacketNamePlayCB::ChunkData;
+ }
+
+ int ChunkX;
+ int ChunkZ;
+ bool GroundUpContinuous;
+ int PrimaryBitMask;
+ //int Size;
+ std::vector<unsigned char> Data;
+ //int NumberOfBlockEntities;
+ std::vector<int> BlockEntities; //TODO: Replace int with NbtTag and implement NbtTree
+};
+
+struct PacketPlayerPosition : Packet {
+ void ToStream(StreamOutput *stream) override {
+ stream->WriteDouble(X);
+ stream->WriteDouble(FeetY);
+ stream->WriteDouble(Z);
+ stream->WriteBool(OnGround);
+ }
+
+ void FromStream(StreamInput *stream) override {
+ X = stream->ReadDouble();
+ FeetY = stream->ReadDouble();
+ Z = stream->ReadDouble();
+ OnGround = stream->ReadBool();
+ }
+
+ int GetPacketId() override {
+ return PacketNamePlaySB::PlayerPosition;
+ }
+
+ double X;
+ double FeetY;
+ double Z;
+ bool OnGround;
+
+ PacketPlayerPosition(double X, double Y, double Z, bool ground) : X(X), FeetY(Y), Z(Z), OnGround(ground) {}
+};
+
+struct PacketPlayerLook : Packet {
+ void ToStream(StreamOutput *stream) override {
+ stream->WriteFloat(Yaw);
+ stream->WriteFloat(Pitch);
+ stream->WriteBool(OnGround);
+ }
+
+ void FromStream(StreamInput *stream) override {
+ Yaw = stream->ReadFloat();
+ Pitch = stream->ReadFloat();
+ OnGround = stream->ReadBool();
+ }
+
+ int GetPacketId() override {
+ return PacketNamePlaySB::PlayerLook;
+ }
+
+ float Yaw;
+ float Pitch;
+ bool OnGround;
+
+ PacketPlayerLook(float Yaw, float Pitch, bool ground) : Yaw(Yaw), Pitch(Pitch), OnGround(ground) {}
+};
+
+struct PacketUpdateHealth : Packet {
+ void ToStream(StreamOutput *stream) override {
+ stream->WriteFloat(Health);
+ stream->WriteVarInt(Food);
+ stream->WriteFloat(FoodSaturation);
+ }
+
+ void FromStream(StreamInput *stream) override {
+ Health = stream->ReadFloat();
+ Food = stream->ReadVarInt();
+ FoodSaturation = stream->ReadFloat();
+ }
+
+ int GetPacketId() override {
+ return PacketNamePlayCB::UpdateHealth;
+ }
+
+ float Health;
+ int Food;
+ float FoodSaturation;
+}; \ No newline at end of file
diff --git a/old/network/Socket.cpp b/old/network/Socket.cpp
new file mode 100644
index 0000000..2bbf49a
--- /dev/null
+++ b/old/network/Socket.cpp
@@ -0,0 +1,29 @@
+#include "Socket.hpp"
+
+Socket::Socket(std::string address, unsigned short port) {
+ sf::Socket::Status connectionStatus = socket.connect(sf::IpAddress(address), port);
+ if (connectionStatus == sf::Socket::Status::Error)
+ throw std::runtime_error("Can't connect to remote server");
+ else if (connectionStatus != sf::Socket::Status::Done)
+ throw std::runtime_error("Connection failed with unknown reason");
+}
+
+Socket::~Socket() {
+ socket.disconnect();
+}
+
+void Socket::Read(unsigned char *buffPtr, size_t buffLen) {
+ size_t received = 0;
+ socket.receive(buffPtr, buffLen, received);
+ size_t totalReceived = received;
+ while (totalReceived < buffLen) {
+ if (socket.receive(buffPtr + totalReceived, buffLen - totalReceived, received) != sf::Socket::Done)
+ throw std::runtime_error("Raw socket data receiving is failed");
+ totalReceived += received;
+ }
+}
+
+void Socket::Write(unsigned char *buffPtr, size_t buffLen) {
+ if (socket.send(buffPtr, buffLen) != sf::Socket::Done)
+ throw std::runtime_error("Raw socket data sending is failed");
+}
diff --git a/old/network/Socket.hpp b/old/network/Socket.hpp
new file mode 100644
index 0000000..48bcad9
--- /dev/null
+++ b/old/network/Socket.hpp
@@ -0,0 +1,46 @@
+#pragma once
+
+#include <string>
+
+#include <SFML/Network.hpp>
+
+/**
+ * Platform independent class for working with platform dependent hardware socket
+ * @brief Wrapper around raw sockets
+ * @warning Connection state is based on lifetime of Socket object instance, ie connected at ctor and disconnect at dtor
+ * @todo Replace SFML's socket with WinSock and POSIX's socket implementation
+ */
+class Socket {
+ sf::TcpSocket socket;
+public:
+ /**
+ * Constructs Socket class instance from IP's string and Port number and connects to remote server
+ * @param[in] address IP address of remote server. String should be ANSI and contains 4 one-byte values separated by dots
+ * @param[in] port target port of remote server to connect
+ * @throw std::runtime_error if connection is failed
+ */
+ Socket(std::string address, unsigned short port);
+
+ /**
+ * Destruct Socket instance and disconnect from server
+ * @warning There is no way to force disconnect, except use delete for manually allocated objects and scope of visibility for variables on stack
+ */
+ ~Socket();
+
+ /**
+ * Reads data from socket and write to buffer
+ * @warning This is blocking function, and execution flow will not be returned until all required data is sended
+ * @warning Reported buffer length must be <= actual size of buffer, or memory corruption will be caused
+ * @param[out] buffPtr Pointer to buffer, where data must be placed
+ * @param[in] buffLen Length of data, that must be readed from server and writed to buffer
+ */
+ void Read(unsigned char *buffPtr, size_t buffLen);
+
+ /**
+ * Writes data from buffer to socket
+ * @warning This is blocking function, and execution flow will not be returned until all required data is received
+ * @param[in] buffPtr Pointer to buffer that contain data to send
+ * @param[in] buffLen Length of buffer
+ */
+ void Write(unsigned char *buffPtr, size_t buffLen);
+}; \ No newline at end of file
diff --git a/old/network/Stream.cpp b/old/network/Stream.cpp
new file mode 100644
index 0000000..54b1e1b
--- /dev/null
+++ b/old/network/Stream.cpp
@@ -0,0 +1,348 @@
+#include "Stream.hpp"
+
+const int MAX_VARINT_LENGTH = 5;
+
+bool StreamInput::ReadBool() {
+ unsigned char value;
+ ReadData(&value, 1);
+ return value != 0;
+}
+
+signed char StreamInput::ReadByte() {
+ signed char value;
+ ReadData((unsigned char *) &value, 1);
+ endswap(value);
+ return value;
+}
+
+unsigned char StreamInput::ReadUByte() {
+ unsigned char value;
+ ReadData(&value, 1);
+ endswap(value);
+ return value;
+}
+
+short StreamInput::ReadShort() {
+ unsigned short value;
+ ReadData((unsigned char *) &value, 2);
+ endswap(value);
+ return value;
+}
+
+unsigned short StreamInput::ReadUShort() {
+ unsigned short value;
+ ReadData((unsigned char *) &value, 2);
+ endswap(value);
+ return value;
+}
+
+int StreamInput::ReadInt() {
+ int value;
+ ReadData((unsigned char *) &value, 4);
+ endswap(value);
+ return value;
+}
+
+long long StreamInput::ReadLong() {
+ long long value;
+ ReadData((unsigned char *) &value, 8);
+ endswap(value);
+ return value;
+}
+
+float StreamInput::ReadFloat() {
+ float value;
+ ReadData((unsigned char *) &value, 4);
+ endswap(value);
+ return value;
+}
+
+double StreamInput::ReadDouble() {
+ double value;
+ ReadData((unsigned char *) &value, 8);
+ endswap(value);
+ return value;
+}
+
+std::string StreamInput::ReadString() {
+ int strLength = ReadVarInt();
+ unsigned char *buff = new unsigned char[strLength + 1];
+ ReadData(buff, strLength);
+ buff[strLength] = 0;
+ std::string str((char *) buff);
+ delete buff;
+ return str;
+}
+
+std::string StreamInput::ReadChat() {
+ std::string str, jsonStr = ReadString();
+ nlohmann::json json;
+ try {
+ json = nlohmann::json::parse(jsonStr);
+ } catch (std::exception &e) {
+ LOG(WARNING) << "Chat json parsing failed: " << e.what();
+ LOG(WARNING) << "Corrupted json: " << jsonStr;
+ return "";
+ }
+ if (json.find("translate") != json.end())
+ if (json["translate"].get<std::string>() == "multiplayer.disconnect.kicked")
+ return "kicked by operator";
+ for (auto &it:json["extra"]) {
+ str += it["text"].get<std::string>();
+ }
+ return str;
+}
+
+int StreamInput::ReadVarInt() {
+ unsigned char data[MAX_VARINT_LENGTH] = {0};
+ size_t dataLen = 0;
+ do {
+ ReadData(&data[dataLen], 1);
+ } while ((data[dataLen++] & 0x80) != 0);
+
+ int readed = 0;
+ int result = 0;
+ char read;
+ do {
+ read = data[readed];
+ int value = (read & 0b01111111);
+ result |= (value << (7 * readed));
+ readed++;
+ } while ((read & 0b10000000) != 0);
+
+ return result;
+}
+
+long long StreamInput::ReadVarLong() {
+ return 0;
+}
+
+std::vector<unsigned char> StreamInput::ReadEntityMetadata() {
+ return std::vector<unsigned char>();
+}
+
+std::vector<unsigned char> StreamInput::ReadSlot() {
+ return std::vector<unsigned char>();
+}
+
+std::vector<unsigned char> StreamInput::ReadNbtTag() {
+ return std::vector<unsigned char>();
+}
+
+Vector StreamInput::ReadPosition() {
+ unsigned long long t = ReadLong();
+ int x = t >> 38;
+ int y = (t >> 26) & 0xFFF;
+ int z = t << 38 >> 38;
+ if (x >= pow(2, 25)) {
+ x -= pow(2, 26);
+ }
+ if (y >= pow(2, 11)) {
+ y -= pow(2, 12);
+ }
+ if (z >= pow(2, 25)) {
+ z -= pow(2, 26);
+ }
+ return Vector(x, y, z);
+}
+
+unsigned char StreamInput::ReadAngle() {
+ return ReadUByte();
+}
+
+std::vector<unsigned char> StreamInput::ReadUuid() {
+ unsigned char buff[16];
+ ReadData(buff, 16);
+ endswap(buff, 16);
+ return std::vector<unsigned char>(buff, buff + 16);
+}
+
+std::vector<unsigned char> StreamInput::ReadByteArray(size_t arrLength) {
+ unsigned char *buffer = new unsigned char[arrLength];
+ ReadData(buffer, arrLength);
+ std::vector<unsigned char> ret(buffer, buffer + arrLength);
+ delete buffer;
+ return ret;
+
+}
+
+void StreamOutput::WriteBool(bool value) {
+ unsigned char val = value ? 1 : 0;
+ endswap(val);
+ WriteData(&val, 1);
+}
+
+void StreamOutput::WriteByte(signed char value) {
+ endswap(value);
+ WriteData((unsigned char *) &value, 1);
+}
+
+void StreamOutput::WriteUByte(unsigned char value) {
+ endswap(value);
+ WriteData(&value, 1);
+}
+
+void StreamOutput::WriteShort(short value) {
+ endswap(value);
+ WriteData((unsigned char *) &value, 2);
+}
+
+void StreamOutput::WriteUShort(unsigned short value) {
+ endswap(value);
+ WriteData((unsigned char *) &value, 2);
+}
+
+void StreamOutput::WriteInt(int value) {
+ endswap(value);
+ WriteData((unsigned char *) &value, 4);
+}
+
+void StreamOutput::WriteLong(long long value) {
+ endswap(value);
+ WriteData((unsigned char *) &value, 8);
+}
+
+void StreamOutput::WriteFloat(float value) {
+ endswap(value);
+ WriteData((unsigned char *) &value, 4);
+}
+
+void StreamOutput::WriteDouble(double value) {
+ endswap(value);
+ WriteData((unsigned char *) &value, 8);
+}
+
+void StreamOutput::WriteString(std::string value) {
+ WriteVarInt(value.size());
+ WriteData((unsigned char *) value.data(), value.size());
+}
+
+void StreamOutput::WriteChat(std::string value) {
+ WriteString(value);
+}
+
+void StreamOutput::WriteVarInt(int value) {
+ unsigned char buff[5];
+ size_t len = 0;
+ do {
+ unsigned char temp = (unsigned char) (value & 0b01111111);
+ value >>= 7;
+ if (value != 0) {
+ temp |= 0b10000000;
+ }
+ buff[len] = temp;
+ len++;
+ } while (value != 0);
+ WriteData(buff, len);
+}
+
+void StreamOutput::WriteVarLong(long long value) {
+ unsigned char buff[10];
+ size_t len = 0;
+ do {
+ unsigned char temp = (unsigned char) (value & 0b01111111);
+ value >>= 7;
+ if (value != 0) {
+ temp |= 0b10000000;
+ }
+ buff[len] = temp;
+ len++;
+ } while (value != 0);
+ WriteData(buff, len);
+}
+
+void StreamOutput::WriteEntityMetadata(std::vector<unsigned char> value) {
+ LOG(FATAL) << "Used unimplemented WriteEntityMetadata: " << value.size();
+}
+
+void StreamOutput::WriteSlot(std::vector<unsigned char> value) {
+ LOG(FATAL) << "Used unimplemented WriteSlot " << value.size();
+}
+
+void StreamOutput::WriteNbtTag(std::vector<unsigned char> value) {
+ LOG(FATAL) << "Used unimplemented WriteNbtTag " << value.size();
+}
+
+void StreamOutput::WritePosition(Vector value) {
+ LOG(FATAL) << "Used unimplemented Position: " << value.GetX() << ", " << value.GetY() << " " << value.GetZ();
+}
+
+void StreamOutput::WriteAngle(unsigned char value) {
+ WriteUByte(value);
+}
+
+void StreamOutput::WriteUuid(std::vector<unsigned char> value) {
+ WriteByteArray(value);
+}
+
+void StreamOutput::WriteByteArray(std::vector<unsigned char> value) {
+ WriteData(value.data(), value.size());
+}
+
+void StreamBuffer::ReadData(unsigned char *buffPtr, size_t buffLen) {
+ size_t bufferLengthLeft = buffer + bufferLength - bufferPtr;
+ if (bufferLengthLeft < buffLen)
+ throw std::runtime_error("Required data is more, than in buffer available");
+ std::memcpy(buffPtr, bufferPtr, buffLen);
+ bufferPtr += buffLen;
+}
+
+void StreamBuffer::WriteData(unsigned char *buffPtr, size_t buffLen) {
+ size_t bufferLengthLeft = buffer + bufferLength - bufferPtr;
+ if (bufferLengthLeft < buffLen)
+ throw std::runtime_error("Required data is more, than in buffer available");
+ std::memcpy(bufferPtr, buffPtr, buffLen);
+ bufferPtr += buffLen;
+}
+
+StreamBuffer::StreamBuffer(unsigned char *data, size_t dataLen) {
+ buffer = new unsigned char[dataLen];
+ bufferPtr = buffer;
+ bufferLength = dataLen;
+ std::memcpy(buffer, data, dataLen);
+}
+
+StreamBuffer::StreamBuffer(size_t bufferLen) {
+ buffer = new unsigned char[bufferLen];
+ bufferPtr = buffer;
+ bufferLength = bufferLen;
+ for (unsigned char *p = buffer; p != buffer + bufferLength; ++p)
+ *p = 0;
+}
+
+StreamBuffer::~StreamBuffer() {
+ delete buffer;
+}
+
+std::vector<unsigned char> StreamBuffer::GetBuffer() {
+ return std::vector<unsigned char>(buffer, buffer + bufferLength);
+}
+
+void StreamCounter::WriteData(unsigned char *buffPtr, size_t buffLen) {
+ buffPtr++;
+ size += buffLen;
+}
+
+StreamCounter::StreamCounter(size_t initialSize) : size(initialSize) {
+
+}
+
+StreamCounter::~StreamCounter() {
+
+}
+
+size_t StreamCounter::GetCountedSize() {
+ return size;
+}
+
+void StreamSocket::ReadData(unsigned char *buffPtr, size_t buffLen) {
+ socket->Read(buffPtr, buffLen);
+}
+
+void StreamSocket::WriteData(unsigned char *buffPtr, size_t buffLen) {
+ socket->Write(buffPtr, buffLen);
+}
+
+StreamSocket::StreamSocket(Socket *socketPtr) : socket(socketPtr) {
+
+} \ No newline at end of file
diff --git a/old/network/Stream.hpp b/old/network/Stream.hpp
new file mode 100644
index 0000000..bf75bdb
--- /dev/null
+++ b/old/network/Stream.hpp
@@ -0,0 +1,107 @@
+#pragma once
+
+#include <algorithm>
+#include <string>
+#include <stdexcept>
+#include <vector>
+#include <cstring>
+
+#include <nlohmann/json.hpp>
+#include <easylogging++.h>
+
+#include "Socket.hpp"
+#include "../Vector.hpp"
+#include "../Utility.hpp"
+
+class Stream {
+public:
+ virtual ~Stream() {};
+};
+
+class StreamInput : Stream {
+ virtual void ReadData(unsigned char *buffPtr, size_t buffLen) = 0;
+public:
+ virtual ~StreamInput() = default;
+ bool ReadBool();
+ signed char ReadByte();
+ unsigned char ReadUByte();
+ short ReadShort();
+ unsigned short ReadUShort();
+ int ReadInt();
+ long long ReadLong();
+ float ReadFloat();
+ double ReadDouble();
+ std::string ReadString();
+ std::string ReadChat();
+ int ReadVarInt();
+ long long ReadVarLong();
+ std::vector<unsigned char> ReadEntityMetadata();
+ std::vector<unsigned char> ReadSlot();
+ std::vector<unsigned char> ReadNbtTag();
+ Vector ReadPosition();
+ unsigned char ReadAngle();
+ std::vector<unsigned char> ReadUuid();
+ std::vector<unsigned char> ReadByteArray(size_t arrLength);
+};
+
+class StreamOutput : Stream {
+ virtual void WriteData(unsigned char *buffPtr, size_t buffLen) = 0;
+public:
+ virtual ~StreamOutput() = default;
+ void WriteBool(bool value);
+ void WriteByte(signed char value);
+ void WriteUByte(unsigned char value);
+ void WriteShort(short value);
+ void WriteUShort(unsigned short value);
+ void WriteInt(int value);
+ void WriteLong(long long value);
+ void WriteFloat(float value);
+ void WriteDouble(double value);
+ void WriteString(std::string value);
+ void WriteChat(std::string value);
+ void WriteVarInt(int value);
+ void WriteVarLong(long long value);
+ void WriteEntityMetadata(std::vector<unsigned char> value);
+ void WriteSlot(std::vector<unsigned char> value);
+ void WriteNbtTag(std::vector<unsigned char> value);
+ void WritePosition(Vector value);
+ void WriteAngle(unsigned char value);
+ void WriteUuid(std::vector<unsigned char> value);
+ void WriteByteArray(std::vector<unsigned char> value);
+};
+
+class StreamBuffer : public StreamInput, public StreamOutput {
+ unsigned char *buffer;
+ unsigned char *bufferPtr;
+ size_t bufferLength;
+
+ void ReadData(unsigned char *buffPtr, size_t buffLen) override;
+ void WriteData(unsigned char *buffPtr, size_t buffLen) override;
+
+public:
+ StreamBuffer(unsigned char *data, size_t dataLen);
+ StreamBuffer(size_t bufferLen);
+ ~StreamBuffer();
+
+ std::vector<unsigned char> GetBuffer();
+};
+
+class StreamCounter : public StreamOutput {
+ void WriteData(unsigned char *buffPtr, size_t buffLen) override;
+
+ size_t size;
+public:
+ StreamCounter(size_t initialSize = 0);
+ ~StreamCounter();
+
+ size_t GetCountedSize();
+};
+
+class StreamSocket : public StreamInput, public StreamOutput {
+ Socket *socket;
+ void ReadData(unsigned char *buffPtr, size_t buffLen) override;
+ void WriteData(unsigned char *buffPtr, size_t buffLen) override;
+public:
+ StreamSocket(Socket *socketPtr);
+ ~StreamSocket() = default;
+}; \ No newline at end of file
diff --git a/old/world/Block.cpp b/old/world/Block.cpp
new file mode 100644
index 0000000..e88068a
--- /dev/null
+++ b/old/world/Block.cpp
@@ -0,0 +1,17 @@
+#include "Block.hpp"
+
+Block::~Block() {}
+
+Block::Block(unsigned short id, unsigned char state) : id(id), state(state) {}
+
+Block::Block() : id(0), state(0) {}
+
+bool operator<(const Block &lhs, const Block &rhs) {
+ if (lhs.id < rhs.id)
+ return true;
+ if (lhs.id == rhs.id) {
+ if (lhs.state != rhs.state)
+ return lhs.state < rhs.state;
+ }
+ return false;
+}
diff --git a/old/world/Block.hpp b/old/world/Block.hpp
new file mode 100644
index 0000000..2f823fe
--- /dev/null
+++ b/old/world/Block.hpp
@@ -0,0 +1,15 @@
+#pragma once
+
+struct Block {
+ Block();
+
+ Block(unsigned short id, unsigned char state);
+
+ ~Block();
+
+ unsigned short id : 13;
+ unsigned char state : 4;
+ //unsigned char light:4;
+};
+
+bool operator<(const Block &lhs, const Block &rhs); \ No newline at end of file
diff --git a/old/world/Collision.cpp b/old/world/Collision.cpp
new file mode 100644
index 0000000..4f2c837
--- /dev/null
+++ b/old/world/Collision.cpp
@@ -0,0 +1,28 @@
+#include "Collision.hpp"
+
+bool TestCollision(AABB first, AABB second) {
+ double firstXl = first.x;
+ double firstXr = first.x + first.w;
+
+ double firstYl = first.y;
+ double firstYr = first.y + first.h;
+
+ double firstZl = first.z;
+ double firstZr = first.z + first.l;
+
+
+ double secondXl = second.x;
+ double secondXr = second.x + second.w;
+
+ double secondYl = second.y;
+ double secondYr = second.y + second.h;
+
+ double secondZl = second.z;
+ double secondZr = second.z + second.l;
+
+ bool collidesOnX = firstXr >= secondXl && firstXl <= secondXr;
+ bool collidesOnY = firstYr >= secondYl && firstYl <= secondYr;
+ bool collidesOnZ = firstZr >= secondZl && firstZl <= secondZr;
+
+ return collidesOnX && collidesOnY && collidesOnZ;
+}
diff --git a/old/world/Collision.hpp b/old/world/Collision.hpp
new file mode 100644
index 0000000..b88fbf7
--- /dev/null
+++ b/old/world/Collision.hpp
@@ -0,0 +1,8 @@
+#pragma once
+
+struct AABB {
+ double x,y,z;
+ double w,l,h;
+};
+
+bool TestCollision(AABB first, AABB second); \ No newline at end of file
diff --git a/old/world/GameState.cpp b/old/world/GameState.cpp
new file mode 100644
index 0000000..3ccff37
--- /dev/null
+++ b/old/world/GameState.cpp
@@ -0,0 +1,383 @@
+#include "GameState.hpp"
+
+GameState::GameState(NetworkClient *Net, bool &quit) : nc(Net), isRunning(quit) {
+ Front = glm::vec3(0.0f, 0.0f, -1.0f);
+ this->SetPosition(glm::vec3(0.0f, 0.0f, 3.0f));
+ this->WorldUp = glm::vec3(0.0f, 1.0f, 0.0f);
+ this->updateCameraVectors();
+}
+
+void GameState::Update(float deltaTime) {
+ if (g_IsGameStarted) {
+ std::chrono::steady_clock clock;
+ static auto timeOfPreviousSendedPacket(clock.now());
+ auto delta = clock.now() - timeOfPreviousSendedPacket;
+ using namespace std::chrono_literals;
+ if (delta >= 50ms) {
+ nc->SendPacket(std::make_shared<PacketPlayerPositionAndLookSB>(g_PlayerX, g_PlayerY, g_PlayerZ, g_PlayerYaw,
+ g_PlayerPitch, g_OnGround));
+ timeOfPreviousSendedPacket = clock.now();
+ }
+
+ const float gravity = -9.8f;
+ g_PlayerVelocityY += gravity * deltaTime;
+
+ bool isCollides = world.isPlayerCollides(g_PlayerX, g_PlayerY + g_PlayerVelocityY * deltaTime,
+ g_PlayerZ);
+ if (!isCollides) {
+ g_PlayerY += g_PlayerVelocityY * deltaTime;
+ g_OnGround = false;
+ } else {
+ g_PlayerVelocityY = 0;
+ if (g_OnGround == false) {
+ auto updatePacket = std::make_shared<PacketPlayerPosition>(g_PlayerX, g_PlayerY, g_PlayerZ, true);
+ nc->SendPacket(updatePacket);
+ }
+ g_OnGround = true;
+ }
+
+ isCollides = world.isPlayerCollides(g_PlayerX + g_PlayerVelocityX * deltaTime, g_PlayerY,
+ g_PlayerZ + g_PlayerVelocityZ * deltaTime);
+ if (!isCollides) {
+ g_PlayerX += g_PlayerVelocityX * deltaTime;
+ g_PlayerZ += g_PlayerVelocityZ * deltaTime;
+ }
+
+ const float AirResistance = 10.0f;
+ glm::vec3 vel(g_PlayerVelocityX, 0, g_PlayerVelocityZ);
+ glm::vec3 resistForce = -vel * AirResistance * deltaTime;
+ vel += resistForce;
+ g_PlayerVelocityX = vel.x;
+ g_PlayerVelocityZ = vel.z;
+ }
+
+
+ //Packet handling
+ auto ptr = nc->ReceivePacket();
+ while (ptr != nullptr) {
+ switch ((PacketNamePlayCB) ptr->GetPacketId()) {
+ case SpawnObject:
+ break;
+ case SpawnExperienceOrb:
+ break;
+ case SpawnGlobalEntity:
+ break;
+ case SpawnMob:
+ break;
+ case SpawnPainting:
+ break;
+ case SpawnPlayer:
+ break;
+ case AnimationCB:
+ break;
+ case Statistics:
+ break;
+ case BlockBreakAnimation:
+ break;
+ case UpdateBlockEntity:
+ break;
+ case BlockAction:
+ break;
+ case BlockChange:
+ break;
+ case BossBar:
+ break;
+ case ServerDifficulty:
+ break;
+ case TabCompleteCB:
+ break;
+ case ChatMessageCB:
+ break;
+ case MultiBlockChange:
+ break;
+ case ConfirmTransactionCB:
+ break;
+ case CloseWindowCB:
+ break;
+ case OpenWindow:
+ break;
+ case WindowItems:
+ break;
+ case WindowProperty:
+ break;
+ case SetSlot:
+ break;
+ case SetCooldown:
+ break;
+ case PluginMessageCB:
+ break;
+ case NamedSoundEffect:
+ break;
+ case DisconnectPlay: {
+ auto packet = std::static_pointer_cast<PacketDisconnectPlay>(ptr);
+ LOG(INFO) << "Disconnect reason: " << packet->Reason;
+ isRunning = false;
+ break;
+ }
+ case EntityStatus:
+ break;
+ case Explosion:
+ break;
+ case UnloadChunk:
+ break;
+ case ChangeGameState:
+ break;
+ case KeepAliveCB:
+ LOG(WARNING) << "Receive KeepAlive packet in GameState handler";
+ break;
+ case ChunkData: {
+ auto packet = std::static_pointer_cast<PacketChunkData>(ptr);
+ world.ParseChunkData(packet);
+ break;
+ }
+ case Effect:
+ break;
+ case Particle:
+ break;
+ case JoinGame: {
+ auto packet = std::static_pointer_cast<PacketJoinGame>(ptr);
+ g_PlayerEid = packet->EntityId;
+ g_Gamemode = (packet->Gamemode & 0b11111011);
+ g_Dimension = packet->Dimension;
+ g_Difficulty = packet->Difficulty;
+ g_MaxPlayers = packet->MaxPlayers;
+ g_LevelType = packet->LevelType;
+ g_ReducedDebugInfo = packet->ReducedDebugInfo;
+ LOG(INFO) << "Gamemode is " << g_Gamemode << ", Difficulty is " << (int) g_Difficulty
+ << ", Level Type is " << g_LevelType;
+ break;
+ }
+ case Map:
+ break;
+ case EntityRelativeMove:
+ break;
+ case EntityLookAndRelativeMove:
+ break;
+ case EntityLook:
+ break;
+ case Entity:
+ break;
+ case VehicleMove:
+ break;
+ case OpenSignEditor:
+ break;
+ case PlayerAbilitiesCB:
+ break;
+ case CombatEvent:
+ break;
+ case PlayerListItem:
+ break;
+ case PlayerPositionAndLookCB: {
+ auto packet = std::static_pointer_cast<PacketPlayerPositionAndLookCB>(ptr);
+ if ((packet->Flags & 0x10) != 0) {
+ g_PlayerPitch += packet->Pitch;
+ } else {
+ g_PlayerPitch = packet->Pitch;
+ };
+
+ if ((packet->Flags & 0x08) != 0) {
+ g_PlayerYaw += packet->Yaw;
+ } else {
+ g_PlayerYaw = packet->Yaw;
+ }
+
+ if ((packet->Flags & 0x01) != 0) {
+ g_PlayerX += packet->X;
+ } else {
+ g_PlayerX = packet->X;
+ }
+
+ if ((packet->Flags & 0x02) != 0) {
+ g_PlayerY += packet->Y;
+ } else {
+ g_PlayerY = packet->Y;
+ }
+
+ if ((packet->Flags & 0x04) != 0) {
+ g_PlayerZ += packet->Z;
+ } else {
+ g_PlayerZ = packet->Z;
+ }
+
+ //if (!g_IsGameStarted)
+ LOG(INFO) << "PlayerPos is " << g_PlayerX << ", " << g_PlayerY << ", " << g_PlayerZ << "\t\tAngle: "
+ << g_PlayerYaw << "," << g_PlayerPitch;
+
+ g_IsGameStarted = true;
+
+ auto packetResponse = std::make_shared<PacketTeleportConfirm>(packet->TeleportId);
+ auto packetPerformRespawn = std::make_shared<PacketClientStatus>(0);
+
+ nc->SendPacket(packetResponse);
+ nc->SendPacket(packetPerformRespawn);
+ break;
+ }
+ case UseBed:
+ break;
+ case UnlockRecipes:
+ break;
+ case DestroyEntities:
+ break;
+ case RemoveEntityEffect:
+ break;
+ case ResourcePackSend:
+ break;
+ case Respawn:
+ break;
+ case EntityHeadLook:
+ break;
+ case SelectAdvancementTab:
+ break;
+ case WorldBorder:
+ break;
+ case Camera:
+ break;
+ case HeldItemChangeCB:
+ break;
+ case DisplayScoreboard:
+ break;
+ case EntityMetadata:
+ break;
+ case AttachEntity:
+ break;
+ case EntityVelocity:
+ break;
+ case EntityEquipment:
+ break;
+ case SetExperience:
+ break;
+ case UpdateHealth: {
+ auto packet = std::static_pointer_cast<PacketUpdateHealth>(ptr);
+ g_PlayerHealth = packet->Health;
+ if (g_PlayerHealth <= 0) {
+ LOG(INFO) << "Player is dead. Respawning...";
+ auto packetPerformRespawn = std::make_shared<PacketClientStatus>(0);
+ nc->SendPacket(packetPerformRespawn);
+ }
+ break;
+ }
+ case ScoreboardObjective:
+ break;
+ case SetPassengers:
+ break;
+ case Teams:
+ break;
+ case UpdateScore:
+ break;
+ case SpawnPosition: {
+ auto packet = std::static_pointer_cast<PacketSpawnPosition>(ptr);
+ g_SpawnPosition = packet->Location;
+ LOG(INFO) << "Spawn position is " << g_SpawnPosition.GetX() << "," << g_SpawnPosition.GetY() << ","
+ << g_SpawnPosition.GetZ();
+ break;
+ }
+ case TimeUpdate:
+ break;
+ case Title:
+ break;
+ case SoundEffect:
+ break;
+ case PlayerListHeaderAndFooter:
+ break;
+ case CollectItem:
+ break;
+ case EntityTeleport:
+ break;
+ case Advancements:
+ break;
+ case EntityProperties:
+ break;
+ case EntityEffect:
+ break;
+ }
+ ptr = nc->ReceivePacket();
+ }
+}
+
+void GameState::HandleMovement(GameState::Direction direction, float deltaTime) {
+ const float PlayerSpeed = 40.0;
+ float velocity = PlayerSpeed * deltaTime;
+ glm::vec3 vel(g_PlayerVelocityX, g_PlayerVelocityY, g_PlayerVelocityZ);
+ glm::vec3 front(cos(glm::radians(this->Yaw())) * cos(glm::radians(this->Pitch())), 0,
+ sin(glm::radians(this->Yaw())) * cos(glm::radians(this->Pitch())));
+ front = glm::normalize(front);
+ glm::vec3 right = glm::normalize(glm::cross(front, this->WorldUp));
+ switch (direction) {
+ case FORWARD:
+ vel += front * velocity;
+ break;
+ case BACKWARD:
+ vel -= front * velocity;
+ break;
+ case RIGHT:
+ vel += right * velocity;
+ break;
+ case LEFT:
+ vel -= right * velocity;
+ break;
+ case JUMP:
+ if (g_OnGround) {
+ vel.y += 5;
+ g_OnGround = false;
+ }
+ break;
+ }
+ g_PlayerVelocityX = vel.x;
+ g_PlayerVelocityY = vel.y;
+ g_PlayerVelocityZ = vel.z;
+}
+
+void GameState::HandleRotation(double yaw, double pitch) {
+ this->SetYaw(Yaw() + yaw);
+ this->SetPitch(Pitch() + pitch);
+ if (this->Pitch() > 89.0f)
+ this->SetPitch(89.0f);
+ if (this->Pitch() < -89.0f)
+ this->SetPitch(-89.0f);
+ this->updateCameraVectors();
+
+ auto updatePacket = std::make_shared<PacketPlayerLook>(g_PlayerYaw, g_PlayerPitch, g_OnGround);
+ nc->SendPacket(updatePacket);
+}
+
+glm::mat4 GameState::GetViewMatrix() {
+ auto pos = this->Position();
+ pos.y+=1.62;
+ return glm::lookAt(pos, pos + this->Front, this->Up);
+}
+
+void GameState::updateCameraVectors() {
+ glm::vec3 front;
+ front.x = cos(glm::radians(this->Yaw())) * cos(glm::radians(this->Pitch()));
+ front.y = sin(glm::radians(this->Pitch()));
+ front.z = sin(glm::radians(this->Yaw())) * cos(glm::radians(this->Pitch()));
+ this->Front = glm::normalize(front);
+ this->Right = glm::normalize(glm::cross(this->Front, this->WorldUp));
+ this->Up = glm::normalize(glm::cross(this->Right, this->Front));
+}
+
+float GameState::Yaw() {
+ return g_PlayerYaw + 90;
+}
+
+float GameState::Pitch() {
+ return -g_PlayerPitch;
+}
+
+void GameState::SetYaw(float yaw) {
+ g_PlayerYaw = yaw - 90;
+}
+
+void GameState::SetPitch(float pitch) {
+ g_PlayerPitch = -pitch;
+}
+
+glm::vec3 GameState::Position() {
+ return glm::vec3(g_PlayerX, g_PlayerY, g_PlayerZ);
+}
+
+void GameState::SetPosition(glm::vec3 Position) {
+ g_PlayerX = Position.x;
+ g_PlayerY = Position.y;
+ g_PlayerZ = Position.z;
+}
diff --git a/old/world/GameState.hpp b/old/world/GameState.hpp
new file mode 100644
index 0000000..2635054
--- /dev/null
+++ b/old/world/GameState.hpp
@@ -0,0 +1,71 @@
+#pragma once
+
+#include <nlohmann/json.hpp>
+#include <glm/glm.hpp>
+#include <glm/gtc/matrix_transform.hpp>
+
+#include "World.hpp"
+#include "../network/NetworkClient.hpp"
+#include "../Vector.hpp"
+
+class GameState {
+ NetworkClient *nc;
+public:
+ GameState(NetworkClient *NetClient, bool &quit);
+
+ void Update(float deltaTime);
+
+ //Navigation
+ enum Direction {
+ FORWARD, BACKWARD, LEFT, RIGHT, JUMP
+ };
+ void HandleMovement(GameState::Direction direction, float deltaTime);
+ void HandleRotation(double yaw, double pitch);
+ glm::mat4 GetViewMatrix();
+ void updateCameraVectors();
+
+ float Yaw();
+ float Pitch();
+ void SetYaw(float yaw);
+ void SetPitch(float pitch);
+
+ glm::vec3 Position();
+ void SetPosition(glm::vec3 Position);
+ glm::vec3 Front;
+ glm::vec3 Up;
+ glm::vec3 Right;
+ glm::vec3 WorldUp;
+
+ //Everything other
+ World world;
+ bool &isRunning;
+
+ std::string g_PlayerUuid;
+ std::string g_PlayerName;
+ bool g_IsGameStarted;
+ int g_PlayerEid;
+ int g_Gamemode;
+ int g_Dimension;
+ byte g_Difficulty;
+ byte g_MaxPlayers;
+ std::string g_LevelType;
+ bool g_ReducedDebugInfo;
+ Vector g_SpawnPosition;
+ bool g_PlayerInvulnerable;
+ bool g_PlayerFlying;
+ bool g_PlayerAllowFlying;
+ bool g_PlayerCreativeMode;
+ float g_PlayerFlyingSpeed;
+ float g_PlayerFovModifier;
+ float g_PlayerPitch;
+ float g_PlayerYaw;
+ double g_PlayerX;
+ double g_PlayerY;
+ double g_PlayerZ;
+ float g_PlayerHealth;
+
+ bool g_OnGround = true;
+ double g_PlayerVelocityX = 0;
+ double g_PlayerVelocityY = 0;
+ double g_PlayerVelocityZ = 0;
+};
diff --git a/old/world/Section.cpp b/old/world/Section.cpp
new file mode 100644
index 0000000..8b86afd
--- /dev/null
+++ b/old/world/Section.cpp
@@ -0,0 +1,147 @@
+#include "Section.hpp"
+
+
+Section::Section(Vector position, byte *dataBlocks, size_t dataBlocksLength, byte *dataLight, byte *dataSky,
+ byte bitsPerBlock,
+ std::vector<unsigned short> palette) {
+ worldPosition = position;
+
+ m_dataBlocksLen = dataBlocksLength;
+ m_dataBlocks = new byte[m_dataBlocksLen];
+ std::copy(dataBlocks, dataBlocks + m_dataBlocksLen, m_dataBlocks);
+
+ m_dataLight = new byte[2048];
+ std::copy(dataLight, dataLight + 2048, m_dataLight);
+
+ if (dataSky) {
+ m_dataSkyLight = new byte[2048];
+ std::copy(dataSky, dataSky + 2048, m_dataSkyLight);
+ }
+
+ m_palette = palette;
+ m_bitsPerBlock = bitsPerBlock;
+}
+
+Section::~Section() {
+ delete[] m_dataBlocks;
+ m_dataBlocksLen = 0;
+ m_dataBlocks = nullptr;
+ delete[] m_dataLight;
+ m_dataLight = nullptr;
+ delete[] m_dataSkyLight;
+ m_dataSkyLight = nullptr;
+}
+
+Block &Section::GetBlock(Vector pos) {
+ return m_blocks[pos.GetY() * 256 + pos.GetZ() * 16 + pos.GetX()];
+}
+
+double totalParsingTime = 0;
+
+void Section::Parse() {
+ if (!m_blocks.empty())
+ return;
+
+ long long *longArray = reinterpret_cast<long long *>(m_dataBlocks);
+ for (size_t i = 0; i < m_dataBlocksLen / 8; i++)
+ endswap(&longArray[i]);
+ std::vector<unsigned short> blocks;
+ blocks.reserve(4096);
+ {
+ auto begin = std::chrono::steady_clock::now();
+ int bitPos = 0;
+ unsigned short t = 0;
+ for (size_t i = 0; i < m_dataBlocksLen; i++) {
+ for (int j = 0; j < 8; j++) {
+ t |= (m_dataBlocks[i] & 0x01) ? 0x80 : 0x00;
+ t >>= 1;
+ m_dataBlocks[i] >>= 1;
+ bitPos++;
+ if (bitPos >= m_bitsPerBlock) {
+ bitPos = 0;
+ t >>= m_bitsPerBlock - 1;
+ blocks.push_back(t);
+ t = 0;
+ }
+ }
+ }
+ auto end = std::chrono::steady_clock::now();
+ std::chrono::duration<double, std::milli> time = end - begin;
+ totalParsingTime += time.count();
+ }
+ std::vector<byte> light;
+ light.reserve(4096);
+ for (int i = 0; i < 2048; i++) {
+ byte t = m_dataLight[i];
+ byte first = t & 0b11110000;
+ byte second = t >> 4;
+ light.push_back(first);
+ light.push_back(second);
+ }
+ for (int i = 0; i < 4096; i++) {
+ unsigned short blockId = m_palette.size() > 0 ? m_palette[blocks[i]] : blocks[i];
+ Block block(blockId >> 4, blockId & 0xF);
+ m_blocks.push_back(block);
+ }
+ delete[] m_dataBlocks;
+ m_dataBlocksLen = 0;
+ m_dataBlocks = nullptr;
+ delete[] m_dataLight;
+ m_dataLight = nullptr;
+ delete[] m_dataSkyLight;
+ m_dataSkyLight = nullptr;
+
+ parseWaiter.notify_all();
+}
+
+Section &Section::operator=(Section other) {
+ std::swap(*this, other);
+ return *this;
+}
+
+void swap(Section &a, Section &b) {
+ using std::swap;
+ swap(a.m_dataBlocksLen, b.m_dataBlocksLen);
+ swap(a.m_dataBlocks, b.m_dataBlocks);
+ swap(a.m_dataLight, b.m_dataLight);
+ swap(a.m_dataSkyLight, b.m_dataSkyLight);
+ swap(a.m_blocks, b.m_blocks);
+ swap(a.m_palette, b.m_palette);
+ swap(a.m_bitsPerBlock, b.m_bitsPerBlock);
+}
+
+Section::Section(const Section &other) {
+ worldPosition = other.worldPosition;
+ m_dataBlocksLen = other.m_dataBlocksLen;
+ if (other.m_blocks.empty()) {
+ m_dataBlocks = new byte[m_dataBlocksLen];
+ std::copy(other.m_dataBlocks, other.m_dataBlocks + m_dataBlocksLen, m_dataBlocks);
+
+ m_dataLight = new byte[2048];
+ std::copy(other.m_dataLight, other.m_dataLight + 2048, m_dataLight);
+
+ if (other.m_dataSkyLight) {
+ m_dataSkyLight = new byte[2048];
+ std::copy(other.m_dataSkyLight, other.m_dataSkyLight + 2048, m_dataSkyLight);
+ }
+ } else {
+ std::copy(other.m_blocks.begin(), other.m_blocks.end(), std::back_inserter(m_blocks));
+ }
+
+ m_palette = other.m_palette;
+ m_bitsPerBlock = other.m_bitsPerBlock;
+}
+
+Vector Section::GetPosition() {
+ return worldPosition;
+}
+
+size_t Section::GetHash() {
+ if (m_blocks.empty()) return 0;
+
+ unsigned char *from = reinterpret_cast<unsigned char *>(m_blocks.data());
+ size_t length = m_blocks.size() * sizeof(Block);
+
+ std::string str(from, from + length);
+ return std::hash<std::string>{}(str);
+} \ No newline at end of file
diff --git a/old/world/Section.hpp b/old/world/Section.hpp
new file mode 100644
index 0000000..e98e231
--- /dev/null
+++ b/old/world/Section.hpp
@@ -0,0 +1,51 @@
+#pragma once
+
+#include <vector>
+#include <map>
+#include <condition_variable>
+#include <functional>
+
+#include <easylogging++.h>
+
+#include "Block.hpp"
+#include "../Vector.hpp"
+#include "../Utility.hpp"
+
+const int SECTION_WIDTH = 16;
+const int SECTION_LENGTH = 16;
+const int SECTION_HEIGHT = 16;
+
+class Section {
+ std::vector<unsigned short> m_palette;
+ byte *m_dataBlocks = nullptr;
+ size_t m_dataBlocksLen;
+ byte *m_dataLight = nullptr;
+ byte *m_dataSkyLight = nullptr;
+ byte m_bitsPerBlock = 0;
+ std::vector<Block> m_blocks;
+ std::condition_variable parseWaiter;
+
+ Section();
+
+ Vector worldPosition;
+
+public:
+ void Parse();
+
+ Section(Vector position, byte *dataBlocks, size_t dataBlocksLength, byte *dataLight, byte *dataSky, byte bitsPerBlock,
+ std::vector<unsigned short> palette);
+
+ ~Section();
+
+ Block &GetBlock(Vector pos);
+
+ Section &operator=(Section other);
+
+ friend void swap(Section &a, Section &b);
+
+ Section(const Section &other);
+
+ Vector GetPosition();
+
+ size_t GetHash();
+}; \ No newline at end of file
diff --git a/old/world/World.cpp b/old/world/World.cpp
new file mode 100644
index 0000000..487f4ba
--- /dev/null
+++ b/old/world/World.cpp
@@ -0,0 +1,129 @@
+#include "World.hpp"
+
+void World::ParseChunkData(std::shared_ptr<PacketChunkData> packet) {
+ StreamBuffer chunkData(packet->Data.data(), packet->Data.size());
+ std::bitset<16> bitmask(packet->PrimaryBitMask);
+ for (int i = 0; i < 16; i++) {
+ if (bitmask[i]) {
+ Vector chunkPosition = Vector(packet->ChunkX, i, packet->ChunkZ);
+ Section section = ParseSection(&chunkData, chunkPosition);
+ section.Parse();
+ sectionMutexes[chunkPosition].lock();
+ auto it = sections.find(chunkPosition);
+ if (it == sections.end()) {
+ sections.insert(std::make_pair(chunkPosition, section));
+ } else {
+ using std::swap;
+ swap(it->second, section);
+ }
+ sectionMutexes[chunkPosition].unlock();
+ }
+ }
+}
+
+Section World::ParseSection(StreamInput *data, Vector position) {
+ unsigned char bitsPerBlock = data->ReadUByte();
+ int paletteLength = data->ReadVarInt();
+ std::vector<unsigned short> palette;
+ for (int i = 0; i < paletteLength; i++) {
+ palette.push_back(data->ReadVarInt());
+ }
+ int dataArrayLength = data->ReadVarInt();
+ auto dataArray = data->ReadByteArray(dataArrayLength * 8);
+ auto blockLight = data->ReadByteArray(4096 / 2);
+ std::vector<unsigned char> skyLight;
+ if (dimension == 0)
+ skyLight = data->ReadByteArray(4096 / 2);
+ return Section(position, dataArray.data(), dataArray.size(), blockLight.data(),
+ (skyLight.size() > 0 ? skyLight.data() : nullptr), bitsPerBlock, palette);
+}
+
+World::~World() {
+}
+
+World::World() {
+
+}
+
+bool World::isPlayerCollides(double X, double Y, double Z) {
+ Vector PlayerChunk(floor(X / 16.0), floor(Y / 16.0), floor(Z / 16.0));
+ std::vector<Vector> closestSectionsCoordinates = {
+ Vector(PlayerChunk.GetX(), PlayerChunk.GetY(), PlayerChunk.GetZ()),
+ Vector(PlayerChunk.GetX() + 1, PlayerChunk.GetY(), PlayerChunk.GetZ()),
+ Vector(PlayerChunk.GetX() - 1, PlayerChunk.GetY(), PlayerChunk.GetZ()),
+ Vector(PlayerChunk.GetX(), PlayerChunk.GetY() + 1, PlayerChunk.GetZ()),
+ Vector(PlayerChunk.GetX(), PlayerChunk.GetY() - 1, PlayerChunk.GetZ()),
+ Vector(PlayerChunk.GetX(), PlayerChunk.GetY(), PlayerChunk.GetZ() + 1),
+ Vector(PlayerChunk.GetX(), PlayerChunk.GetY(), PlayerChunk.GetZ() - 1),
+ };
+ std::vector<std::map<Vector, Section>::iterator> closestSections;
+ for (auto &coord:closestSectionsCoordinates) {
+ auto it = sections.find(coord);
+ if (it != sections.end())
+ closestSections.push_back(it);
+ }
+ if (closestSections.empty())
+ return false;
+
+ for (auto &it:closestSections) {
+
+ const double PlayerWidth = 0.6;
+ const double PlayerHeight = 1.82;
+ const double PlayerLength = 0.6;
+
+ AABB playerColl;
+ playerColl.x = X - PlayerWidth / 2.0;
+ playerColl.w = PlayerWidth;
+ playerColl.y = Y;
+ playerColl.h = PlayerHeight;
+ playerColl.z = Z - PlayerLength / 2.0;
+ playerColl.l = PlayerLength;
+
+ for (int x = 0; x < 16; x++) {
+ for (int y = 0; y < 16; y++) {
+ for (int z = 0; z < 16; z++) {
+ Block block = it->second.GetBlock(Vector(x, y, z));
+ if (block.id == 0 || block.id == 31)
+ continue;
+ AABB blockColl{(x + it->first.GetX() * 16.0),
+ (y + it->first.GetY() * 16.0),
+ (z + it->first.GetZ() * 16.0), 1, 1, 1};
+ if (TestCollision(playerColl, blockColl))
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+Block &World::GetBlock(Vector pos) {
+ Vector sectionPos (floor(pos.GetX() / 16.0f),floor(pos.GetY() / 16.0f),floor(pos.GetZ()/16.0f));
+ Vector inSectionPos = pos - (sectionPos * 16);
+ if (sections.find(sectionPos)==sections.end()){
+ static Block block(0,0);
+ return block;
+ }
+ sectionMutexes[sectionPos].lock();
+ Block& block = sections.find(sectionPos)->second.GetBlock(inSectionPos);
+ sectionMutexes[sectionPos].unlock();
+ return block;
+}
+
+std::vector<Vector> World::GetSectionsList() {
+ std::vector<Vector> sectionsList;
+ for (auto& it:sections) {
+ sectionsList.push_back(it.first);
+ }
+ return sectionsList;
+}
+
+Section &World::GetSection(Vector sectionPos) {
+ sectionMutexes[sectionPos].lock();
+ sectionMutexes[sectionPos].unlock();
+ return sections.find(sectionPos)->second;
+}
+
+glm::vec3 World::Raycast(glm::vec3 position, glm::vec3 direction, float maxLength, float minPrecision) {
+ return glm::vec3(position * direction / maxLength * minPrecision);
+}
diff --git a/old/world/World.hpp b/old/world/World.hpp
new file mode 100644
index 0000000..05fe57d
--- /dev/null
+++ b/old/world/World.hpp
@@ -0,0 +1,38 @@
+#pragma once
+
+#include <map>
+#include <bitset>
+
+#include <easylogging++.h>
+
+#include <old/world/Block.hpp>
+#include <old/world/Section.hpp>
+#include <old/network/Packet.hpp>
+#include <old/world/Collision.hpp>
+
+class World {
+ std::map<Vector, Section> sections;
+ std::map<Vector, std::mutex> sectionMutexes;
+ int dimension = 0;
+
+ Section ParseSection(StreamInput *data, Vector position);
+
+ World(const World &other);
+ World &operator=(const World &other);
+public:
+ World();
+
+ ~World();
+
+ void ParseChunkData(std::shared_ptr<PacketChunkData> packet);
+
+ bool isPlayerCollides(double X, double Y, double Z);
+
+ Block &GetBlock(Vector pos);
+
+ std::vector<Vector> GetSectionsList();
+
+ Section &GetSection(Vector sectionPos);
+
+ glm::vec3 Raycast(glm::vec3 position, glm::vec3 direction, float maxLength = 1000.0f, float minPrecision = 0.01f);
+}; \ No newline at end of file
diff --git a/src/AssetManager.cpp b/src/AssetManager.cpp
new file mode 100644
index 0000000..351a118
--- /dev/null
+++ b/src/AssetManager.cpp
@@ -0,0 +1,185 @@
+#include <fstream>
+#include "AssetManager.hpp"
+
+//const fs::path pathToAssets = "./assets/";
+//const fs::path pathToAssetsList = "./items.json";
+//const fs::path pathToTextureIndex = "./textures.json";
+const std::string pathToAssetsList = "./items.json";
+const std::string pathToTextureIndex = "./textures.json";
+
+AssetManager::AssetManager() {
+ LoadIds();
+ LoadTextureResources();
+}
+
+void AssetManager::LoadIds() {
+ std::ifstream in(pathToAssetsList);
+ nlohmann::json index;
+ in >> index;
+ for (auto &it:index) {
+ int id = it["type"].get<int>();
+ int state = it["meta"].get<int>();
+ std::string blockName = it["text_type"].get<std::string>();
+ assetIds[blockName] = Block(id, state);
+ }
+ LOG(INFO) << "Loaded " << assetIds.size() << " ids";
+}
+
+AssetManager::~AssetManager() {
+ delete textureAtlas;
+}
+
+//TODO: This function must be replaced with runtime texture atlas generating
+void AssetManager::LoadTextureResources() {
+ std::ifstream in(pathToTextureIndex);
+ nlohmann::json index;
+ in >> index;
+ std::string filename = index["meta"]["image"].get<std::string>();
+ float textureWidth = index["meta"]["size"]["w"].get<int>();
+ float textureHeight = index["meta"]["size"]["h"].get<int>();
+ for (auto &it:index["frames"]) {
+ auto frame = it["frame"];
+ TextureCoordinates coord;
+ coord.x = frame["x"].get<int>() / textureWidth;
+ coord.y = frame["y"].get<int>() / textureHeight;
+ coord.w = frame["w"].get<int>() / textureWidth;
+ coord.h = frame["h"].get<int>() / textureHeight;
+ std::string assetName = it["filename"].get<std::string>();
+ assetName.insert(0, "minecraft/textures/");
+ assetName.erase(assetName.length() - 4);
+ assetTextures[assetName] = coord;
+ }
+
+ textureAtlas = new Texture(filename);
+ LOG(INFO) << "Texture atlas id is " << textureAtlas->texture;
+}
+
+TextureCoordinates AssetManager::GetTextureByAssetName(std::string AssetName) {
+ if (assetTextures.find(AssetName) != assetTextures.end())
+ return assetTextures[AssetName];
+ else
+ return TextureCoordinates{-1, -1, -1, -1};
+}
+
+std::string AssetManager::GetTextureAssetNameByBlockId(BlockTextureId block) {
+ //Block sides: 0 - bottom, 1 - top, 2 - north, 3 - south, 4 - west, 5 - east 6 - every side
+ const std::map<BlockTextureId, std::string> lookupTable = {
+ {BlockTextureId(0, 0), "minecraft/textures/blocks/air"},
+ {BlockTextureId(1, 0), "minecraft/textures/blocks/stone"},
+ {BlockTextureId(1, 1), "minecraft/textures/blocks/stone_granite"},
+
+ {BlockTextureId(2, 0, 0), "minecraft/textures/blocks/dirt"},
+ {BlockTextureId(2, 0, 1), "minecraft/textures/blocks/grass_top"},
+ {BlockTextureId(2, 0, 2), "minecraft/textures/blocks/grass_side"},
+ {BlockTextureId(2, 0, 3), "minecraft/textures/blocks/grass_side"},
+ {BlockTextureId(2, 0, 4), "minecraft/textures/blocks/grass_side"},
+ {BlockTextureId(2, 0, 5), "minecraft/textures/blocks/grass_side"},
+
+ {BlockTextureId(3, 0), "minecraft/textures/blocks/dirt"},
+ {BlockTextureId(4, 0), "minecraft/textures/blocks/cobblestone"},
+ {BlockTextureId(5, 0), "minecraft/textures/blocks/planks"},
+
+ {BlockTextureId(7, 0), "minecraft/textures/blocks/bedrock"},
+
+ {BlockTextureId(17, 0, 0), "minecraft/textures/blocks/log_oak_top"},
+ {BlockTextureId(17, 0, 1), "minecraft/textures/blocks/log_oak_top"},
+ {BlockTextureId(17, 0, 2), "minecraft/textures/blocks/log_oak"},
+ {BlockTextureId(17, 0, 3), "minecraft/textures/blocks/log_oak"},
+ {BlockTextureId(17, 0, 4), "minecraft/textures/blocks/log_oak"},
+ {BlockTextureId(17, 0, 5), "minecraft/textures/blocks/log_oak"},
+
+ {BlockTextureId(17, 1, 0), "minecraft/textures/blocks/log_spruce_top"},
+ {BlockTextureId(17, 1, 1), "minecraft/textures/blocks/log_spruce_top"},
+ {BlockTextureId(17, 1, 2), "minecraft/textures/blocks/log_spruce"},
+ {BlockTextureId(17, 1, 3), "minecraft/textures/blocks/log_spruce"},
+ {BlockTextureId(17, 1, 4), "minecraft/textures/blocks/log_spruce"},
+ {BlockTextureId(17, 1, 5), "minecraft/textures/blocks/log_spruce"},
+
+ {BlockTextureId(17, 2, 0), "minecraft/textures/blocks/log_birch_top"},
+ {BlockTextureId(17, 2, 1), "minecraft/textures/blocks/log_birch_top"},
+ {BlockTextureId(17, 2, 2), "minecraft/textures/blocks/log_birch"},
+ {BlockTextureId(17, 2, 3), "minecraft/textures/blocks/log_birch"},
+ {BlockTextureId(17, 2, 4), "minecraft/textures/blocks/log_birch"},
+ {BlockTextureId(17, 2, 5), "minecraft/textures/blocks/log_birch"},
+
+ {BlockTextureId(17, 3, 0), "minecraft/textures/blocks/log_jungle_top"},
+ {BlockTextureId(17, 3, 1), "minecraft/textures/blocks/log_jungle_top"},
+ {BlockTextureId(17, 3, 2), "minecraft/textures/blocks/log_jungle"},
+ {BlockTextureId(17, 3, 3), "minecraft/textures/blocks/log_jungle"},
+ {BlockTextureId(17, 3, 4), "minecraft/textures/blocks/log_jungle"},
+ {BlockTextureId(17, 3, 5), "minecraft/textures/blocks/log_jungle"},
+
+ {BlockTextureId(18, 0), "minecraft/textures/blocks/leaves_oak"},
+ {BlockTextureId(18, 1), "minecraft/textures/blocks/leaves_spruce"},
+ {BlockTextureId(18, 2), "minecraft/textures/blocks/leaves_birch"},
+ {BlockTextureId(18, 3), "minecraft/textures/blocks/leaves_jungle"},
+
+ {BlockTextureId(61, 0, 0), "minecraft/textures/blocks/furnace_side"},
+ {BlockTextureId(61, 0, 1), "minecraft/textures/blocks/furnace_top"},
+ {BlockTextureId(61, 0, 2), "minecraft/textures/blocks/furnace_front_off"},
+ {BlockTextureId(61, 0, 3), "minecraft/textures/blocks/furnace_side"},
+ {BlockTextureId(61, 0, 4), "minecraft/textures/blocks/furnace_side"},
+ {BlockTextureId(61, 0, 5), "minecraft/textures/blocks/furnace_side"},
+
+ {BlockTextureId(62, 0, 0), "minecraft/textures/blocks/furnace_side"},
+ {BlockTextureId(62, 0, 1), "minecraft/textures/blocks/furnace_top"},
+ {BlockTextureId(62, 0, 2), "minecraft/textures/blocks/furnace_front_on"},
+ {BlockTextureId(62, 0, 3), "minecraft/textures/blocks/furnace_side"},
+ {BlockTextureId(62, 0, 4), "minecraft/textures/blocks/furnace_side"},
+ {BlockTextureId(62, 0, 5), "minecraft/textures/blocks/furnace_side"},
+
+
+ {BlockTextureId(31, 0), "minecraft/textures/blocks/deadbush"},
+ {BlockTextureId(31, 1), "minecraft/textures/blocks/tallgrass"},
+ {BlockTextureId(31, 2), "minecraft/textures/blocks/fern"},
+ };
+ auto ret = lookupTable.find(block);
+ if (ret == lookupTable.end())
+ return "";
+ else
+ return ret->second;
+}
+
+GLuint AssetManager::GetTextureAtlas() {
+ return textureAtlas->texture;
+}
+
+TextureCoordinates AssetManager::GetTextureByBlock(BlockTextureId block) {
+ std::string assetName = this->GetTextureAssetNameByBlockId(block);
+ return this->GetTextureByAssetName(assetName);
+}
+
+const std::map<BlockTextureId, glm::vec4> &AssetManager::GetTextureAtlasIndexes() {
+ if (!textureAtlasIndexes.empty())
+ return textureAtlasIndexes;
+
+ LOG(INFO) << "Initializing texture atlas...";
+ for (int id = 1; id < 128; id++) {
+ for (int state = 0; state < 16; state++) {
+ BlockTextureId blockTextureId(id, state, 6);
+ if (!this->GetTextureByBlock(blockTextureId) &&
+ !this->GetTextureByBlock(BlockTextureId(id, state, 0))) {
+ continue;
+ }
+ if (this->GetTextureByBlock(blockTextureId)) {
+ for (int i = 0; i < 6; i++) {
+ TextureCoordinates tc = this->GetTextureByBlock(BlockTextureId(id, state, 6));
+ textureAtlasIndexes[BlockTextureId(id, state, i)] = glm::vec4(tc.x, tc.y, tc.w, tc.h);
+ }
+ } else {
+ for (int i = 0; i < 6; i++) {
+ TextureCoordinates tc = this->GetTextureByBlock(BlockTextureId(id, state, i));
+ textureAtlasIndexes[BlockTextureId(id, state, i)] = glm::vec4(tc.x, tc.y, tc.w, tc.h);
+ }
+ }
+ }
+ }
+ LOG(INFO) << "Created " << textureAtlasIndexes.size() << " texture indexes";
+
+ return textureAtlasIndexes;
+}
+
+AssetManager &AssetManager::Instance() {
+ static AssetManager assetManager;
+ return assetManager;
+}
diff --git a/src/AssetManager.hpp b/src/AssetManager.hpp
new file mode 100644
index 0000000..ba5546b
--- /dev/null
+++ b/src/AssetManager.hpp
@@ -0,0 +1,77 @@
+#pragma once
+
+#include <experimental/filesystem>
+#include <map>
+
+#include <GL/glew.h>
+#include <glm/vec4.hpp>
+#include <nlohmann/json.hpp>
+
+#include "Block.hpp"
+#include "Texture.hpp"
+
+struct TextureCoordinates {
+ TextureCoordinates(float x = -1, float y = -1, float w = -1, float h = -1) : x(x), y(y), w(w), h(h) {}
+
+ bool operator==(const TextureCoordinates &rhs) const {
+ return x == rhs.x &&
+ y == rhs.y &&
+ w == rhs.w &&
+ h == rhs.h;
+ }
+
+ explicit operator bool() const {
+ return !(*this == TextureCoordinates(-1, -1, -1, -1));
+ }
+
+ float x, y, w, h;
+};
+
+struct BlockTextureId {
+ //Block sides: 0 - bottom, 1 - top, 2 - north, 3 - south, 4 - west, 5 - east 6 - every side
+ BlockTextureId(int id = 0, int state = 0, int side = 6) : id(id), state(state), side(side) {}
+
+ int id:9;
+ int state:4;
+ int side:3;
+
+
+ bool operator<(const BlockTextureId &rhs) const {
+ if (id < rhs.id)
+ return true;
+ if (rhs.id < id)
+ return false;
+ if (state < rhs.state)
+ return true;
+ if (rhs.state < state)
+ return false;
+ return side < rhs.side;
+ }
+};
+
+class AssetManager {
+ Texture *textureAtlas;
+ std::map<std::string, Block> assetIds;
+ std::map<std::string, TextureCoordinates> assetTextures;
+ std::map<BlockTextureId,glm::vec4> textureAtlasIndexes;
+public:
+ AssetManager();
+
+ ~AssetManager();
+
+ void LoadTextureResources();
+
+ TextureCoordinates GetTextureByAssetName(std::string AssetName);
+
+ std::string GetTextureAssetNameByBlockId(BlockTextureId block);
+
+ GLuint GetTextureAtlas();
+
+ const std::map<BlockTextureId,glm::vec4> &GetTextureAtlasIndexes();
+
+ void LoadIds();
+
+ TextureCoordinates GetTextureByBlock(BlockTextureId block);
+
+ static AssetManager& Instance();
+};
diff --git a/src/Block.cpp b/src/Block.cpp
new file mode 100644
index 0000000..e88068a
--- /dev/null
+++ b/src/Block.cpp
@@ -0,0 +1,17 @@
+#include "Block.hpp"
+
+Block::~Block() {}
+
+Block::Block(unsigned short id, unsigned char state) : id(id), state(state) {}
+
+Block::Block() : id(0), state(0) {}
+
+bool operator<(const Block &lhs, const Block &rhs) {
+ if (lhs.id < rhs.id)
+ return true;
+ if (lhs.id == rhs.id) {
+ if (lhs.state != rhs.state)
+ return lhs.state < rhs.state;
+ }
+ return false;
+}
diff --git a/src/Block.hpp b/src/Block.hpp
new file mode 100644
index 0000000..2f823fe
--- /dev/null
+++ b/src/Block.hpp
@@ -0,0 +1,15 @@
+#pragma once
+
+struct Block {
+ Block();
+
+ Block(unsigned short id, unsigned char state);
+
+ ~Block();
+
+ unsigned short id : 13;
+ unsigned char state : 4;
+ //unsigned char light:4;
+};
+
+bool operator<(const Block &lhs, const Block &rhs); \ No newline at end of file
diff --git a/src/Collision.cpp b/src/Collision.cpp
new file mode 100644
index 0000000..4f2c837
--- /dev/null
+++ b/src/Collision.cpp
@@ -0,0 +1,28 @@
+#include "Collision.hpp"
+
+bool TestCollision(AABB first, AABB second) {
+ double firstXl = first.x;
+ double firstXr = first.x + first.w;
+
+ double firstYl = first.y;
+ double firstYr = first.y + first.h;
+
+ double firstZl = first.z;
+ double firstZr = first.z + first.l;
+
+
+ double secondXl = second.x;
+ double secondXr = second.x + second.w;
+
+ double secondYl = second.y;
+ double secondYr = second.y + second.h;
+
+ double secondZl = second.z;
+ double secondZr = second.z + second.l;
+
+ bool collidesOnX = firstXr >= secondXl && firstXl <= secondXr;
+ bool collidesOnY = firstYr >= secondYl && firstYl <= secondYr;
+ bool collidesOnZ = firstZr >= secondZl && firstZl <= secondZr;
+
+ return collidesOnX && collidesOnY && collidesOnZ;
+}
diff --git a/src/Collision.hpp b/src/Collision.hpp
new file mode 100644
index 0000000..b88fbf7
--- /dev/null
+++ b/src/Collision.hpp
@@ -0,0 +1,8 @@
+#pragma once
+
+struct AABB {
+ double x,y,z;
+ double w,l,h;
+};
+
+bool TestCollision(AABB first, AABB second); \ No newline at end of file
diff --git a/src/Core.cpp b/src/Core.cpp
new file mode 100644
index 0000000..3a89c07
--- /dev/null
+++ b/src/Core.cpp
@@ -0,0 +1,59 @@
+#include "Core.hpp"
+#include "NetworkClient.hpp"
+
+Core::Core() {
+ coreLoop = std::thread(&Core::ExecuteCoreLoop, this);
+ render = new Render(900, 480, "AltCraft");
+}
+
+Core::~Core() {
+ delete render;
+ coreLoop.join();
+}
+
+void Core::ExecuteRenderLoop() {
+ render->ExecuteRenderLoop();
+}
+
+void Core::ExecuteCoreLoop() {
+
+ EventListener events;
+ events.RegisterHandler(EventType::ConnectionSuccessfull, [](EventData eventData) {
+ GlobalAppStateData data = {GlobalState::Loading};
+ EventAgregator::PushEvent(EventType::GlobalAppState, EventData{data});
+ });
+ events.RegisterHandler(EventType::GlobalAppState, [this](EventData eventData) {
+ auto data = std::get<GlobalAppStateData>(eventData);
+ globalState = data.state;
+ });
+
+ while (globalState != GlobalState::Exiting) {
+ if (events.IsEventsQueueIsNotEmpty()) {
+ events.HandleEvent();
+ }
+ }
+}
+
+void Core::ExecuteNetworkLoop() {
+ NetworkClient *nc;
+ EventListener events;
+ bool isRunning = true;
+ events.RegisterHandler(EventType::ConnectToServer, [](EventData eventData) {
+ auto data = std::get<ConnectToServerData>(eventData);
+ try {
+ nc = new NetworkClient(data.address, data.port, "HelloOne", isRunning);
+ } catch (std::exception &e) {
+ GlobalAppStateData data{GlobalState::Exiting};
+ EventAgregator::PushEvent(EventType::GlobalAppState, data);
+ }
+ });
+ events.RegisterHandler(EventType::Disconnect, [nc](EventData eventData) {
+ delete nc;
+ nc = nullptr;
+ });
+
+ while (globalState != GlobalState::Exiting) {
+
+ }
+ delete nc;
+}
diff --git a/src/Core.hpp b/src/Core.hpp
new file mode 100644
index 0000000..3c2d8da
--- /dev/null
+++ b/src/Core.hpp
@@ -0,0 +1,23 @@
+#pragma once
+
+#include <thread>
+#include <memory>
+
+#include "Render.hpp"
+#include "Event.hpp"
+
+class Core {
+ std::thread coreLoop;
+ std::thread networkLoop;
+ Render* render;
+
+ GlobalState globalState = GlobalState::InitialLoading;
+
+ void ExecuteCoreLoop();
+ void ExecuteNetworkLoop();
+public:
+ Core();
+ ~Core();
+
+ void ExecuteRenderLoop();
+}; \ No newline at end of file
diff --git a/src/Event.cpp b/src/Event.cpp
new file mode 100644
index 0000000..ff16178
--- /dev/null
+++ b/src/Event.cpp
@@ -0,0 +1,100 @@
+#include "Event.hpp"
+#include <easylogging++.h>
+
+std::queue <Event> EventAgregator::eventsToHandle;
+std::mutex EventAgregator::queueMutex;
+bool EventAgregator::isStarted = false;
+std::vector<EventListener*> EventAgregator::listeners;
+std::mutex EventAgregator::listenersMutex;
+
+EventListener::EventListener() {
+ EventAgregator::RegisterListener(*this);
+}
+
+EventListener::~EventListener() {
+ EventAgregator::UnregisterListener(*this);
+}
+
+void EventListener::PushEvent(Event event) {
+ eventsMutex.lock();
+ events.push(event);
+ eventsMutex.unlock();
+}
+
+bool EventListener::IsEventsQueueIsNotEmpty() {
+ eventsMutex.lock();
+ bool value = !events.empty();
+ eventsMutex.unlock();
+ return value;
+}
+
+
+void EventListener::RegisterHandler(EventType type, EventListener::HandlerFunc handler) {
+ handlers[type] = handler;
+}
+
+void EventListener::HandleEvent() {
+ eventsMutex.lock();
+ if (events.empty()) {
+ eventsMutex.unlock();
+ return;
+ }
+ Event event = events.front();
+ events.pop();
+ eventsMutex.unlock();
+ auto function = handlers[event.type];
+ function(event.data);
+}
+
+
+
+void EventAgregator::RegisterListener(EventListener &listener) {
+ listenersMutex.lock();
+ LOG(WARNING)<<"Registered handler "<<&listener;
+ listeners.push_back(&listener);
+ listenersMutex.unlock();
+}
+
+void EventAgregator::UnregisterListener(EventListener &listener) {
+ listenersMutex.lock();
+ LOG(WARNING)<<"Unregistered handler "<<&listener;
+ listeners.erase(std::find(listeners.begin(), listeners.end(), &listener));
+ listenersMutex.unlock();
+}
+
+void EventAgregator::PushEvent(EventType type, EventData data) {
+ Event event;
+ event.type = type;
+ event.data = data;
+ eventsToHandle.push(event);
+ if (!isStarted) {
+ isStarted = true;
+ std::thread(&EventAgregator::EventHandlingLoop).detach();
+ }
+}
+
+void EventAgregator::EventHandlingLoop() {
+ while (true) {
+ queueMutex.lock();
+ if (!eventsToHandle.empty()) {
+ auto queue = eventsToHandle;
+ while (!eventsToHandle.empty())
+ eventsToHandle.pop();
+ queueMutex.unlock();
+
+ while (!queue.empty()) {
+ auto event = queue.front();
+ listenersMutex.lock();
+ for (auto& listener : listeners) {
+ LOG(ERROR)<<"Listener notified about event";
+ listener->PushEvent(event);
+ }
+ listenersMutex.unlock();
+ queue.pop();
+ }
+
+ queueMutex.lock();
+ }
+ queueMutex.unlock();
+ }
+}
diff --git a/src/Event.hpp b/src/Event.hpp
new file mode 100644
index 0000000..2d830a4
--- /dev/null
+++ b/src/Event.hpp
@@ -0,0 +1,116 @@
+#pragma once
+
+#include <queue>
+#include <map>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <chrono>
+#include <variant>
+#include <functional>
+
+#include "Vector.hpp"
+#include "Packet.hpp"
+
+enum class EventType {
+ Echo,
+ ChunkChanged,
+ ConnectToServer,
+ ConnectionSuccessfull,
+ GlobalAppState,
+ Disconnect,
+ SendPacket,
+ ReceivePacket,
+};
+
+struct EchoData {
+ std::chrono::time_point<std::chrono::high_resolution_clock> time;
+};
+
+struct ChunkChangedData {
+ Vector chunkPosition;
+};
+
+struct ConnectToServerData {
+ std::string address;
+ unsigned short port;
+};
+
+struct ConnectionSuccessfullData {
+
+};
+
+enum class GlobalState {
+ InitialLoading,
+ MainMenu,
+ Loading,
+ InGame,
+ PauseMenu,
+ Exiting,
+};
+
+struct GlobalAppStateData {
+ GlobalState state;
+};
+
+struct DisconnectData {
+
+};
+
+struct SendPacketData {
+ std::shared_ptr<Packet> packet;
+};
+
+struct ReceivePacketData {
+ std::shared_ptr<Packet> packet;
+};
+
+using EventData = std::variant<EchoData, ChunkChangedData, ConnectToServerData, ConnectionSuccessfullData,
+ GlobalAppStateData, DisconnectData, SendPacketData, ReceivePacketData>;
+
+struct Event {
+ EventType type;
+ EventData data;
+};
+
+class EventListener {
+ friend class EventAgregator;
+
+ using HandlerFunc = std::function<void(EventData)>;
+
+ std::map<EventType, HandlerFunc> handlers; //TODO: There must be more elegant solution than std::variant of all data
+
+ std::mutex eventsMutex;
+
+ std::queue<Event> events;
+
+ void PushEvent(Event event);
+
+public:
+ EventListener();
+ ~EventListener();
+ bool IsEventsQueueIsNotEmpty();
+
+ void RegisterHandler(EventType type, HandlerFunc handler);
+
+ void HandleEvent();
+};
+
+class EventAgregator {
+ friend EventListener;
+
+ EventAgregator() = default;
+ static std::queue<Event> eventsToHandle;
+ static std::mutex queueMutex;
+ static bool isStarted;
+ static std::vector<EventListener *> listeners;
+ static std::mutex listenersMutex;
+
+ static void EventHandlingLoop();
+
+ static void RegisterListener(EventListener &listener);
+ static void UnregisterListener(EventListener &listener);
+
+public:
+ static void PushEvent(EventType type, EventData data);
+}; \ No newline at end of file
diff --git a/src/GameState.cpp b/src/GameState.cpp
new file mode 100644
index 0000000..3ccff37
--- /dev/null
+++ b/src/GameState.cpp
@@ -0,0 +1,383 @@
+#include "GameState.hpp"
+
+GameState::GameState(NetworkClient *Net, bool &quit) : nc(Net), isRunning(quit) {
+ Front = glm::vec3(0.0f, 0.0f, -1.0f);
+ this->SetPosition(glm::vec3(0.0f, 0.0f, 3.0f));
+ this->WorldUp = glm::vec3(0.0f, 1.0f, 0.0f);
+ this->updateCameraVectors();
+}
+
+void GameState::Update(float deltaTime) {
+ if (g_IsGameStarted) {
+ std::chrono::steady_clock clock;
+ static auto timeOfPreviousSendedPacket(clock.now());
+ auto delta = clock.now() - timeOfPreviousSendedPacket;
+ using namespace std::chrono_literals;
+ if (delta >= 50ms) {
+ nc->SendPacket(std::make_shared<PacketPlayerPositionAndLookSB>(g_PlayerX, g_PlayerY, g_PlayerZ, g_PlayerYaw,
+ g_PlayerPitch, g_OnGround));
+ timeOfPreviousSendedPacket = clock.now();
+ }
+
+ const float gravity = -9.8f;
+ g_PlayerVelocityY += gravity * deltaTime;
+
+ bool isCollides = world.isPlayerCollides(g_PlayerX, g_PlayerY + g_PlayerVelocityY * deltaTime,
+ g_PlayerZ);
+ if (!isCollides) {
+ g_PlayerY += g_PlayerVelocityY * deltaTime;
+ g_OnGround = false;
+ } else {
+ g_PlayerVelocityY = 0;
+ if (g_OnGround == false) {
+ auto updatePacket = std::make_shared<PacketPlayerPosition>(g_PlayerX, g_PlayerY, g_PlayerZ, true);
+ nc->SendPacket(updatePacket);
+ }
+ g_OnGround = true;
+ }
+
+ isCollides = world.isPlayerCollides(g_PlayerX + g_PlayerVelocityX * deltaTime, g_PlayerY,
+ g_PlayerZ + g_PlayerVelocityZ * deltaTime);
+ if (!isCollides) {
+ g_PlayerX += g_PlayerVelocityX * deltaTime;
+ g_PlayerZ += g_PlayerVelocityZ * deltaTime;
+ }
+
+ const float AirResistance = 10.0f;
+ glm::vec3 vel(g_PlayerVelocityX, 0, g_PlayerVelocityZ);
+ glm::vec3 resistForce = -vel * AirResistance * deltaTime;
+ vel += resistForce;
+ g_PlayerVelocityX = vel.x;
+ g_PlayerVelocityZ = vel.z;
+ }
+
+
+ //Packet handling
+ auto ptr = nc->ReceivePacket();
+ while (ptr != nullptr) {
+ switch ((PacketNamePlayCB) ptr->GetPacketId()) {
+ case SpawnObject:
+ break;
+ case SpawnExperienceOrb:
+ break;
+ case SpawnGlobalEntity:
+ break;
+ case SpawnMob:
+ break;
+ case SpawnPainting:
+ break;
+ case SpawnPlayer:
+ break;
+ case AnimationCB:
+ break;
+ case Statistics:
+ break;
+ case BlockBreakAnimation:
+ break;
+ case UpdateBlockEntity:
+ break;
+ case BlockAction:
+ break;
+ case BlockChange:
+ break;
+ case BossBar:
+ break;
+ case ServerDifficulty:
+ break;
+ case TabCompleteCB:
+ break;
+ case ChatMessageCB:
+ break;
+ case MultiBlockChange:
+ break;
+ case ConfirmTransactionCB:
+ break;
+ case CloseWindowCB:
+ break;
+ case OpenWindow:
+ break;
+ case WindowItems:
+ break;
+ case WindowProperty:
+ break;
+ case SetSlot:
+ break;
+ case SetCooldown:
+ break;
+ case PluginMessageCB:
+ break;
+ case NamedSoundEffect:
+ break;
+ case DisconnectPlay: {
+ auto packet = std::static_pointer_cast<PacketDisconnectPlay>(ptr);
+ LOG(INFO) << "Disconnect reason: " << packet->Reason;
+ isRunning = false;
+ break;
+ }
+ case EntityStatus:
+ break;
+ case Explosion:
+ break;
+ case UnloadChunk:
+ break;
+ case ChangeGameState:
+ break;
+ case KeepAliveCB:
+ LOG(WARNING) << "Receive KeepAlive packet in GameState handler";
+ break;
+ case ChunkData: {
+ auto packet = std::static_pointer_cast<PacketChunkData>(ptr);
+ world.ParseChunkData(packet);
+ break;
+ }
+ case Effect:
+ break;
+ case Particle:
+ break;
+ case JoinGame: {
+ auto packet = std::static_pointer_cast<PacketJoinGame>(ptr);
+ g_PlayerEid = packet->EntityId;
+ g_Gamemode = (packet->Gamemode & 0b11111011);
+ g_Dimension = packet->Dimension;
+ g_Difficulty = packet->Difficulty;
+ g_MaxPlayers = packet->MaxPlayers;
+ g_LevelType = packet->LevelType;
+ g_ReducedDebugInfo = packet->ReducedDebugInfo;
+ LOG(INFO) << "Gamemode is " << g_Gamemode << ", Difficulty is " << (int) g_Difficulty
+ << ", Level Type is " << g_LevelType;
+ break;
+ }
+ case Map:
+ break;
+ case EntityRelativeMove:
+ break;
+ case EntityLookAndRelativeMove:
+ break;
+ case EntityLook:
+ break;
+ case Entity:
+ break;
+ case VehicleMove:
+ break;
+ case OpenSignEditor:
+ break;
+ case PlayerAbilitiesCB:
+ break;
+ case CombatEvent:
+ break;
+ case PlayerListItem:
+ break;
+ case PlayerPositionAndLookCB: {
+ auto packet = std::static_pointer_cast<PacketPlayerPositionAndLookCB>(ptr);
+ if ((packet->Flags & 0x10) != 0) {
+ g_PlayerPitch += packet->Pitch;
+ } else {
+ g_PlayerPitch = packet->Pitch;
+ };
+
+ if ((packet->Flags & 0x08) != 0) {
+ g_PlayerYaw += packet->Yaw;
+ } else {
+ g_PlayerYaw = packet->Yaw;
+ }
+
+ if ((packet->Flags & 0x01) != 0) {
+ g_PlayerX += packet->X;
+ } else {
+ g_PlayerX = packet->X;
+ }
+
+ if ((packet->Flags & 0x02) != 0) {
+ g_PlayerY += packet->Y;
+ } else {
+ g_PlayerY = packet->Y;
+ }
+
+ if ((packet->Flags & 0x04) != 0) {
+ g_PlayerZ += packet->Z;
+ } else {
+ g_PlayerZ = packet->Z;
+ }
+
+ //if (!g_IsGameStarted)
+ LOG(INFO) << "PlayerPos is " << g_PlayerX << ", " << g_PlayerY << ", " << g_PlayerZ << "\t\tAngle: "
+ << g_PlayerYaw << "," << g_PlayerPitch;
+
+ g_IsGameStarted = true;
+
+ auto packetResponse = std::make_shared<PacketTeleportConfirm>(packet->TeleportId);
+ auto packetPerformRespawn = std::make_shared<PacketClientStatus>(0);
+
+ nc->SendPacket(packetResponse);
+ nc->SendPacket(packetPerformRespawn);
+ break;
+ }
+ case UseBed:
+ break;
+ case UnlockRecipes:
+ break;
+ case DestroyEntities:
+ break;
+ case RemoveEntityEffect:
+ break;
+ case ResourcePackSend:
+ break;
+ case Respawn:
+ break;
+ case EntityHeadLook:
+ break;
+ case SelectAdvancementTab:
+ break;
+ case WorldBorder:
+ break;
+ case Camera:
+ break;
+ case HeldItemChangeCB:
+ break;
+ case DisplayScoreboard:
+ break;
+ case EntityMetadata:
+ break;
+ case AttachEntity:
+ break;
+ case EntityVelocity:
+ break;
+ case EntityEquipment:
+ break;
+ case SetExperience:
+ break;
+ case UpdateHealth: {
+ auto packet = std::static_pointer_cast<PacketUpdateHealth>(ptr);
+ g_PlayerHealth = packet->Health;
+ if (g_PlayerHealth <= 0) {
+ LOG(INFO) << "Player is dead. Respawning...";
+ auto packetPerformRespawn = std::make_shared<PacketClientStatus>(0);
+ nc->SendPacket(packetPerformRespawn);
+ }
+ break;
+ }
+ case ScoreboardObjective:
+ break;
+ case SetPassengers:
+ break;
+ case Teams:
+ break;
+ case UpdateScore:
+ break;
+ case SpawnPosition: {
+ auto packet = std::static_pointer_cast<PacketSpawnPosition>(ptr);
+ g_SpawnPosition = packet->Location;
+ LOG(INFO) << "Spawn position is " << g_SpawnPosition.GetX() << "," << g_SpawnPosition.GetY() << ","
+ << g_SpawnPosition.GetZ();
+ break;
+ }
+ case TimeUpdate:
+ break;
+ case Title:
+ break;
+ case SoundEffect:
+ break;
+ case PlayerListHeaderAndFooter:
+ break;
+ case CollectItem:
+ break;
+ case EntityTeleport:
+ break;
+ case Advancements:
+ break;
+ case EntityProperties:
+ break;
+ case EntityEffect:
+ break;
+ }
+ ptr = nc->ReceivePacket();
+ }
+}
+
+void GameState::HandleMovement(GameState::Direction direction, float deltaTime) {
+ const float PlayerSpeed = 40.0;
+ float velocity = PlayerSpeed * deltaTime;
+ glm::vec3 vel(g_PlayerVelocityX, g_PlayerVelocityY, g_PlayerVelocityZ);
+ glm::vec3 front(cos(glm::radians(this->Yaw())) * cos(glm::radians(this->Pitch())), 0,
+ sin(glm::radians(this->Yaw())) * cos(glm::radians(this->Pitch())));
+ front = glm::normalize(front);
+ glm::vec3 right = glm::normalize(glm::cross(front, this->WorldUp));
+ switch (direction) {
+ case FORWARD:
+ vel += front * velocity;
+ break;
+ case BACKWARD:
+ vel -= front * velocity;
+ break;
+ case RIGHT:
+ vel += right * velocity;
+ break;
+ case LEFT:
+ vel -= right * velocity;
+ break;
+ case JUMP:
+ if (g_OnGround) {
+ vel.y += 5;
+ g_OnGround = false;
+ }
+ break;
+ }
+ g_PlayerVelocityX = vel.x;
+ g_PlayerVelocityY = vel.y;
+ g_PlayerVelocityZ = vel.z;
+}
+
+void GameState::HandleRotation(double yaw, double pitch) {
+ this->SetYaw(Yaw() + yaw);
+ this->SetPitch(Pitch() + pitch);
+ if (this->Pitch() > 89.0f)
+ this->SetPitch(89.0f);
+ if (this->Pitch() < -89.0f)
+ this->SetPitch(-89.0f);
+ this->updateCameraVectors();
+
+ auto updatePacket = std::make_shared<PacketPlayerLook>(g_PlayerYaw, g_PlayerPitch, g_OnGround);
+ nc->SendPacket(updatePacket);
+}
+
+glm::mat4 GameState::GetViewMatrix() {
+ auto pos = this->Position();
+ pos.y+=1.62;
+ return glm::lookAt(pos, pos + this->Front, this->Up);
+}
+
+void GameState::updateCameraVectors() {
+ glm::vec3 front;
+ front.x = cos(glm::radians(this->Yaw())) * cos(glm::radians(this->Pitch()));
+ front.y = sin(glm::radians(this->Pitch()));
+ front.z = sin(glm::radians(this->Yaw())) * cos(glm::radians(this->Pitch()));
+ this->Front = glm::normalize(front);
+ this->Right = glm::normalize(glm::cross(this->Front, this->WorldUp));
+ this->Up = glm::normalize(glm::cross(this->Right, this->Front));
+}
+
+float GameState::Yaw() {
+ return g_PlayerYaw + 90;
+}
+
+float GameState::Pitch() {
+ return -g_PlayerPitch;
+}
+
+void GameState::SetYaw(float yaw) {
+ g_PlayerYaw = yaw - 90;
+}
+
+void GameState::SetPitch(float pitch) {
+ g_PlayerPitch = -pitch;
+}
+
+glm::vec3 GameState::Position() {
+ return glm::vec3(g_PlayerX, g_PlayerY, g_PlayerZ);
+}
+
+void GameState::SetPosition(glm::vec3 Position) {
+ g_PlayerX = Position.x;
+ g_PlayerY = Position.y;
+ g_PlayerZ = Position.z;
+}
diff --git a/src/GameState.hpp b/src/GameState.hpp
new file mode 100644
index 0000000..2ac7bc1
--- /dev/null
+++ b/src/GameState.hpp
@@ -0,0 +1,71 @@
+#pragma once
+
+#include <nlohmann/json.hpp>
+#include <glm/glm.hpp>
+#include <glm/gtc/matrix_transform.hpp>
+
+#include "World.hpp"
+#include "NetworkClient.hpp"
+#include "Vector.hpp"
+
+class GameState {
+ NetworkClient *nc;
+public:
+ GameState(NetworkClient *NetClient, bool &quit);
+
+ void Update(float deltaTime);
+
+ //Navigation
+ enum Direction {
+ FORWARD, BACKWARD, LEFT, RIGHT, JUMP
+ };
+ void HandleMovement(GameState::Direction direction, float deltaTime);
+ void HandleRotation(double yaw, double pitch);
+ glm::mat4 GetViewMatrix();
+ void updateCameraVectors();
+
+ float Yaw();
+ float Pitch();
+ void SetYaw(float yaw);
+ void SetPitch(float pitch);
+
+ glm::vec3 Position();
+ void SetPosition(glm::vec3 Position);
+ glm::vec3 Front;
+ glm::vec3 Up;
+ glm::vec3 Right;
+ glm::vec3 WorldUp;
+
+ //Everything other
+ World world;
+ bool &isRunning;
+
+ std::string g_PlayerUuid;
+ std::string g_PlayerName;
+ bool g_IsGameStarted;
+ int g_PlayerEid;
+ int g_Gamemode;
+ int g_Dimension;
+ byte g_Difficulty;
+ byte g_MaxPlayers;
+ std::string g_LevelType;
+ bool g_ReducedDebugInfo;
+ Vector g_SpawnPosition;
+ bool g_PlayerInvulnerable;
+ bool g_PlayerFlying;
+ bool g_PlayerAllowFlying;
+ bool g_PlayerCreativeMode;
+ float g_PlayerFlyingSpeed;
+ float g_PlayerFovModifier;
+ float g_PlayerPitch;
+ float g_PlayerYaw;
+ double g_PlayerX;
+ double g_PlayerY;
+ double g_PlayerZ;
+ float g_PlayerHealth;
+
+ bool g_OnGround = true;
+ double g_PlayerVelocityX = 0;
+ double g_PlayerVelocityY = 0;
+ double g_PlayerVelocityZ = 0;
+};
diff --git a/src/Network.cpp b/src/Network.cpp
new file mode 100644
index 0000000..dcdda10
--- /dev/null
+++ b/src/Network.cpp
@@ -0,0 +1,224 @@
+#include "Network.hpp"
+
+Network::Network(std::string address, unsigned short port) {
+ try {
+ socket = new Socket(address, port);
+ stream = new StreamSocket(socket);
+ } catch (std::exception &e) {
+ LOG(FATAL)<<e.what();
+ }
+}
+
+Network::~Network() {
+ delete stream;
+ delete socket;
+}
+
+std::shared_ptr<Packet> Network::ReceivePacket(ConnectionState state) {
+ int packetSize = stream->ReadVarInt();
+ auto packetData = stream->ReadByteArray(packetSize);
+ StreamBuffer streamBuffer(packetData.data(), packetData.size());
+ int packetId = streamBuffer.ReadVarInt();
+ auto packet = ReceivePacketByPacketId(packetId, state, streamBuffer);
+ return packet;
+}
+
+void Network::SendPacket(Packet &packet) {
+ StreamCounter packetSize;
+ packetSize.WriteVarInt(packet.GetPacketId());
+ packet.ToStream(&packetSize);
+ stream->WriteVarInt(packetSize.GetCountedSize());
+ stream->WriteVarInt(packet.GetPacketId());
+ packet.ToStream(stream);
+}
+
+std::shared_ptr<Packet> Network::ReceivePacketByPacketId(int packetId, ConnectionState state, StreamInput &stream) {
+ std::shared_ptr<Packet> packet(nullptr);
+ switch (state) {
+ case Handshaking:
+ switch (packetId) {
+ case PacketNameHandshakingCB::Handshake:
+ packet = std::make_shared<PacketHandshake>();
+ break;
+ }
+ case Login:
+ switch (packetId) {
+ case PacketNameLoginCB::LoginSuccess:
+ packet = std::make_shared<PacketLoginSuccess>();
+ break;
+ }
+ break;
+ case Play:
+ packet = ParsePacketPlay((PacketNamePlayCB) packetId);
+ break;
+ case Status:
+ break;
+ }
+ if (packet.get() != nullptr)
+ packet->FromStream(&stream);
+ return packet;
+}
+
+std::shared_ptr<Packet> Network::ParsePacketPlay(PacketNamePlayCB id) {
+ switch (id) {
+ case SpawnObject:
+ break;
+ case SpawnExperienceOrb:
+ break;
+ case SpawnGlobalEntity:
+ break;
+ case SpawnMob:
+ break;
+ case SpawnPainting:
+ break;
+ case SpawnPlayer:
+ break;
+ case AnimationCB:
+ break;
+ case Statistics:
+ break;
+ case BlockBreakAnimation:
+ break;
+ case UpdateBlockEntity:
+ break;
+ case BlockAction:
+ break;
+ case BlockChange:
+ break;
+ case BossBar:
+ break;
+ case ServerDifficulty:
+ break;
+ case TabCompleteCB:
+ break;
+ case ChatMessageCB:
+ break;
+ case MultiBlockChange:
+ break;
+ case ConfirmTransactionCB:
+ break;
+ case CloseWindowCB:
+ break;
+ case OpenWindow:
+ break;
+ case WindowItems:
+ break;
+ case WindowProperty:
+ break;
+ case SetSlot:
+ break;
+ case SetCooldown:
+ break;
+ case PluginMessageCB:
+ break;
+ case NamedSoundEffect:
+ break;
+ case DisconnectPlay:
+ return std::make_shared<PacketDisconnectPlay>();
+ case EntityStatus:
+ break;
+ case Explosion:
+ break;
+ case UnloadChunk:
+ break;
+ case ChangeGameState:
+ break;
+ case KeepAliveCB:
+ return std::make_shared<PacketKeepAliveCB>();
+ case ChunkData:
+ return std::make_shared<PacketChunkData>();
+ case Effect:
+ break;
+ case Particle:
+ break;
+ case JoinGame:
+ return std::make_shared<PacketJoinGame>();
+ case Map:
+ break;
+ case EntityRelativeMove:
+ break;
+ case EntityLookAndRelativeMove:
+ break;
+ case EntityLook:
+ break;
+ case Entity:
+ break;
+ case VehicleMove:
+ break;
+ case OpenSignEditor:
+ break;
+ case PlayerAbilitiesCB:
+ break;
+ case CombatEvent:
+ break;
+ case PlayerListItem:
+ break;
+ case PlayerPositionAndLookCB:
+ return std::make_shared<PacketPlayerPositionAndLookCB>();
+ case UseBed:
+ break;
+ case DestroyEntities:
+ break;
+ case RemoveEntityEffect:
+ break;
+ case ResourcePackSend:
+ break;
+ case Respawn:
+ break;
+ case EntityHeadLook:
+ break;
+ case WorldBorder:
+ break;
+ case Camera:
+ break;
+ case HeldItemChangeCB:
+ break;
+ case DisplayScoreboard:
+ break;
+ case EntityMetadata:
+ break;
+ case AttachEntity:
+ break;
+ case EntityVelocity:
+ break;
+ case EntityEquipment:
+ break;
+ case SetExperience:
+ break;
+ case UpdateHealth:
+ return std::make_shared<PacketUpdateHealth>();
+ case ScoreboardObjective:
+ break;
+ case SetPassengers:
+ break;
+ case Teams:
+ break;
+ case UpdateScore:
+ break;
+ case SpawnPosition:
+ return std::make_shared<PacketSpawnPosition>();
+ case TimeUpdate:
+ break;
+ case Title:
+ break;
+ case SoundEffect:
+ break;
+ case PlayerListHeaderAndFooter:
+ break;
+ case CollectItem:
+ break;
+ case EntityTeleport:
+ break;
+ case EntityProperties:
+ break;
+ case EntityEffect:
+ break;
+ case UnlockRecipes:
+ break;
+ case SelectAdvancementTab:
+ break;
+ case Advancements:
+ break;
+ }
+ return nullptr;
+}
diff --git a/src/Network.hpp b/src/Network.hpp
new file mode 100644
index 0000000..1281289
--- /dev/null
+++ b/src/Network.hpp
@@ -0,0 +1,26 @@
+#pragma once
+
+#include <memory>
+#include "Socket.hpp"
+#include "Packet.hpp"
+
+enum ConnectionState {
+ Handshaking,
+ Login,
+ Play,
+ Status,
+};
+
+class Network {
+ Socket *socket;
+ StreamSocket *stream;
+
+ std::shared_ptr<Packet> ReceivePacketByPacketId(int packetId, ConnectionState state, StreamInput &stream);
+public:
+ Network(std::string address, unsigned short port);
+ ~Network();
+
+ std::shared_ptr<Packet> ReceivePacket(ConnectionState state = Play);
+ void SendPacket(Packet &packet);
+ std::shared_ptr<Packet> ParsePacketPlay(PacketNamePlayCB id);
+}; \ No newline at end of file
diff --git a/src/NetworkClient.cpp b/src/NetworkClient.cpp
new file mode 100644
index 0000000..0b759e6
--- /dev/null
+++ b/src/NetworkClient.cpp
@@ -0,0 +1,93 @@
+#include "NetworkClient.hpp"
+
+NetworkClient::NetworkClient(std::string address, unsigned short port, std::string username, bool &quit)
+ : network(address, port), isRunning(quit) {
+ state = Handshaking;
+
+ PacketHandshake handshake;
+ handshake.protocolVersion = 335;
+ handshake.serverAddress = "127.0.0.1";
+ handshake.serverPort = 25565;
+ handshake.nextState = 2;
+ network.SendPacket(handshake);
+ state = Login;
+
+ PacketLoginStart loginStart;
+ loginStart.Username = "HelloOne";
+ network.SendPacket(loginStart);
+
+ auto response = std::static_pointer_cast<PacketLoginSuccess>(network.ReceivePacket(Login));
+ if (response->Username != username) {
+ throw std::logic_error("Received username is not sended username");
+ }
+
+ state = Play;
+
+ isActive = true;
+ std::thread thread(&NetworkClient::NetworkLoop, this);
+ std::swap(networkThread, thread);
+}
+
+NetworkClient::~NetworkClient() {
+ isActive = false;
+ networkThread.join();
+}
+
+std::shared_ptr<Packet> NetworkClient::ReceivePacket() {
+ if (toReceive.empty())
+ return std::shared_ptr<Packet>(nullptr);
+ toReceiveMutex.lock();
+ auto ret = toReceive.front();
+ toReceive.pop();
+ toReceiveMutex.unlock();
+ return ret;
+}
+
+void NetworkClient::SendPacket(std::shared_ptr<Packet> packet) {
+ toSendMutex.lock();
+ toSend.push(packet);
+ toSendMutex.unlock();
+}
+
+void NetworkClient::NetworkLoop() {
+ auto timeOfLastKeepAlivePacket = std::chrono::steady_clock::now();
+ el::Helpers::setThreadName("Network");
+ LOG(INFO) << "Network thread is started";
+ try {
+ while (isActive) {
+ toSendMutex.lock();
+ while (!toSend.empty()) {
+ if (toSend.front()!=nullptr)
+ network.SendPacket(*toSend.front());
+ toSend.pop();
+ }
+ toSendMutex.unlock();
+ auto packet = network.ReceivePacket(state);
+ if (packet.get() != nullptr) {
+ if (packet->GetPacketId() != PacketNamePlayCB::KeepAliveCB) {
+ toReceiveMutex.lock();
+ toReceive.push(packet);
+ toReceiveMutex.unlock();
+ } else {
+ timeOfLastKeepAlivePacket = std::chrono::steady_clock::now();
+ auto packetKeepAlive = std::static_pointer_cast<PacketKeepAliveCB>(packet);
+ auto packetKeepAliveSB = std::make_shared<PacketKeepAliveSB>(packetKeepAlive->KeepAliveId);
+ network.SendPacket(*packetKeepAliveSB);
+ }
+ }
+ using namespace std::chrono_literals;
+ if (std::chrono::steady_clock::now() - timeOfLastKeepAlivePacket > 20s) {
+ auto disconnectPacket = std::make_shared<PacketDisconnectPlay>();
+ disconnectPacket->Reason = "Timeout";
+ toReceiveMutex.lock();
+ toReceive.push(disconnectPacket);
+ toReceiveMutex.unlock();
+ break;
+ }
+ }
+ } catch (std::exception &e) {
+ LOG(ERROR) << "Exception catched in NetworkLoop: " << e.what();
+ isRunning = false;
+ }
+ LOG(INFO) << "Network thread is stopped";
+}
diff --git a/src/NetworkClient.hpp b/src/NetworkClient.hpp
new file mode 100644
index 0000000..cf41f91
--- /dev/null
+++ b/src/NetworkClient.hpp
@@ -0,0 +1,26 @@
+#pragma once
+
+#include <thread>
+#include <queue>
+#include <mutex>
+
+#include "Network.hpp"
+
+class NetworkClient {
+ Network network;
+ std::thread networkThread;
+ std::mutex toSendMutex;
+ std::mutex toReceiveMutex;
+ std::queue <std::shared_ptr<Packet>> toSend;
+ std::queue <std::shared_ptr<Packet>> toReceive;
+ bool isActive=true;
+ bool &isRunning;
+ ConnectionState state;
+ void NetworkLoop();
+public:
+ NetworkClient(std::string address, unsigned short port, std::string username, bool &quit);
+ ~NetworkClient();
+
+ std::shared_ptr <Packet> ReceivePacket();
+ void SendPacket(std::shared_ptr<Packet> packet);
+}; \ No newline at end of file
diff --git a/src/Packet.hpp b/src/Packet.hpp
new file mode 100644
index 0000000..d615332
--- /dev/null
+++ b/src/Packet.hpp
@@ -0,0 +1,521 @@
+#pragma once
+
+#include <easylogging++.h>
+
+#include "Stream.hpp"
+
+enum PacketNameLoginSB {
+ LoginStart = 0x00,
+ EncryptionResponse = 0x01,
+};
+enum PacketNamePlaySB {
+ TeleportConfirm,
+ PrepareCraftingGrid,
+ TabCompleteSB,
+ ChatMessageSB,
+ ClientStatus,
+ ClientSettings,
+ ConfirmTransactionSB,
+ EnchantItem,
+ ClickWindow,
+ CloseWindowSB,
+ PluginMessageSB,
+ UseEntity,
+ KeepAliveSB,
+ Player,
+ PlayerPosition,
+ PlayerPositionAndLookSB,
+ PlayerLook,
+ VehicleMoveSB,
+ SteerBoat,
+ PlayerAbilitiesSB,
+ PlayerDigging,
+ EntityAction,
+ SteerVehicle,
+ CraftingBookData,
+ ResourcePackStatus,
+ AdvancementTab,
+ HeldItemChangeSB,
+ CreativeInventoryAction,
+ UpdateSign,
+ AnimationSB,
+ Spectate,
+ PlayerBlockPlacement,
+ UseItem,
+};
+
+enum PacketNameHandshakingCB {
+ Handshake = 0x00,
+};
+enum PacketNameLoginCB {
+ Disconnect = 0x00,
+ EncryptionRequest = 0x01,
+ LoginSuccess = 0x02,
+ SetCompression = 0x03,
+};
+enum PacketNamePlayCB {
+ SpawnObject = 0x00,
+ SpawnExperienceOrb,
+ SpawnGlobalEntity,
+ SpawnMob,
+ SpawnPainting,
+ SpawnPlayer,
+ AnimationCB,
+ Statistics,
+ BlockBreakAnimation,
+ UpdateBlockEntity,
+ BlockAction,
+ BlockChange,
+ BossBar,
+ ServerDifficulty,
+ TabCompleteCB,
+ ChatMessageCB,
+ MultiBlockChange,
+ ConfirmTransactionCB,
+ CloseWindowCB,
+ OpenWindow,
+ WindowItems,
+ WindowProperty,
+ SetSlot,
+ SetCooldown,
+ PluginMessageCB,
+ NamedSoundEffect,
+ DisconnectPlay,
+ EntityStatus,
+ Explosion,
+ UnloadChunk,
+ ChangeGameState,
+ KeepAliveCB,
+ ChunkData,
+ Effect,
+ Particle,
+ JoinGame,
+ Map,
+ EntityRelativeMove,
+ EntityLookAndRelativeMove,
+ EntityLook,
+ Entity,
+ VehicleMove,
+ OpenSignEditor,
+ PlayerAbilitiesCB,
+ CombatEvent,
+ PlayerListItem,
+ PlayerPositionAndLookCB,
+ UseBed,
+ UnlockRecipes,
+ DestroyEntities,
+ RemoveEntityEffect,
+ ResourcePackSend,
+ Respawn,
+ EntityHeadLook,
+ SelectAdvancementTab,
+ WorldBorder,
+ Camera,
+ HeldItemChangeCB,
+ DisplayScoreboard,
+ EntityMetadata,
+ AttachEntity,
+ EntityVelocity,
+ EntityEquipment,
+ SetExperience,
+ UpdateHealth,
+ ScoreboardObjective,
+ SetPassengers,
+ Teams,
+ UpdateScore,
+ SpawnPosition,
+ TimeUpdate,
+ Title,
+ SoundEffect,
+ PlayerListHeaderAndFooter,
+ CollectItem,
+ EntityTeleport,
+ Advancements,
+ EntityProperties,
+ EntityEffect,
+};
+
+struct Packet {
+ virtual ~Packet() = default;
+ virtual void ToStream(StreamOutput *stream) = 0;
+ virtual void FromStream(StreamInput *stream) = 0;
+ virtual int GetPacketId() = 0;
+};
+
+struct PacketHandshake : Packet {
+ void ToStream(StreamOutput *stream) override {
+ stream->WriteVarInt(protocolVersion);
+ stream->WriteString(serverAddress);
+ stream->WriteUShort(serverPort);
+ stream->WriteVarInt(nextState);
+ }
+
+ void FromStream(StreamInput *stream) override {
+ protocolVersion = stream->ReadVarInt();
+ serverAddress = stream->ReadString();
+ serverPort = stream->ReadUShort();
+ nextState = stream->ReadVarInt();
+ }
+
+ int GetPacketId() override {
+ return PacketNameHandshakingCB::Handshake;
+ }
+
+ int protocolVersion;
+ std::string serverAddress;
+ unsigned short serverPort;
+ int nextState;
+};
+
+struct PacketLoginStart : Packet {
+ void ToStream(StreamOutput *stream) override {
+ stream->WriteString(Username);
+ }
+
+ void FromStream(StreamInput *stream) override {
+ Username = stream->ReadString();
+ }
+
+ int GetPacketId() override {
+ return PacketNameLoginSB::LoginStart;
+ }
+
+ std::string Username;
+};
+
+struct PacketLoginSuccess : Packet {
+ void ToStream(StreamOutput *stream) override {
+ stream->WriteString(Uuid);
+ stream->WriteString(Username);
+ }
+
+ void FromStream(StreamInput *stream) override {
+ Uuid = stream->ReadString();
+ Username = stream->ReadString();
+ }
+
+ int GetPacketId() override {
+ return PacketNameLoginCB::LoginSuccess;
+ }
+
+ std::string Uuid;
+ std::string Username;
+};
+
+struct PacketJoinGame : Packet {
+ void ToStream(StreamOutput *stream) override {
+ stream->WriteInt(EntityId);
+ stream->WriteUByte(Gamemode);
+ stream->WriteInt(Dimension);
+ stream->WriteUByte(Difficulty);
+ stream->WriteUByte(MaxPlayers);
+ stream->WriteString(LevelType);
+ stream->WriteBool(ReducedDebugInfo);
+ }
+
+ void FromStream(StreamInput *stream) override {
+ EntityId = stream->ReadInt();
+ Gamemode = stream->ReadUByte();
+ Dimension = stream->ReadInt();
+ Difficulty = stream->ReadUByte();
+ MaxPlayers = stream->ReadUByte();
+ LevelType = stream->ReadString();
+ ReducedDebugInfo = stream->ReadBool();
+ }
+
+ int GetPacketId() override {
+ return PacketNamePlayCB::JoinGame;
+ }
+
+ int EntityId;
+ unsigned char Gamemode;
+ int Dimension;
+ unsigned char Difficulty;
+ unsigned char MaxPlayers;
+ std::string LevelType;
+ bool ReducedDebugInfo;
+};
+
+struct PacketDisconnectPlay : Packet {
+ void ToStream(StreamOutput *stream) override {
+ stream->WriteString(Reason); //TODO: Implement chat-wrapper
+ }
+
+ void FromStream(StreamInput *stream) override {
+ Reason = stream->ReadChat();
+ }
+
+ int GetPacketId() override {
+ return PacketNamePlayCB::DisconnectPlay;
+ }
+
+ std::string Reason;
+};
+
+struct PacketSpawnPosition : Packet {
+ void ToStream(StreamOutput *stream) override {
+ stream->WritePosition(Location);
+ }
+
+ void FromStream(StreamInput *stream) override {
+ Location = stream->ReadPosition();
+ }
+
+ int GetPacketId() override {
+ return PacketNamePlayCB::SpawnPosition;
+ }
+
+ Vector Location;
+};
+
+struct PacketKeepAliveCB : Packet {
+ void ToStream(StreamOutput *stream) override {
+ stream->WriteVarInt(KeepAliveId);
+ }
+
+ void FromStream(StreamInput *stream) override {
+ KeepAliveId = stream->ReadVarInt();
+ }
+
+ int GetPacketId() override {
+ return PacketNamePlayCB::KeepAliveCB;
+ }
+
+ int KeepAliveId;
+};
+
+struct PacketKeepAliveSB : Packet {
+ void ToStream(StreamOutput *stream) override {
+ stream->WriteVarInt(KeepAliveId);
+ }
+
+ void FromStream(StreamInput *stream) override {
+ KeepAliveId = stream->ReadVarInt();
+ }
+
+ int GetPacketId() override {
+ return PacketNamePlaySB::KeepAliveSB;
+ }
+
+ int KeepAliveId;
+
+ PacketKeepAliveSB(int KeepAliveId) : KeepAliveId(KeepAliveId) {}
+};
+
+struct PacketPlayerPositionAndLookCB : Packet {
+ void ToStream(StreamOutput *stream) override {
+ stream->WriteDouble(X);
+ stream->WriteDouble(Y);
+ stream->WriteDouble(Z);
+ stream->WriteFloat(Yaw);
+ stream->WriteFloat(Pitch);
+ stream->WriteUByte(Flags);
+ stream->WriteVarInt(TeleportId);
+ }
+
+ void FromStream(StreamInput *stream) override {
+ X = stream->ReadDouble();
+ Y = stream->ReadDouble();
+ Z = stream->ReadDouble();
+ Yaw = stream->ReadFloat();
+ Pitch = stream->ReadFloat();
+ Flags = stream->ReadUByte();
+ TeleportId = stream->ReadVarInt();
+ }
+
+ int GetPacketId() override {
+ return PacketNamePlayCB::PlayerPositionAndLookCB;
+ }
+
+ double X;
+ double Y;
+ double Z;
+ float Yaw;
+ float Pitch;
+ unsigned char Flags;
+ int TeleportId;
+};
+
+struct PacketTeleportConfirm : Packet {
+ void ToStream(StreamOutput *stream) override {
+ stream->WriteVarInt(TeleportId);
+ }
+
+ void FromStream(StreamInput *stream) override {
+ TeleportId = stream->ReadVarInt();
+ }
+
+ int GetPacketId() override {
+ return PacketNamePlaySB::TeleportConfirm;
+ }
+
+ int TeleportId;
+
+ PacketTeleportConfirm(int TeleportId) : TeleportId(TeleportId) {}
+};
+
+struct PacketClientStatus : Packet {
+ void ToStream(StreamOutput *stream) override {
+ stream->WriteVarInt(ActionId);
+ }
+
+ void FromStream(StreamInput *stream) override {
+ ActionId = stream->ReadVarInt();
+ }
+
+ int GetPacketId() override {
+ return PacketNamePlaySB::ClientStatus;
+ }
+
+ int ActionId;
+
+ PacketClientStatus(int ActionId) : ActionId(ActionId) {}
+};
+
+struct PacketPlayerPositionAndLookSB : Packet {
+ void ToStream(StreamOutput *stream) override {
+ stream->WriteDouble(X);
+ stream->WriteDouble(FeetY);
+ stream->WriteDouble(Z);
+ stream->WriteFloat(Yaw);
+ stream->WriteFloat(Pitch);
+ stream->WriteBool(OnGround);
+ }
+
+ void FromStream(StreamInput *stream) override {
+ X = stream->ReadDouble();
+ FeetY = stream->ReadDouble();
+ Z = stream->ReadDouble();
+ Yaw = stream->ReadFloat();
+ Pitch = stream->ReadFloat();
+ OnGround = stream->ReadBool();
+ }
+
+ int GetPacketId() override {
+ return PacketNamePlaySB::PlayerPositionAndLookSB;
+ }
+
+
+ double X;
+ double FeetY;
+ double Z;
+ float Yaw;
+ float Pitch;
+ bool OnGround;
+
+ PacketPlayerPositionAndLookSB(double X, double FeetY, double Z,
+ float Yaw, float Pitch, bool OnGround) : X(X), FeetY(FeetY), Z(Z), Yaw(Yaw),
+ Pitch(Pitch), OnGround(OnGround) {}
+};
+
+struct PacketChunkData : Packet {
+ void ToStream(StreamOutput *stream) override {
+ stream->WriteInt(ChunkX);
+ stream->WriteInt(ChunkZ);
+ stream->WriteBool(GroundUpContinuous);
+ stream->WriteInt(PrimaryBitMask);
+ stream->WriteVarInt(Data.size());
+ stream->WriteByteArray(Data);
+ stream->WriteVarInt(BlockEntities.size());
+ LOG(FATAL) << "Serializing unimplemented packet";
+ }
+
+ void FromStream(StreamInput *stream) override {
+ ChunkX = stream->ReadInt();
+ ChunkZ = stream->ReadInt();
+ GroundUpContinuous = stream->ReadBool();
+ PrimaryBitMask = stream->ReadVarInt();
+ int Size = stream->ReadVarInt();
+ Data = stream->ReadByteArray(Size);
+ int NumberOfBlockEntities = stream->ReadVarInt(); //TODO: Need NBT
+ for (int i = 0; i < NumberOfBlockEntities; i++) {
+ //BlockEntities[i] = stream->ReadNbt();
+ }
+ }
+
+ int GetPacketId() override {
+ return PacketNamePlayCB::ChunkData;
+ }
+
+ int ChunkX;
+ int ChunkZ;
+ bool GroundUpContinuous;
+ int PrimaryBitMask;
+ //int Size;
+ std::vector<unsigned char> Data;
+ //int NumberOfBlockEntities;
+ std::vector<int> BlockEntities; //TODO: Replace int with NbtTag and implement NbtTree
+};
+
+struct PacketPlayerPosition : Packet {
+ void ToStream(StreamOutput *stream) override {
+ stream->WriteDouble(X);
+ stream->WriteDouble(FeetY);
+ stream->WriteDouble(Z);
+ stream->WriteBool(OnGround);
+ }
+
+ void FromStream(StreamInput *stream) override {
+ X = stream->ReadDouble();
+ FeetY = stream->ReadDouble();
+ Z = stream->ReadDouble();
+ OnGround = stream->ReadBool();
+ }
+
+ int GetPacketId() override {
+ return PacketNamePlaySB::PlayerPosition;
+ }
+
+ double X;
+ double FeetY;
+ double Z;
+ bool OnGround;
+
+ PacketPlayerPosition(double X, double Y, double Z, bool ground) : X(X), FeetY(Y), Z(Z), OnGround(ground) {}
+};
+
+struct PacketPlayerLook : Packet {
+ void ToStream(StreamOutput *stream) override {
+ stream->WriteFloat(Yaw);
+ stream->WriteFloat(Pitch);
+ stream->WriteBool(OnGround);
+ }
+
+ void FromStream(StreamInput *stream) override {
+ Yaw = stream->ReadFloat();
+ Pitch = stream->ReadFloat();
+ OnGround = stream->ReadBool();
+ }
+
+ int GetPacketId() override {
+ return PacketNamePlaySB::PlayerLook;
+ }
+
+ float Yaw;
+ float Pitch;
+ bool OnGround;
+
+ PacketPlayerLook(float Yaw, float Pitch, bool ground) : Yaw(Yaw), Pitch(Pitch), OnGround(ground) {}
+};
+
+struct PacketUpdateHealth : Packet {
+ void ToStream(StreamOutput *stream) override {
+ stream->WriteFloat(Health);
+ stream->WriteVarInt(Food);
+ stream->WriteFloat(FoodSaturation);
+ }
+
+ void FromStream(StreamInput *stream) override {
+ Health = stream->ReadFloat();
+ Food = stream->ReadVarInt();
+ FoodSaturation = stream->ReadFloat();
+ }
+
+ int GetPacketId() override {
+ return PacketNamePlayCB::UpdateHealth;
+ }
+
+ float Health;
+ int Food;
+ float FoodSaturation;
+}; \ No newline at end of file
diff --git a/src/Render.cpp b/src/Render.cpp
new file mode 100644
index 0000000..ebfbc20
--- /dev/null
+++ b/src/Render.cpp
@@ -0,0 +1,137 @@
+#include "Render.hpp"
+
+#include "Utility.hpp"
+#include "Shader.hpp"
+#include "AssetManager.hpp"
+#include "Event.hpp"
+
+Render::Render(unsigned int windowWidth, unsigned int windowHeight, std::string windowTitle) {
+ InitSfml(windowWidth, windowHeight, windowTitle);
+ glCheckError();
+ InitGlew();
+ glCheckError();
+ PrepareToRendering();
+ glCheckError();
+}
+
+Render::~Render() {
+ delete window;
+}
+
+void Render::InitSfml(unsigned int WinWidth, unsigned int WinHeight, std::string WinTitle) {
+ LOG(INFO) << "Creating window: " << WinWidth << "x" << WinHeight << " \"" << WinTitle << "\"";
+ sf::ContextSettings contextSetting;
+ contextSetting.majorVersion = 3;
+ contextSetting.minorVersion = 3;
+ contextSetting.attributeFlags = contextSetting.Core;
+ contextSetting.depthBits = 24;
+ window = new sf::Window(sf::VideoMode(WinWidth, WinHeight), WinTitle, sf::Style::Default, contextSetting);
+ glCheckError();
+ window->setPosition(sf::Vector2i(sf::VideoMode::getDesktopMode().width / 2 - window->getSize().x / 2,
+ sf::VideoMode::getDesktopMode().height / 2 - window->getSize().y / 2));
+ SetMouseCapture(false);
+}
+
+void Render::InitGlew() {
+ LOG(INFO) << "Initializing GLEW";
+ glewExperimental = GL_TRUE;
+ GLenum glewStatus = glewInit();
+ glCheckError();
+ if (glewStatus != GLEW_OK) {
+ LOG(FATAL) << "Failed to initialize GLEW: " << glewGetErrorString(glewStatus);
+ }
+ glViewport(0, 0, window->getSize().x, window->getSize().y);
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_BACK);
+ glFrontFace(GL_CCW);
+ //glEnable(GL_BLEND);
+ //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glCheckError();
+}
+
+void Render::PrepareToRendering() {
+ shader = new Shader("./shaders/face.vs", "./shaders/face.fs");
+ shader->Use();
+
+ //TextureAtlas texture
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, AssetManager::Instance().GetTextureAtlas());
+ glUniform1i(glGetUniformLocation(shader->Program, "textureAtlas"), 0);
+}
+
+void Render::RenderFrame() {
+ glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+
+ window->display();
+}
+
+void Render::HandleEvents() {
+ sf::Event event;
+ while (window->pollEvent(event)) {
+ switch (event.type) {
+ case sf::Event::Closed:
+ LOG(INFO) << "Received close event by window closing";
+ isRunning = false;
+ break;
+ case sf::Event::Resized:
+ glViewport(0, 0, window->getSize().x, window->getSize().y);
+ break;
+ case sf::Event::KeyPressed:
+ if (!window->hasFocus()) break;
+ switch (event.key.code) {
+ case sf::Keyboard::Escape:
+ LOG(INFO) << "Received close event by esc";
+ isRunning = false;
+ break;
+ case sf::Keyboard::T:
+ SetMouseCapture(!isMouseCaptured);
+ break;
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ if (window->hasFocus()) {
+ /*if (sf::Keyboard::isKeyPressed(sf::Keyboard::W)) gameState->HandleMovement(GameState::FORWARD, deltaTime);
+ if (sf::Keyboard::isKeyPressed(sf::Keyboard::S)) gameState->HandleMovement(GameState::BACKWARD, deltaTime);
+ if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) gameState->HandleMovement(GameState::LEFT, deltaTime);
+ if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) gameState->HandleMovement(GameState::RIGHT, deltaTime);
+ if (sf::Keyboard::isKeyPressed(sf::Keyboard::Space)) gameState->HandleMovement(GameState::JUMP, deltaTime);*/
+ }
+}
+
+void Render::HandleMouseCapture() {
+ sf::Vector2i mousePos = sf::Mouse::getPosition(*window);
+ sf::Vector2i center = sf::Vector2i(window->getSize().x / 2, window->getSize().y / 2);
+ sf::Mouse::setPosition(center, *window);
+ mouseXDelta = (mousePos - center).x, mouseYDelta = (center - mousePos).y;
+ const float Sensetivity = 0.7f;
+ //gameState->HandleRotation(mouseXDelta * Sensetivity, mouseYDelta * Sensetivity);
+}
+
+void Render::SetMouseCapture(bool IsCaptured) {
+ window->setMouseCursorVisible(!isMouseCaptured);
+ sf::Mouse::setPosition(sf::Vector2i(window->getSize().x / 2, window->getSize().y / 2), *window);
+ isMouseCaptured = IsCaptured;
+ window->setMouseCursorVisible(!IsCaptured);
+}
+
+void Render::ExecuteRenderLoop() {
+ using namespace std::chrono_literals;
+ LoopExecutionTimeController timer(16ms);
+ while (isRunning) {
+ HandleEvents();
+ if (isMouseCaptured) HandleMouseCapture();
+ glCheckError();
+
+ RenderFrame();
+ timer.Update();
+ }
+ EventData data = GlobalAppStateData{GlobalState::Exiting};
+ EventAgregator::PushEvent(EventType::GlobalAppState,data);
+}
diff --git a/src/Render.hpp b/src/Render.hpp
new file mode 100644
index 0000000..636c4c7
--- /dev/null
+++ b/src/Render.hpp
@@ -0,0 +1,32 @@
+#pragma once
+
+#include <SFML/Window.hpp>
+
+#include "Shader.hpp"
+
+class Render {
+ sf::Window *window;
+ bool isRunning=true;
+ bool isMouseCaptured = false;
+ float mouseXDelta, mouseYDelta;
+ Shader *shader;
+
+ void SetMouseCapture(bool IsCaptured);
+
+ void HandleMouseCapture();
+
+ void HandleEvents();
+
+ void InitSfml(unsigned int WinWidth, unsigned int WinHeight, std::string WinTitle);
+
+ void InitGlew();
+
+ void RenderFrame();
+
+ void PrepareToRendering();
+public:
+ Render(unsigned int windowWidth, unsigned int windowHeight, std::string windowTitle);
+ ~Render();
+
+ void ExecuteRenderLoop();
+}; \ No newline at end of file
diff --git a/src/Renderer.cpp b/src/Renderer.cpp
new file mode 100644
index 0000000..5fc8c2e
--- /dev/null
+++ b/src/Renderer.cpp
@@ -0,0 +1,15 @@
+#include "Renderer.hpp"
+
+void RenderState::SetActiveVao(GLuint Vao) {
+ if (Vao != ActiveVao) {
+ glBindVertexArray(Vao);
+ ActiveVao = Vao;
+ }
+}
+
+void RenderState::SetActiveShader(GLuint Shader) {
+ if (Shader != ActiveShader) {
+ glUseProgram(Shader);
+ ActiveShader = Shader;
+ }
+} \ No newline at end of file
diff --git a/src/Renderer.hpp b/src/Renderer.hpp
new file mode 100644
index 0000000..81c5c50
--- /dev/null
+++ b/src/Renderer.hpp
@@ -0,0 +1,18 @@
+#pragma once
+
+#include <GL/glew.h>
+
+class RenderState {
+ GLuint ActiveVao;
+ GLuint ActiveShader;
+public:
+ void SetActiveVao(GLuint Vao);
+ void SetActiveShader(GLuint Shader);
+};
+
+struct Renderer {
+ virtual ~Renderer() = default;
+ virtual void Render(RenderState& renderState) = 0;
+ virtual void PrepareResources() = 0;
+ virtual void PrepareRender() = 0;
+}; \ No newline at end of file
diff --git a/src/RendererSection.cpp b/src/RendererSection.cpp
new file mode 100644
index 0000000..62a0dc7
--- /dev/null
+++ b/src/RendererSection.cpp
@@ -0,0 +1,348 @@
+#include "RendererSection.hpp"
+
+#include <thread>
+
+const GLfloat vertices[] = {
+ 0, 0, 0,
+ 1, 0, 1,
+ 1, 0, 0,
+
+ 0, 0, 0,
+ 0, 0, 1,
+ 1, 0, 1,
+};
+
+const GLfloat uv_coords[] = {
+ 0.0f, 0.0f,
+ 1.0f, 1.0f,
+ 0.0f, 1.0f,
+
+ 0.0f, 0.0f,
+ 1.0f, 0.0f,
+ 1.0f, 1.0f,
+};
+
+const GLuint magicUniqueConstant = 88375;
+GLuint RendererSection::VboVertices = magicUniqueConstant;
+GLuint RendererSection::VboUvs = magicUniqueConstant;
+std::map<GLuint, int> RendererSection::refCounterVbo;
+std::map<GLuint, int> RendererSection::refCounterVao;
+
+
+RendererSection::RendererSection(World *world, Vector position) : sectionPosition(position), world(world) {
+ if (VboVertices == magicUniqueConstant) {
+ glGenBuffers(1, &VboVertices);
+ glGenBuffers(1, &VboUvs);
+
+ //Cube vertices
+ glBindBuffer(GL_ARRAY_BUFFER, VboVertices);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
+
+ //Cube UVs
+ glBindBuffer(GL_ARRAY_BUFFER, VboUvs);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(uv_coords), uv_coords, GL_STATIC_DRAW);
+
+ LOG(INFO) << "Created VBOs with vertices (" << VboVertices << ") and UVs (" << VboUvs
+ << ") for ordinary blocks";
+ }
+
+ glGenBuffers(1, &VboTextures);
+ if (refCounterVbo.find(VboTextures) == refCounterVbo.end())
+ refCounterVbo[VboTextures] = 0;
+ refCounterVbo[VboTextures]++;
+
+ glGenBuffers(1, &VboModels);
+ if (refCounterVbo.find(VboModels) == refCounterVbo.end())
+ refCounterVbo[VboModels] = 0;
+ refCounterVbo[VboModels]++;
+
+ glGenBuffers(1, &VboColors);
+ if (refCounterVbo.find(VboColors) == refCounterVbo.end())
+ refCounterVbo[VboColors] = 0;
+ refCounterVbo[VboColors]++;
+
+ glGenVertexArrays(1, &Vao);
+ if (refCounterVao.find(Vao) == refCounterVao.end())
+ refCounterVao[Vao] = 0;
+ refCounterVao[Vao]++;
+
+ glBindVertexArray(Vao);
+ {
+ //Cube vertices
+ GLuint VertAttribPos = 0;
+ glBindBuffer(GL_ARRAY_BUFFER, VboVertices);
+ glVertexAttribPointer(VertAttribPos, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), nullptr);
+ glEnableVertexAttribArray(VertAttribPos);
+
+ //Cube UVs
+ GLuint UvAttribPos = 2;
+ glBindBuffer(GL_ARRAY_BUFFER, VboUvs);
+ glVertexAttribPointer(UvAttribPos, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), nullptr);
+ glEnableVertexAttribArray(UvAttribPos);
+
+ //Textures
+ GLuint textureAttribPos = 7;
+ glBindBuffer(GL_ARRAY_BUFFER, VboTextures);
+ glVertexAttribPointer(textureAttribPos, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), nullptr);
+ glEnableVertexAttribArray(textureAttribPos);
+ glVertexAttribDivisor(textureAttribPos, 1);
+ glCheckError();
+
+ //Blocks models
+ GLuint matAttribPos = 8;
+ size_t sizeOfMat4 = 4 * 4 * sizeof(GLfloat);
+ glBindBuffer(GL_ARRAY_BUFFER, VboModels);
+ glVertexAttribPointer(matAttribPos + 0, 4, GL_FLOAT, GL_FALSE, sizeOfMat4, nullptr);
+ glVertexAttribPointer(matAttribPos + 1, 4, GL_FLOAT, GL_FALSE, sizeOfMat4, (void *) (1 * 4 * sizeof(GLfloat)));
+ glVertexAttribPointer(matAttribPos + 2, 4, GL_FLOAT, GL_FALSE, sizeOfMat4, (void *) (2 * 4 * sizeof(GLfloat)));
+ glVertexAttribPointer(matAttribPos + 3, 4, GL_FLOAT, GL_FALSE, sizeOfMat4, (void *) (3 * 4 * sizeof(GLfloat)));
+ glEnableVertexAttribArray(matAttribPos + 0);
+ glEnableVertexAttribArray(matAttribPos + 1);
+ glEnableVertexAttribArray(matAttribPos + 2);
+ glEnableVertexAttribArray(matAttribPos + 3);
+ glVertexAttribDivisor(matAttribPos + 0, 1);
+ glVertexAttribDivisor(matAttribPos + 1, 1);
+ glVertexAttribDivisor(matAttribPos + 2, 1);
+ glVertexAttribDivisor(matAttribPos + 3, 1);
+
+ //Color
+ GLuint colorAttribPos = 12;
+ glBindBuffer(GL_ARRAY_BUFFER, VboColors);
+ glVertexAttribPointer(colorAttribPos, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), nullptr);
+ glEnableVertexAttribArray(colorAttribPos);
+ glVertexAttribDivisor(colorAttribPos, 1);
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ }
+ glBindVertexArray(0);
+ glCheckError();
+}
+
+RendererSection::~RendererSection() {
+ refCounterVbo[VboTextures]--;
+ refCounterVbo[VboModels]--;
+ refCounterVbo[VboColors]--;
+ refCounterVao[Vao]--;
+ if (refCounterVbo[VboTextures] <= 0)
+ glDeleteBuffers(1, &VboTextures);
+
+ if (refCounterVbo[VboModels] <= 0)
+ glDeleteBuffers(1, &VboTextures);
+ if (refCounterVbo[VboColors] <= 0)
+ glDeleteBuffers(1, &VboColors);
+
+ if (refCounterVao[Vao] <= 0)
+ glDeleteVertexArrays(1, &Vao);
+}
+
+void RendererSection::Render(RenderState &renderState) {
+ if (!isEnabled) return;
+ if (!models.empty()) {
+ PrepareRender();
+ }
+ renderState.SetActiveVao(Vao);
+ glDrawArraysInstanced(GL_TRIANGLES, 0, 6, numOfFaces);
+ glCheckError();
+}
+
+Section *RendererSection::GetSection() {
+ return &world->GetSection(sectionPosition);
+}
+
+RendererSection::RendererSection(const RendererSection &other) {
+ this->world = other.world;
+ this->VboModels = other.VboModels;
+ this->VboTextures = other.VboTextures;
+ this->VboColors = other.VboColors;
+ this->sectionPosition = other.sectionPosition;
+ this->Vao = other.Vao;
+ this->numOfFaces = other.numOfFaces;
+ this->models = other.models;
+ this->textures = other.textures;
+ this->colors = other.colors;
+ this->hash = other.hash;
+
+ refCounterVbo[VboTextures]++;
+ refCounterVbo[VboModels]++;
+ refCounterVbo[VboColors]++;
+ refCounterVao[Vao]++;
+}
+
+void RendererSection::SetEnabled(bool isEnabled) {
+ this->isEnabled = isEnabled;
+}
+
+bool RendererSection::IsNeedUpdate() {
+ size_t currentHash = world->GetSection(sectionPosition).GetHash();
+ bool isNeedUpdate = currentHash != hash;
+ return isNeedUpdate;
+}
+
+void RendererSection::PrepareResources() {
+ const std::map<BlockTextureId,glm::vec4> &textureAtlas = AssetManager::Instance().GetTextureAtlasIndexes();
+ Section &section = world->GetSection(sectionPosition);
+ models.clear();
+ textures.clear();
+ colors.clear();
+ for (int y = 0; y < 16; y++) {
+ for (int z = 0; z < 16; z++) {
+ for (int x = 0; x < 16; x++) {
+ Vector blockPos = Vector(x, y, z) + (sectionPosition * 16);
+ Block &block = world->GetBlock(blockPos);
+ if (block.id == 0)
+ continue;
+
+ auto checkBlockVisibility = [&](Vector block) -> bool {
+ return section.GetBlock(block).id == 0 ||
+ section.GetBlock(block).id == 31 ||
+ section.GetBlock(block).id == 18;
+ };
+
+ unsigned char isVisible = 0;
+ if (x == 0 || x == 15 || y == 0 || y == 15 || z == 0 || z == 15) {
+ isVisible = 0b1111'1111; //All faces is visible
+ } else {
+ isVisible |= checkBlockVisibility(Vector(x - 1, y, z)) << 0;
+ isVisible |= checkBlockVisibility(Vector(x + 1, y, z)) << 1;
+ isVisible |= checkBlockVisibility(Vector(x, y + 1, z)) << 2;
+ isVisible |= checkBlockVisibility(Vector(x, y - 1, z)) << 3;
+ isVisible |= checkBlockVisibility(Vector(x, y, z - 1)) << 4;
+ isVisible |= checkBlockVisibility(Vector(x, y, z + 1)) << 5;
+ }
+
+ if (isVisible == 0x00)
+ continue;
+
+ glm::mat4 transform;
+ transform = glm::translate(transform, glm::vec3(sectionPosition.GetX() * 16,
+ sectionPosition.GetY() * 16,
+ sectionPosition.GetZ() * 16));
+ transform = glm::translate(transform, glm::vec3(x, y, z));
+ glm::vec3 biomeColor(0.275, 0.63, 0.1);
+ glm::vec3 color(0.0f, 0.0f, 0.0f);
+ if (block.id == 31 || block.id == 18)
+ color = biomeColor;
+
+ if (block.id == 31) { //X-cross like blocks rendering
+ auto texture = textureAtlas.find(BlockTextureId(block.id, block.state, 2));
+ for (int i = 0; i < 4; i++) {
+ textures.push_back(texture->second);
+ colors.push_back(color);
+ }
+ glm::mat4 faceTransform = glm::translate(transform, glm::vec3(0.15f, 0, 0.15f));
+ faceTransform = glm::scale(faceTransform, glm::vec3(1.0f, 0.9f, 1.0f));
+ faceTransform = glm::rotate(faceTransform, glm::radians(90.0f), glm::vec3(0, 0.0f, 1.0f));
+ faceTransform = glm::rotate(faceTransform, glm::radians(45.0f), glm::vec3(1.0f, 0.0f, 0));
+ for (int i = 0; i < 4; i++) {
+ models.push_back(faceTransform);
+ faceTransform = glm::translate(faceTransform, glm::vec3(0.0f, 0.0f, 0.5f));
+ faceTransform = glm::rotate(faceTransform, glm::radians(90.0f), glm::vec3(1.0f, 0.0f, 0.0f));
+ faceTransform = glm::translate(faceTransform, glm::vec3(0.0f, 0.0f, -0.5f));
+ }
+ continue;
+ }
+
+ if (isVisible >> 0 & 0x1) { //east side of block (X+)
+ glm::mat4 faceTransform = glm::translate(transform, glm::vec3(0, 0, 0));
+ faceTransform = glm::rotate(faceTransform, glm::radians(90.0f), glm::vec3(0, 0.0f, 1.0f));
+ models.push_back(faceTransform);
+ auto texture = textureAtlas.find(BlockTextureId(block.id, block.state, 2));
+ if (texture != textureAtlas.end())
+ textures.push_back(texture->second);
+ else
+ textures.push_back(glm::vec4(0.0546875, 0.00442477876106194690,
+ 0.0078125, 0.00442477876106194690)); //Fallback TNT texture
+ colors.push_back(color);
+ }
+ if (isVisible >> 1 & 0x1) { //west side X-
+ glm::mat4 faceTransform = glm::translate(transform, glm::vec3(1, 0, 0));
+ faceTransform = glm::rotate(faceTransform, glm::radians(90.0f), glm::vec3(0, 0.0f, 1.0f));
+ faceTransform = glm::rotate(faceTransform, glm::radians(180.0f), glm::vec3(1.0f, 0.0f, 0.0f));
+ faceTransform = glm::translate(faceTransform, glm::vec3(0, 0, -1));
+ models.push_back(faceTransform);
+ auto texture = textureAtlas.find(BlockTextureId(block.id, block.state, 3));
+ if (texture != textureAtlas.end())
+ textures.push_back(texture->second);
+ else
+ textures.push_back(glm::vec4(0.0546875, 0.00442477876106194690,
+ 0.0078125, 0.00442477876106194690)); //Fallback TNT texture
+ colors.push_back(color);
+ }
+ if (isVisible >> 2 & 0x1) { //Top side Y+
+ glm::mat4 faceTransform = glm::translate(transform, glm::vec3(0, 1, 0));
+ models.push_back(faceTransform);
+ auto texture = textureAtlas.find(BlockTextureId(block.id, block.state, 1));
+ if (texture != textureAtlas.end())
+ textures.push_back(texture->second);
+ else
+ textures.push_back(glm::vec4(0.0546875, 0.00442477876106194690,
+ 0.0078125, 0.00442477876106194690)); //Fallback TNT texture
+ if (block.id != 2)
+ colors.push_back(color);
+ else
+ colors.push_back(biomeColor);
+ }
+ if (isVisible >> 3 & 0x1) { //Bottom side Y-
+ glm::mat4 faceTransform = glm::translate(transform, glm::vec3(0, 0, 0));
+ faceTransform = glm::rotate(faceTransform, glm::radians(180.0f), glm::vec3(1.0f, 0, 0));
+ faceTransform = glm::translate(faceTransform, glm::vec3(0, 0, -1));
+ models.push_back(faceTransform);
+ auto texture = textureAtlas.find(BlockTextureId(block.id, block.state, 0));
+ if (texture != textureAtlas.end())
+ textures.push_back(texture->second);
+ else
+ textures.push_back(glm::vec4(0.0546875, 0.00442477876106194690,
+ 0.0078125, 0.00442477876106194690)); //Fallback TNT texture
+ colors.push_back(color);
+ }
+ if (isVisible >> 4 & 0x1) { //south side Z+
+ glm::mat4 faceTransform = glm::translate(transform, glm::vec3(1, 0, 0));
+ faceTransform = glm::rotate(faceTransform, glm::radians(90.0f), glm::vec3(-1.0f, 0.0f, 0.0f));
+ faceTransform = glm::rotate(faceTransform, glm::radians(90.0f), glm::vec3(0.0f, -1.0f, 0.0f));
+ models.push_back(faceTransform);
+ auto texture = textureAtlas.find(BlockTextureId(block.id, block.state, 3));
+ if (texture != textureAtlas.end())
+ textures.push_back(texture->second);
+ else
+ textures.push_back(glm::vec4(0.0546875, 0.00442477876106194690,
+ 0.0078125, 0.00442477876106194690)); //Fallback TNT texture
+ colors.push_back(color);
+ }
+ if (isVisible >> 5 & 0x1) { //north side Z-
+ glm::mat4 faceTransform = glm::translate(transform, glm::vec3(0, 0, 1));
+ faceTransform = glm::rotate(faceTransform, glm::radians(90.0f), glm::vec3(-1.0f, 0.0f, 0.0f));
+ faceTransform = glm::rotate(faceTransform, glm::radians(90.0f), glm::vec3(0.0f, -1.0f, 0.0f));
+ faceTransform = glm::translate(faceTransform, glm::vec3(0, 0, -1));
+ faceTransform = glm::rotate(faceTransform, glm::radians(180.0f), glm::vec3(1, 0, 0.0f));
+ faceTransform = glm::translate(faceTransform, glm::vec3(0, 0, -1.0f));
+ models.push_back(faceTransform);
+ auto texture = textureAtlas.find(BlockTextureId(block.id, block.state, 4));
+ if (texture != textureAtlas.end())
+ textures.push_back(texture->second);
+ else
+ textures.push_back(glm::vec4(0.0546875, 0.00442477876106194690,
+ 0.0078125, 0.00442477876106194690)); //Fallback TNT texture
+ colors.push_back(color);
+ }
+ }
+ }
+ }
+ numOfFaces = textures.size();
+ hash = section.GetHash();
+}
+
+void RendererSection::PrepareRender() {
+ glBindBuffer(GL_ARRAY_BUFFER, VboTextures);
+ glBufferData(GL_ARRAY_BUFFER, textures.size() * sizeof(glm::vec4), textures.data(), GL_DYNAMIC_DRAW);
+ textures.clear();
+
+ glBindBuffer(GL_ARRAY_BUFFER, VboModels);
+ glBufferData(GL_ARRAY_BUFFER, models.size() * sizeof(glm::mat4), models.data(), GL_DYNAMIC_DRAW);
+ models.clear();
+
+ glBindBuffer(GL_ARRAY_BUFFER, VboColors);
+ glBufferData(GL_ARRAY_BUFFER, colors.size() * sizeof(glm::vec3), colors.data(), GL_DYNAMIC_DRAW);
+ colors.clear();
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+}
diff --git a/src/RendererSection.hpp b/src/RendererSection.hpp
new file mode 100644
index 0000000..093a977
--- /dev/null
+++ b/src/RendererSection.hpp
@@ -0,0 +1,49 @@
+#pragma once
+
+#include <GL/glew.h>
+#include <glm/detail/type_mat.hpp>
+#include <glm/vec2.hpp>
+#include <glm/detail/type_mat4x4.hpp>
+#include <glm/gtx/transform.hpp>
+#include <easylogging++.h>
+
+#include "AssetManager.hpp"
+#include "Section.hpp"
+#include "World.hpp"
+#include "Vector.hpp"
+#include "Renderer.hpp"
+
+class RendererSection : Renderer {
+ Vector sectionPosition;
+ World *world;
+ GLuint Vao, VboTextures, VboModels, VboColors;
+ std::vector<glm::mat4> models;
+ std::vector<glm::vec4> textures;
+ std::vector<glm::vec3> colors;
+
+ static GLuint VboVertices, VboUvs;
+ static std::map<GLuint, int> refCounterVbo;
+ static std::map<GLuint, int> refCounterVao;
+
+ size_t numOfFaces = 0;
+
+ bool isEnabled = true;
+
+ size_t hash = 0;
+public:
+ RendererSection(World *world, Vector position);
+ RendererSection(const RendererSection &other);
+ ~RendererSection() override;
+
+ void Render(RenderState &renderState) override;
+
+ void PrepareResources() override;
+
+ void PrepareRender() override;
+
+ void SetEnabled(bool isEnabled);
+
+ Section *GetSection();
+
+ bool IsNeedUpdate();
+}; \ No newline at end of file
diff --git a/src/RendererWorld.cpp b/src/RendererWorld.cpp
new file mode 100644
index 0000000..c80250c
--- /dev/null
+++ b/src/RendererWorld.cpp
@@ -0,0 +1 @@
+#include "RendererWorld.hpp"
diff --git a/src/RendererWorld.hpp b/src/RendererWorld.hpp
new file mode 100644
index 0000000..761bbde
--- /dev/null
+++ b/src/RendererWorld.hpp
@@ -0,0 +1,7 @@
+#pragma once
+
+#include "RendererSection.hpp"
+
+class RendererWorld {
+
+}; \ No newline at end of file
diff --git a/src/Section.cpp b/src/Section.cpp
new file mode 100644
index 0000000..8b86afd
--- /dev/null
+++ b/src/Section.cpp
@@ -0,0 +1,147 @@
+#include "Section.hpp"
+
+
+Section::Section(Vector position, byte *dataBlocks, size_t dataBlocksLength, byte *dataLight, byte *dataSky,
+ byte bitsPerBlock,
+ std::vector<unsigned short> palette) {
+ worldPosition = position;
+
+ m_dataBlocksLen = dataBlocksLength;
+ m_dataBlocks = new byte[m_dataBlocksLen];
+ std::copy(dataBlocks, dataBlocks + m_dataBlocksLen, m_dataBlocks);
+
+ m_dataLight = new byte[2048];
+ std::copy(dataLight, dataLight + 2048, m_dataLight);
+
+ if (dataSky) {
+ m_dataSkyLight = new byte[2048];
+ std::copy(dataSky, dataSky + 2048, m_dataSkyLight);
+ }
+
+ m_palette = palette;
+ m_bitsPerBlock = bitsPerBlock;
+}
+
+Section::~Section() {
+ delete[] m_dataBlocks;
+ m_dataBlocksLen = 0;
+ m_dataBlocks = nullptr;
+ delete[] m_dataLight;
+ m_dataLight = nullptr;
+ delete[] m_dataSkyLight;
+ m_dataSkyLight = nullptr;
+}
+
+Block &Section::GetBlock(Vector pos) {
+ return m_blocks[pos.GetY() * 256 + pos.GetZ() * 16 + pos.GetX()];
+}
+
+double totalParsingTime = 0;
+
+void Section::Parse() {
+ if (!m_blocks.empty())
+ return;
+
+ long long *longArray = reinterpret_cast<long long *>(m_dataBlocks);
+ for (size_t i = 0; i < m_dataBlocksLen / 8; i++)
+ endswap(&longArray[i]);
+ std::vector<unsigned short> blocks;
+ blocks.reserve(4096);
+ {
+ auto begin = std::chrono::steady_clock::now();
+ int bitPos = 0;
+ unsigned short t = 0;
+ for (size_t i = 0; i < m_dataBlocksLen; i++) {
+ for (int j = 0; j < 8; j++) {
+ t |= (m_dataBlocks[i] & 0x01) ? 0x80 : 0x00;
+ t >>= 1;
+ m_dataBlocks[i] >>= 1;
+ bitPos++;
+ if (bitPos >= m_bitsPerBlock) {
+ bitPos = 0;
+ t >>= m_bitsPerBlock - 1;
+ blocks.push_back(t);
+ t = 0;
+ }
+ }
+ }
+ auto end = std::chrono::steady_clock::now();
+ std::chrono::duration<double, std::milli> time = end - begin;
+ totalParsingTime += time.count();
+ }
+ std::vector<byte> light;
+ light.reserve(4096);
+ for (int i = 0; i < 2048; i++) {
+ byte t = m_dataLight[i];
+ byte first = t & 0b11110000;
+ byte second = t >> 4;
+ light.push_back(first);
+ light.push_back(second);
+ }
+ for (int i = 0; i < 4096; i++) {
+ unsigned short blockId = m_palette.size() > 0 ? m_palette[blocks[i]] : blocks[i];
+ Block block(blockId >> 4, blockId & 0xF);
+ m_blocks.push_back(block);
+ }
+ delete[] m_dataBlocks;
+ m_dataBlocksLen = 0;
+ m_dataBlocks = nullptr;
+ delete[] m_dataLight;
+ m_dataLight = nullptr;
+ delete[] m_dataSkyLight;
+ m_dataSkyLight = nullptr;
+
+ parseWaiter.notify_all();
+}
+
+Section &Section::operator=(Section other) {
+ std::swap(*this, other);
+ return *this;
+}
+
+void swap(Section &a, Section &b) {
+ using std::swap;
+ swap(a.m_dataBlocksLen, b.m_dataBlocksLen);
+ swap(a.m_dataBlocks, b.m_dataBlocks);
+ swap(a.m_dataLight, b.m_dataLight);
+ swap(a.m_dataSkyLight, b.m_dataSkyLight);
+ swap(a.m_blocks, b.m_blocks);
+ swap(a.m_palette, b.m_palette);
+ swap(a.m_bitsPerBlock, b.m_bitsPerBlock);
+}
+
+Section::Section(const Section &other) {
+ worldPosition = other.worldPosition;
+ m_dataBlocksLen = other.m_dataBlocksLen;
+ if (other.m_blocks.empty()) {
+ m_dataBlocks = new byte[m_dataBlocksLen];
+ std::copy(other.m_dataBlocks, other.m_dataBlocks + m_dataBlocksLen, m_dataBlocks);
+
+ m_dataLight = new byte[2048];
+ std::copy(other.m_dataLight, other.m_dataLight + 2048, m_dataLight);
+
+ if (other.m_dataSkyLight) {
+ m_dataSkyLight = new byte[2048];
+ std::copy(other.m_dataSkyLight, other.m_dataSkyLight + 2048, m_dataSkyLight);
+ }
+ } else {
+ std::copy(other.m_blocks.begin(), other.m_blocks.end(), std::back_inserter(m_blocks));
+ }
+
+ m_palette = other.m_palette;
+ m_bitsPerBlock = other.m_bitsPerBlock;
+}
+
+Vector Section::GetPosition() {
+ return worldPosition;
+}
+
+size_t Section::GetHash() {
+ if (m_blocks.empty()) return 0;
+
+ unsigned char *from = reinterpret_cast<unsigned char *>(m_blocks.data());
+ size_t length = m_blocks.size() * sizeof(Block);
+
+ std::string str(from, from + length);
+ return std::hash<std::string>{}(str);
+} \ No newline at end of file
diff --git a/src/Section.hpp b/src/Section.hpp
new file mode 100644
index 0000000..f40fdf9
--- /dev/null
+++ b/src/Section.hpp
@@ -0,0 +1,51 @@
+#pragma once
+
+#include <vector>
+#include <map>
+#include <condition_variable>
+#include <functional>
+
+#include <easylogging++.h>
+
+#include "Block.hpp"
+#include "Vector.hpp"
+#include "Utility.hpp"
+
+const int SECTION_WIDTH = 16;
+const int SECTION_LENGTH = 16;
+const int SECTION_HEIGHT = 16;
+
+class Section {
+ std::vector<unsigned short> m_palette;
+ byte *m_dataBlocks = nullptr;
+ size_t m_dataBlocksLen;
+ byte *m_dataLight = nullptr;
+ byte *m_dataSkyLight = nullptr;
+ byte m_bitsPerBlock = 0;
+ std::vector<Block> m_blocks;
+ std::condition_variable parseWaiter;
+
+ Section();
+
+ Vector worldPosition;
+
+public:
+ void Parse();
+
+ Section(Vector position, byte *dataBlocks, size_t dataBlocksLength, byte *dataLight, byte *dataSky, byte bitsPerBlock,
+ std::vector<unsigned short> palette);
+
+ ~Section();
+
+ Block &GetBlock(Vector pos);
+
+ Section &operator=(Section other);
+
+ friend void swap(Section &a, Section &b);
+
+ Section(const Section &other);
+
+ Vector GetPosition();
+
+ size_t GetHash();
+}; \ No newline at end of file
diff --git a/src/Shader.cpp b/src/Shader.cpp
new file mode 100644
index 0000000..cf43115
--- /dev/null
+++ b/src/Shader.cpp
@@ -0,0 +1,115 @@
+#include "Shader.hpp"
+
+Shader::Shader(const GLchar *vertexPath, const GLchar *fragmentPath, const GLchar *geometryPath) {
+ vertex = vertexPath;
+ fragment = fragmentPath;
+ // 1. Получаем исходный код шейдера из filePath
+ std::string vertexCode;
+ std::string fragmentCode;
+ std::string geometryCode;
+ std::ifstream vShaderFile;
+ std::ifstream fShaderFile;
+ std::ifstream gShaderFile;
+ // Удостоверимся, что ifstream объекты могут выкидывать исключения
+ vShaderFile.exceptions(std::ifstream::failbit);
+ fShaderFile.exceptions(std::ifstream::failbit);
+ gShaderFile.exceptions(std::ifstream::failbit);
+ try {
+ // Открываем файлы
+ vShaderFile.open(vertexPath);
+ fShaderFile.open(fragmentPath);
+ if (geometryPath != nullptr)
+ gShaderFile.open(geometryPath);
+ std::stringstream vShaderStream, fShaderStream, gShaderStream;
+ // Считываем данные в потоки
+ vShaderStream << vShaderFile.rdbuf();
+ fShaderStream << fShaderFile.rdbuf();
+ if (geometryPath != nullptr)
+ gShaderStream << gShaderFile.rdbuf();
+ // Закрываем файлы
+ vShaderFile.close();
+ fShaderFile.close();
+ if (geometryPath != nullptr)
+ gShaderFile.close();
+ // Преобразовываем потоки в массив GLchar
+ vertexCode = vShaderStream.str();
+ fragmentCode = fShaderStream.str();
+ if (geometryPath != nullptr)
+ geometryCode = gShaderStream.str();
+ }
+ catch (std::ifstream::failure e) {
+ LOG(ERROR) << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ";
+ }
+ const GLchar *vShaderCode = vertexCode.c_str();
+ const GLchar *fShaderCode = fragmentCode.c_str();
+ const GLchar *gShaderCode = geometryCode.c_str();
+
+ // 2. Сборка шейдеров
+ GLuint vertex, fragment, geometry;
+ GLint success;
+ GLchar infoLog[512];
+
+ // Вершинный шейдер
+ vertex = glCreateShader(GL_VERTEX_SHADER);
+ glShaderSource(vertex, 1, &vShaderCode, NULL);
+ glCompileShader(vertex);
+ // Если есть ошибки - вывести их
+ glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
+ if (!success) {
+ glGetShaderInfoLog(vertex, 512, NULL, infoLog);
+ LOG(ERROR) << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog;
+ };
+
+ // Вершинный шейдер
+ fragment = glCreateShader(GL_FRAGMENT_SHADER);
+ glShaderSource(fragment, 1, &fShaderCode, NULL);
+ glCompileShader(fragment);
+ // Если есть ошибки - вывести их
+ glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
+ if (!success) {
+ glGetShaderInfoLog(fragment, 512, NULL, infoLog);
+ LOG(ERROR) << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog;
+ };
+
+ if (geometryPath != nullptr) {
+ geometry = glCreateShader(GL_GEOMETRY_SHADER);
+ glShaderSource(geometry, 1, &gShaderCode, NULL);
+ glCompileShader(geometry);
+ // Если есть ошибки - вывести их
+ glGetShaderiv(geometry, GL_COMPILE_STATUS, &success);
+ if (!success) {
+ glGetShaderInfoLog(geometry, 512, NULL, infoLog);
+ LOG(ERROR) << "ERROR::SHADER::GEOMETRY::COMPILATION_FAILED\n" << infoLog;
+ };
+ }
+
+ // Шейдерная программа
+ this->Program = glCreateProgram();
+ glAttachShader(this->Program, vertex);
+ glAttachShader(this->Program, fragment);
+ if (geometryPath != nullptr)
+ glAttachShader(this->Program, geometry);
+ glLinkProgram(this->Program);
+ //Если есть ошибки - вывести их
+ glGetProgramiv(this->Program, GL_LINK_STATUS, &success);
+ if (!success) {
+ glGetProgramInfoLog(this->Program, 512, NULL, infoLog);
+ LOG(FATAL) << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog;
+ }
+
+ // Удаляем шейдеры, поскольку они уже в программу и нам больше не нужны.
+ glDeleteShader(vertex);
+ glDeleteShader(fragment);
+}
+
+void Shader::Use() {
+ glUseProgram(this->Program);
+}
+
+void Shader::Reload() {
+ const GLchar *vertexPath = vertex;
+ const GLchar *fragmentPath = fragment;
+ this->~Shader();
+ new(this) Shader(vertexPath, fragmentPath);
+ LOG(INFO) << "Shader is realoded!";
+}
diff --git a/src/Shader.hpp b/src/Shader.hpp
new file mode 100644
index 0000000..17a434e
--- /dev/null
+++ b/src/Shader.hpp
@@ -0,0 +1,24 @@
+#pragma once
+
+#include <string>
+#include <fstream>
+#include <sstream>
+
+#include <easylogging++.h>
+#include <GL/glew.h>
+
+class Shader
+{
+private:
+ const GLchar *vertex;
+ const GLchar *fragment;
+public:
+ // Идентификатор программы
+ GLuint Program;
+ // Конструктор считывает и собирает шейдер
+ Shader(const GLchar* vertexPath, const GLchar* fragmentPath, const GLchar* geometryPath = nullptr);
+ // Использование программы
+ void Use();
+
+ void Reload();
+}; \ No newline at end of file
diff --git a/src/Socket.cpp b/src/Socket.cpp
new file mode 100644
index 0000000..2bbf49a
--- /dev/null
+++ b/src/Socket.cpp
@@ -0,0 +1,29 @@
+#include "Socket.hpp"
+
+Socket::Socket(std::string address, unsigned short port) {
+ sf::Socket::Status connectionStatus = socket.connect(sf::IpAddress(address), port);
+ if (connectionStatus == sf::Socket::Status::Error)
+ throw std::runtime_error("Can't connect to remote server");
+ else if (connectionStatus != sf::Socket::Status::Done)
+ throw std::runtime_error("Connection failed with unknown reason");
+}
+
+Socket::~Socket() {
+ socket.disconnect();
+}
+
+void Socket::Read(unsigned char *buffPtr, size_t buffLen) {
+ size_t received = 0;
+ socket.receive(buffPtr, buffLen, received);
+ size_t totalReceived = received;
+ while (totalReceived < buffLen) {
+ if (socket.receive(buffPtr + totalReceived, buffLen - totalReceived, received) != sf::Socket::Done)
+ throw std::runtime_error("Raw socket data receiving is failed");
+ totalReceived += received;
+ }
+}
+
+void Socket::Write(unsigned char *buffPtr, size_t buffLen) {
+ if (socket.send(buffPtr, buffLen) != sf::Socket::Done)
+ throw std::runtime_error("Raw socket data sending is failed");
+}
diff --git a/src/Socket.hpp b/src/Socket.hpp
new file mode 100644
index 0000000..48bcad9
--- /dev/null
+++ b/src/Socket.hpp
@@ -0,0 +1,46 @@
+#pragma once
+
+#include <string>
+
+#include <SFML/Network.hpp>
+
+/**
+ * Platform independent class for working with platform dependent hardware socket
+ * @brief Wrapper around raw sockets
+ * @warning Connection state is based on lifetime of Socket object instance, ie connected at ctor and disconnect at dtor
+ * @todo Replace SFML's socket with WinSock and POSIX's socket implementation
+ */
+class Socket {
+ sf::TcpSocket socket;
+public:
+ /**
+ * Constructs Socket class instance from IP's string and Port number and connects to remote server
+ * @param[in] address IP address of remote server. String should be ANSI and contains 4 one-byte values separated by dots
+ * @param[in] port target port of remote server to connect
+ * @throw std::runtime_error if connection is failed
+ */
+ Socket(std::string address, unsigned short port);
+
+ /**
+ * Destruct Socket instance and disconnect from server
+ * @warning There is no way to force disconnect, except use delete for manually allocated objects and scope of visibility for variables on stack
+ */
+ ~Socket();
+
+ /**
+ * Reads data from socket and write to buffer
+ * @warning This is blocking function, and execution flow will not be returned until all required data is sended
+ * @warning Reported buffer length must be <= actual size of buffer, or memory corruption will be caused
+ * @param[out] buffPtr Pointer to buffer, where data must be placed
+ * @param[in] buffLen Length of data, that must be readed from server and writed to buffer
+ */
+ void Read(unsigned char *buffPtr, size_t buffLen);
+
+ /**
+ * Writes data from buffer to socket
+ * @warning This is blocking function, and execution flow will not be returned until all required data is received
+ * @param[in] buffPtr Pointer to buffer that contain data to send
+ * @param[in] buffLen Length of buffer
+ */
+ void Write(unsigned char *buffPtr, size_t buffLen);
+}; \ No newline at end of file
diff --git a/src/Stream.cpp b/src/Stream.cpp
new file mode 100644
index 0000000..54b1e1b
--- /dev/null
+++ b/src/Stream.cpp
@@ -0,0 +1,348 @@
+#include "Stream.hpp"
+
+const int MAX_VARINT_LENGTH = 5;
+
+bool StreamInput::ReadBool() {
+ unsigned char value;
+ ReadData(&value, 1);
+ return value != 0;
+}
+
+signed char StreamInput::ReadByte() {
+ signed char value;
+ ReadData((unsigned char *) &value, 1);
+ endswap(value);
+ return value;
+}
+
+unsigned char StreamInput::ReadUByte() {
+ unsigned char value;
+ ReadData(&value, 1);
+ endswap(value);
+ return value;
+}
+
+short StreamInput::ReadShort() {
+ unsigned short value;
+ ReadData((unsigned char *) &value, 2);
+ endswap(value);
+ return value;
+}
+
+unsigned short StreamInput::ReadUShort() {
+ unsigned short value;
+ ReadData((unsigned char *) &value, 2);
+ endswap(value);
+ return value;
+}
+
+int StreamInput::ReadInt() {
+ int value;
+ ReadData((unsigned char *) &value, 4);
+ endswap(value);
+ return value;
+}
+
+long long StreamInput::ReadLong() {
+ long long value;
+ ReadData((unsigned char *) &value, 8);
+ endswap(value);
+ return value;
+}
+
+float StreamInput::ReadFloat() {
+ float value;
+ ReadData((unsigned char *) &value, 4);
+ endswap(value);
+ return value;
+}
+
+double StreamInput::ReadDouble() {
+ double value;
+ ReadData((unsigned char *) &value, 8);
+ endswap(value);
+ return value;
+}
+
+std::string StreamInput::ReadString() {
+ int strLength = ReadVarInt();
+ unsigned char *buff = new unsigned char[strLength + 1];
+ ReadData(buff, strLength);
+ buff[strLength] = 0;
+ std::string str((char *) buff);
+ delete buff;
+ return str;
+}
+
+std::string StreamInput::ReadChat() {
+ std::string str, jsonStr = ReadString();
+ nlohmann::json json;
+ try {
+ json = nlohmann::json::parse(jsonStr);
+ } catch (std::exception &e) {
+ LOG(WARNING) << "Chat json parsing failed: " << e.what();
+ LOG(WARNING) << "Corrupted json: " << jsonStr;
+ return "";
+ }
+ if (json.find("translate") != json.end())
+ if (json["translate"].get<std::string>() == "multiplayer.disconnect.kicked")
+ return "kicked by operator";
+ for (auto &it:json["extra"]) {
+ str += it["text"].get<std::string>();
+ }
+ return str;
+}
+
+int StreamInput::ReadVarInt() {
+ unsigned char data[MAX_VARINT_LENGTH] = {0};
+ size_t dataLen = 0;
+ do {
+ ReadData(&data[dataLen], 1);
+ } while ((data[dataLen++] & 0x80) != 0);
+
+ int readed = 0;
+ int result = 0;
+ char read;
+ do {
+ read = data[readed];
+ int value = (read & 0b01111111);
+ result |= (value << (7 * readed));
+ readed++;
+ } while ((read & 0b10000000) != 0);
+
+ return result;
+}
+
+long long StreamInput::ReadVarLong() {
+ return 0;
+}
+
+std::vector<unsigned char> StreamInput::ReadEntityMetadata() {
+ return std::vector<unsigned char>();
+}
+
+std::vector<unsigned char> StreamInput::ReadSlot() {
+ return std::vector<unsigned char>();
+}
+
+std::vector<unsigned char> StreamInput::ReadNbtTag() {
+ return std::vector<unsigned char>();
+}
+
+Vector StreamInput::ReadPosition() {
+ unsigned long long t = ReadLong();
+ int x = t >> 38;
+ int y = (t >> 26) & 0xFFF;
+ int z = t << 38 >> 38;
+ if (x >= pow(2, 25)) {
+ x -= pow(2, 26);
+ }
+ if (y >= pow(2, 11)) {
+ y -= pow(2, 12);
+ }
+ if (z >= pow(2, 25)) {
+ z -= pow(2, 26);
+ }
+ return Vector(x, y, z);
+}
+
+unsigned char StreamInput::ReadAngle() {
+ return ReadUByte();
+}
+
+std::vector<unsigned char> StreamInput::ReadUuid() {
+ unsigned char buff[16];
+ ReadData(buff, 16);
+ endswap(buff, 16);
+ return std::vector<unsigned char>(buff, buff + 16);
+}
+
+std::vector<unsigned char> StreamInput::ReadByteArray(size_t arrLength) {
+ unsigned char *buffer = new unsigned char[arrLength];
+ ReadData(buffer, arrLength);
+ std::vector<unsigned char> ret(buffer, buffer + arrLength);
+ delete buffer;
+ return ret;
+
+}
+
+void StreamOutput::WriteBool(bool value) {
+ unsigned char val = value ? 1 : 0;
+ endswap(val);
+ WriteData(&val, 1);
+}
+
+void StreamOutput::WriteByte(signed char value) {
+ endswap(value);
+ WriteData((unsigned char *) &value, 1);
+}
+
+void StreamOutput::WriteUByte(unsigned char value) {
+ endswap(value);
+ WriteData(&value, 1);
+}
+
+void StreamOutput::WriteShort(short value) {
+ endswap(value);
+ WriteData((unsigned char *) &value, 2);
+}
+
+void StreamOutput::WriteUShort(unsigned short value) {
+ endswap(value);
+ WriteData((unsigned char *) &value, 2);
+}
+
+void StreamOutput::WriteInt(int value) {
+ endswap(value);
+ WriteData((unsigned char *) &value, 4);
+}
+
+void StreamOutput::WriteLong(long long value) {
+ endswap(value);
+ WriteData((unsigned char *) &value, 8);
+}
+
+void StreamOutput::WriteFloat(float value) {
+ endswap(value);
+ WriteData((unsigned char *) &value, 4);
+}
+
+void StreamOutput::WriteDouble(double value) {
+ endswap(value);
+ WriteData((unsigned char *) &value, 8);
+}
+
+void StreamOutput::WriteString(std::string value) {
+ WriteVarInt(value.size());
+ WriteData((unsigned char *) value.data(), value.size());
+}
+
+void StreamOutput::WriteChat(std::string value) {
+ WriteString(value);
+}
+
+void StreamOutput::WriteVarInt(int value) {
+ unsigned char buff[5];
+ size_t len = 0;
+ do {
+ unsigned char temp = (unsigned char) (value & 0b01111111);
+ value >>= 7;
+ if (value != 0) {
+ temp |= 0b10000000;
+ }
+ buff[len] = temp;
+ len++;
+ } while (value != 0);
+ WriteData(buff, len);
+}
+
+void StreamOutput::WriteVarLong(long long value) {
+ unsigned char buff[10];
+ size_t len = 0;
+ do {
+ unsigned char temp = (unsigned char) (value & 0b01111111);
+ value >>= 7;
+ if (value != 0) {
+ temp |= 0b10000000;
+ }
+ buff[len] = temp;
+ len++;
+ } while (value != 0);
+ WriteData(buff, len);
+}
+
+void StreamOutput::WriteEntityMetadata(std::vector<unsigned char> value) {
+ LOG(FATAL) << "Used unimplemented WriteEntityMetadata: " << value.size();
+}
+
+void StreamOutput::WriteSlot(std::vector<unsigned char> value) {
+ LOG(FATAL) << "Used unimplemented WriteSlot " << value.size();
+}
+
+void StreamOutput::WriteNbtTag(std::vector<unsigned char> value) {
+ LOG(FATAL) << "Used unimplemented WriteNbtTag " << value.size();
+}
+
+void StreamOutput::WritePosition(Vector value) {
+ LOG(FATAL) << "Used unimplemented Position: " << value.GetX() << ", " << value.GetY() << " " << value.GetZ();
+}
+
+void StreamOutput::WriteAngle(unsigned char value) {
+ WriteUByte(value);
+}
+
+void StreamOutput::WriteUuid(std::vector<unsigned char> value) {
+ WriteByteArray(value);
+}
+
+void StreamOutput::WriteByteArray(std::vector<unsigned char> value) {
+ WriteData(value.data(), value.size());
+}
+
+void StreamBuffer::ReadData(unsigned char *buffPtr, size_t buffLen) {
+ size_t bufferLengthLeft = buffer + bufferLength - bufferPtr;
+ if (bufferLengthLeft < buffLen)
+ throw std::runtime_error("Required data is more, than in buffer available");
+ std::memcpy(buffPtr, bufferPtr, buffLen);
+ bufferPtr += buffLen;
+}
+
+void StreamBuffer::WriteData(unsigned char *buffPtr, size_t buffLen) {
+ size_t bufferLengthLeft = buffer + bufferLength - bufferPtr;
+ if (bufferLengthLeft < buffLen)
+ throw std::runtime_error("Required data is more, than in buffer available");
+ std::memcpy(bufferPtr, buffPtr, buffLen);
+ bufferPtr += buffLen;
+}
+
+StreamBuffer::StreamBuffer(unsigned char *data, size_t dataLen) {
+ buffer = new unsigned char[dataLen];
+ bufferPtr = buffer;
+ bufferLength = dataLen;
+ std::memcpy(buffer, data, dataLen);
+}
+
+StreamBuffer::StreamBuffer(size_t bufferLen) {
+ buffer = new unsigned char[bufferLen];
+ bufferPtr = buffer;
+ bufferLength = bufferLen;
+ for (unsigned char *p = buffer; p != buffer + bufferLength; ++p)
+ *p = 0;
+}
+
+StreamBuffer::~StreamBuffer() {
+ delete buffer;
+}
+
+std::vector<unsigned char> StreamBuffer::GetBuffer() {
+ return std::vector<unsigned char>(buffer, buffer + bufferLength);
+}
+
+void StreamCounter::WriteData(unsigned char *buffPtr, size_t buffLen) {
+ buffPtr++;
+ size += buffLen;
+}
+
+StreamCounter::StreamCounter(size_t initialSize) : size(initialSize) {
+
+}
+
+StreamCounter::~StreamCounter() {
+
+}
+
+size_t StreamCounter::GetCountedSize() {
+ return size;
+}
+
+void StreamSocket::ReadData(unsigned char *buffPtr, size_t buffLen) {
+ socket->Read(buffPtr, buffLen);
+}
+
+void StreamSocket::WriteData(unsigned char *buffPtr, size_t buffLen) {
+ socket->Write(buffPtr, buffLen);
+}
+
+StreamSocket::StreamSocket(Socket *socketPtr) : socket(socketPtr) {
+
+} \ No newline at end of file
diff --git a/src/Stream.hpp b/src/Stream.hpp
new file mode 100644
index 0000000..b856d5f
--- /dev/null
+++ b/src/Stream.hpp
@@ -0,0 +1,107 @@
+#pragma once
+
+#include <algorithm>
+#include <string>
+#include <stdexcept>
+#include <vector>
+#include <cstring>
+
+#include <nlohmann/json.hpp>
+#include <easylogging++.h>
+
+#include "Socket.hpp"
+#include "Vector.hpp"
+#include "Utility.hpp"
+
+class Stream {
+public:
+ virtual ~Stream() {};
+};
+
+class StreamInput : Stream {
+ virtual void ReadData(unsigned char *buffPtr, size_t buffLen) = 0;
+public:
+ virtual ~StreamInput() = default;
+ bool ReadBool();
+ signed char ReadByte();
+ unsigned char ReadUByte();
+ short ReadShort();
+ unsigned short ReadUShort();
+ int ReadInt();
+ long long ReadLong();
+ float ReadFloat();
+ double ReadDouble();
+ std::string ReadString();
+ std::string ReadChat();
+ int ReadVarInt();
+ long long ReadVarLong();
+ std::vector<unsigned char> ReadEntityMetadata();
+ std::vector<unsigned char> ReadSlot();
+ std::vector<unsigned char> ReadNbtTag();
+ Vector ReadPosition();
+ unsigned char ReadAngle();
+ std::vector<unsigned char> ReadUuid();
+ std::vector<unsigned char> ReadByteArray(size_t arrLength);
+};
+
+class StreamOutput : Stream {
+ virtual void WriteData(unsigned char *buffPtr, size_t buffLen) = 0;
+public:
+ virtual ~StreamOutput() = default;
+ void WriteBool(bool value);
+ void WriteByte(signed char value);
+ void WriteUByte(unsigned char value);
+ void WriteShort(short value);
+ void WriteUShort(unsigned short value);
+ void WriteInt(int value);
+ void WriteLong(long long value);
+ void WriteFloat(float value);
+ void WriteDouble(double value);
+ void WriteString(std::string value);
+ void WriteChat(std::string value);
+ void WriteVarInt(int value);
+ void WriteVarLong(long long value);
+ void WriteEntityMetadata(std::vector<unsigned char> value);
+ void WriteSlot(std::vector<unsigned char> value);
+ void WriteNbtTag(std::vector<unsigned char> value);
+ void WritePosition(Vector value);
+ void WriteAngle(unsigned char value);
+ void WriteUuid(std::vector<unsigned char> value);
+ void WriteByteArray(std::vector<unsigned char> value);
+};
+
+class StreamBuffer : public StreamInput, public StreamOutput {
+ unsigned char *buffer;
+ unsigned char *bufferPtr;
+ size_t bufferLength;
+
+ void ReadData(unsigned char *buffPtr, size_t buffLen) override;
+ void WriteData(unsigned char *buffPtr, size_t buffLen) override;
+
+public:
+ StreamBuffer(unsigned char *data, size_t dataLen);
+ StreamBuffer(size_t bufferLen);
+ ~StreamBuffer();
+
+ std::vector<unsigned char> GetBuffer();
+};
+
+class StreamCounter : public StreamOutput {
+ void WriteData(unsigned char *buffPtr, size_t buffLen) override;
+
+ size_t size;
+public:
+ StreamCounter(size_t initialSize = 0);
+ ~StreamCounter();
+
+ size_t GetCountedSize();
+};
+
+class StreamSocket : public StreamInput, public StreamOutput {
+ Socket *socket;
+ void ReadData(unsigned char *buffPtr, size_t buffLen) override;
+ void WriteData(unsigned char *buffPtr, size_t buffLen) override;
+public:
+ StreamSocket(Socket *socketPtr);
+ ~StreamSocket() = default;
+}; \ No newline at end of file
diff --git a/src/Texture.cpp b/src/Texture.cpp
new file mode 100644
index 0000000..5d183c3
--- /dev/null
+++ b/src/Texture.cpp
@@ -0,0 +1,37 @@
+#include "Texture.hpp"
+
+Texture::Texture(std::string filename, GLenum textureWrapping, GLenum textureFiltering) {
+ glGenTextures(1, &texture);
+ glBindTexture(GL_TEXTURE_2D, texture);
+
+ //Texture options
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, textureWrapping);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, textureWrapping);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, textureFiltering);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ //Image load
+ sf::Image image;
+ if (!image.loadFromFile(filename)) {
+ LOG(ERROR) << "Can't open image " << filename;
+ throw 201;
+ }
+ if (image.getPixelsPtr() == nullptr) {
+ LOG(ERROR) << "Image data is corrupted!";
+ throw 202;
+ }
+ image.flipVertically();
+
+
+ //Creating texture
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.getSize().x, image.getSize().y, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ (GLvoid *) image.getPixelsPtr());
+ glGenerateMipmap(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+}
+
+Texture::~Texture() {
+ glDeleteTextures(1, &texture);
+}
diff --git a/src/Texture.hpp b/src/Texture.hpp
new file mode 100644
index 0000000..5b2afcf
--- /dev/null
+++ b/src/Texture.hpp
@@ -0,0 +1,14 @@
+#pragma once
+
+#include <easylogging++.h>
+#include <GL/glew.h>
+#include <SFML/Graphics.hpp>
+
+class Texture {
+ Texture(Texture&);
+ Texture&operator=(Texture&);
+public:
+ GLuint texture;
+ Texture(std::string filename, GLenum textureWrapping = GL_CLAMP_TO_BORDER, GLenum textureFiltering = GL_NEAREST);
+ ~Texture();
+}; \ No newline at end of file
diff --git a/src/Utility.cpp b/src/Utility.cpp
new file mode 100644
index 0000000..9fecc08
--- /dev/null
+++ b/src/Utility.cpp
@@ -0,0 +1,73 @@
+#include <thread>
+#include "Utility.hpp"
+
+GLenum glCheckError_(const char *file, int line) {
+ GLenum errorCode;
+ while ((errorCode = glGetError()) != GL_NO_ERROR) {
+ std::string error;
+ switch (errorCode) {
+ case GL_INVALID_ENUM:
+ error = "INVALID_ENUM";
+ break;
+ case GL_INVALID_VALUE:
+ error = "INVALID_VALUE";
+ break;
+ case GL_INVALID_OPERATION:
+ error = "INVALID_OPERATION";
+ break;
+ case GL_STACK_OVERFLOW:
+ error = "STACK_OVERFLOW";
+ break;
+ case GL_STACK_UNDERFLOW:
+ error = "STACK_UNDERFLOW";
+ break;
+ case GL_OUT_OF_MEMORY:
+ error = "OUT_OF_MEMORY";
+ break;
+ case GL_INVALID_FRAMEBUFFER_OPERATION:
+ error = "INVALID_FRAMEBUFFER_OPERATION";
+ break;
+ }
+ static int t = 0;
+ t++;
+ if (t > 10)
+ LOG(FATAL);
+ LOG(ERROR) << "OpenGL error: " << error << " at " << file << ":" << line;
+ }
+ return errorCode;
+}
+
+LoopExecutionTimeController::LoopExecutionTimeController(duration delayLength) : delayLength(delayLength) {
+ previousUpdate = clock::now();
+}
+
+LoopExecutionTimeController::~LoopExecutionTimeController() {
+
+}
+
+void LoopExecutionTimeController::SetDelayLength(duration length) {
+ delayLength = length;
+}
+
+unsigned long long LoopExecutionTimeController::GetIterations() {
+ return iterations;
+}
+
+void LoopExecutionTimeController::Update() {
+ iterations++;
+ auto timeToSleep = delayLength - GetDelta();
+ if (timeToSleep.count()>0)
+ std::this_thread::sleep_for(timeToSleep);
+ previousUpdate = clock::now();
+}
+
+double LoopExecutionTimeController::GetDeltaMs() {
+ auto now = clock::now();
+ return duration(now-previousUpdate).count();
+}
+
+LoopExecutionTimeController::duration LoopExecutionTimeController::GetDelta() {
+ auto now = clock::now();
+ //std::cerr<<duration(now-previousUpdate).count()<<std::endl;
+ return duration(now-previousUpdate);
+}
diff --git a/src/Utility.hpp b/src/Utility.hpp
index 11b4ff7..52d6016 100644
--- a/src/Utility.hpp
+++ b/src/Utility.hpp
@@ -1,7 +1,10 @@
#pragma once
#include <algorithm>
+#include <string>
+#include <chrono>
+#include <easylogging++.h>
#include <GL/glew.h>
template<class T>
@@ -20,40 +23,30 @@ inline void endswap(unsigned char *arr, size_t arrLen) {
std::reverse(arr, arr + arrLen);
}
-inline GLenum glCheckError_(const char *file, int line) {
- GLenum errorCode;
- while ((errorCode = glGetError()) != GL_NO_ERROR) {
- std::string error;
- switch (errorCode) {
- case GL_INVALID_ENUM:
- error = "INVALID_ENUM";
- break;
- case GL_INVALID_VALUE:
- error = "INVALID_VALUE";
- break;
- case GL_INVALID_OPERATION:
- error = "INVALID_OPERATION";
- break;
- case GL_STACK_OVERFLOW:
- error = "STACK_OVERFLOW";
- break;
- case GL_STACK_UNDERFLOW:
- error = "STACK_UNDERFLOW";
- break;
- case GL_OUT_OF_MEMORY:
- error = "OUT_OF_MEMORY";
- break;
- case GL_INVALID_FRAMEBUFFER_OPERATION:
- error = "INVALID_FRAMEBUFFER_OPERATION";
- break;
- }
- static int t = 0;
- t++;
- if (t>10)
- LOG(FATAL);
- LOG(ERROR) << "OpenGL error: " << error << " at " << file << ":" << line;
- }
- return errorCode;
-}
+GLenum glCheckError_(const char *file, int line);
+#define glCheckError() glCheckError_(__FILE__, __LINE__)
+
+
+
+class LoopExecutionTimeController {
+ using clock = std::chrono::steady_clock ;
+ using timePoint = std::chrono::time_point<clock>;
+ using duration = std::chrono::duration<double,std::milli>;
+ timePoint previousUpdate;
+ duration delayLength;
+ unsigned long long iterations=0;
+public:
+ LoopExecutionTimeController(duration delayLength);
+
+ ~LoopExecutionTimeController();
+
+ void SetDelayLength(duration length);
+
+ unsigned long long GetIterations();
+
+ void Update();
+
+ double GetDeltaMs();
-#define glCheckError() glCheckError_(__FILE__, __LINE__) \ No newline at end of file
+ duration GetDelta();
+};
diff --git a/src/World.cpp b/src/World.cpp
new file mode 100644
index 0000000..487f4ba
--- /dev/null
+++ b/src/World.cpp
@@ -0,0 +1,129 @@
+#include "World.hpp"
+
+void World::ParseChunkData(std::shared_ptr<PacketChunkData> packet) {
+ StreamBuffer chunkData(packet->Data.data(), packet->Data.size());
+ std::bitset<16> bitmask(packet->PrimaryBitMask);
+ for (int i = 0; i < 16; i++) {
+ if (bitmask[i]) {
+ Vector chunkPosition = Vector(packet->ChunkX, i, packet->ChunkZ);
+ Section section = ParseSection(&chunkData, chunkPosition);
+ section.Parse();
+ sectionMutexes[chunkPosition].lock();
+ auto it = sections.find(chunkPosition);
+ if (it == sections.end()) {
+ sections.insert(std::make_pair(chunkPosition, section));
+ } else {
+ using std::swap;
+ swap(it->second, section);
+ }
+ sectionMutexes[chunkPosition].unlock();
+ }
+ }
+}
+
+Section World::ParseSection(StreamInput *data, Vector position) {
+ unsigned char bitsPerBlock = data->ReadUByte();
+ int paletteLength = data->ReadVarInt();
+ std::vector<unsigned short> palette;
+ for (int i = 0; i < paletteLength; i++) {
+ palette.push_back(data->ReadVarInt());
+ }
+ int dataArrayLength = data->ReadVarInt();
+ auto dataArray = data->ReadByteArray(dataArrayLength * 8);
+ auto blockLight = data->ReadByteArray(4096 / 2);
+ std::vector<unsigned char> skyLight;
+ if (dimension == 0)
+ skyLight = data->ReadByteArray(4096 / 2);
+ return Section(position, dataArray.data(), dataArray.size(), blockLight.data(),
+ (skyLight.size() > 0 ? skyLight.data() : nullptr), bitsPerBlock, palette);
+}
+
+World::~World() {
+}
+
+World::World() {
+
+}
+
+bool World::isPlayerCollides(double X, double Y, double Z) {
+ Vector PlayerChunk(floor(X / 16.0), floor(Y / 16.0), floor(Z / 16.0));
+ std::vector<Vector> closestSectionsCoordinates = {
+ Vector(PlayerChunk.GetX(), PlayerChunk.GetY(), PlayerChunk.GetZ()),
+ Vector(PlayerChunk.GetX() + 1, PlayerChunk.GetY(), PlayerChunk.GetZ()),
+ Vector(PlayerChunk.GetX() - 1, PlayerChunk.GetY(), PlayerChunk.GetZ()),
+ Vector(PlayerChunk.GetX(), PlayerChunk.GetY() + 1, PlayerChunk.GetZ()),
+ Vector(PlayerChunk.GetX(), PlayerChunk.GetY() - 1, PlayerChunk.GetZ()),
+ Vector(PlayerChunk.GetX(), PlayerChunk.GetY(), PlayerChunk.GetZ() + 1),
+ Vector(PlayerChunk.GetX(), PlayerChunk.GetY(), PlayerChunk.GetZ() - 1),
+ };
+ std::vector<std::map<Vector, Section>::iterator> closestSections;
+ for (auto &coord:closestSectionsCoordinates) {
+ auto it = sections.find(coord);
+ if (it != sections.end())
+ closestSections.push_back(it);
+ }
+ if (closestSections.empty())
+ return false;
+
+ for (auto &it:closestSections) {
+
+ const double PlayerWidth = 0.6;
+ const double PlayerHeight = 1.82;
+ const double PlayerLength = 0.6;
+
+ AABB playerColl;
+ playerColl.x = X - PlayerWidth / 2.0;
+ playerColl.w = PlayerWidth;
+ playerColl.y = Y;
+ playerColl.h = PlayerHeight;
+ playerColl.z = Z - PlayerLength / 2.0;
+ playerColl.l = PlayerLength;
+
+ for (int x = 0; x < 16; x++) {
+ for (int y = 0; y < 16; y++) {
+ for (int z = 0; z < 16; z++) {
+ Block block = it->second.GetBlock(Vector(x, y, z));
+ if (block.id == 0 || block.id == 31)
+ continue;
+ AABB blockColl{(x + it->first.GetX() * 16.0),
+ (y + it->first.GetY() * 16.0),
+ (z + it->first.GetZ() * 16.0), 1, 1, 1};
+ if (TestCollision(playerColl, blockColl))
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+Block &World::GetBlock(Vector pos) {
+ Vector sectionPos (floor(pos.GetX() / 16.0f),floor(pos.GetY() / 16.0f),floor(pos.GetZ()/16.0f));
+ Vector inSectionPos = pos - (sectionPos * 16);
+ if (sections.find(sectionPos)==sections.end()){
+ static Block block(0,0);
+ return block;
+ }
+ sectionMutexes[sectionPos].lock();
+ Block& block = sections.find(sectionPos)->second.GetBlock(inSectionPos);
+ sectionMutexes[sectionPos].unlock();
+ return block;
+}
+
+std::vector<Vector> World::GetSectionsList() {
+ std::vector<Vector> sectionsList;
+ for (auto& it:sections) {
+ sectionsList.push_back(it.first);
+ }
+ return sectionsList;
+}
+
+Section &World::GetSection(Vector sectionPos) {
+ sectionMutexes[sectionPos].lock();
+ sectionMutexes[sectionPos].unlock();
+ return sections.find(sectionPos)->second;
+}
+
+glm::vec3 World::Raycast(glm::vec3 position, glm::vec3 direction, float maxLength, float minPrecision) {
+ return glm::vec3(position * direction / maxLength * minPrecision);
+}
diff --git a/src/World.hpp b/src/World.hpp
new file mode 100644
index 0000000..52493a7
--- /dev/null
+++ b/src/World.hpp
@@ -0,0 +1,39 @@
+#pragma once
+
+#include <map>
+#include <bitset>
+
+#include <easylogging++.h>
+
+#include "Block.hpp"
+#include "Section.hpp"
+#include "Packet.hpp"
+#include "Collision.hpp"
+#include "Vector.hpp"
+
+class World {
+ std::map<Vector, Section> sections;
+ std::map<Vector, std::mutex> sectionMutexes;
+ int dimension = 0;
+
+ Section ParseSection(StreamInput *data, Vector position);
+
+ World(const World &other);
+ World &operator=(const World &other);
+public:
+ World();
+
+ ~World();
+
+ void ParseChunkData(std::shared_ptr<PacketChunkData> packet);
+
+ bool isPlayerCollides(double X, double Y, double Z);
+
+ Block &GetBlock(Vector pos);
+
+ std::vector<Vector> GetSectionsList();
+
+ Section &GetSection(Vector sectionPos);
+
+ glm::vec3 Raycast(glm::vec3 position, glm::vec3 direction, float maxLength = 1000.0f, float minPrecision = 0.01f);
+}; \ No newline at end of file
diff --git a/src/core/AssetManager.cpp b/src/core/AssetManager.cpp
index 14ea677..d263c4a 100644
--- a/src/core/AssetManager.cpp
+++ b/src/core/AssetManager.cpp
@@ -1,4 +1,4 @@
-#include <core/AssetManager.hpp>
+#include <AssetManager.hpp>
namespace fs = std::experimental::filesystem;
diff --git a/src/core/Core.cpp b/src/core/Core.cpp
index e98d204..dcfa890 100644
--- a/src/core/Core.cpp
+++ b/src/core/Core.cpp
@@ -1,6 +1,5 @@
#include "Core.hpp"
-//Core::Core():toRenderMutex("toRender"),availableChunksMutex("availableChunks") {
Core::Core() {
LOG(INFO) << "Core initializing...";
InitSfml(900, 450, "AltCraft");
@@ -9,8 +8,8 @@ Core::Core() {
glCheckError();
client = new NetworkClient("127.0.0.1", 25565, "HelloOne", isRunning);
gameState = new GameState(client, isRunning);
- gameStateLoopThread = std::thread(&Core::UpdateGameState, this);
- sectionUpdateLoopThread = std::thread(&Core::UpdateSections, this);
+ std::thread loop = std::thread(&Core::UpdateGameState, this);
+ std::swap(loop, gameStateLoopThread);
assetManager = new AssetManager;
PrepareToRendering();
LOG(INFO) << "Core is initialized";
@@ -20,7 +19,6 @@ Core::Core() {
Core::~Core() {
LOG(INFO) << "Core stopping...";
gameStateLoopThread.join();
- sectionUpdateLoopThread.join();
delete shader;
delete gameState;
delete client;
@@ -56,7 +54,6 @@ void Core::Exec() {
toWindow << "FPS: " << (1.0f / deltaTime) << " ";
toWindow << " (" << deltaTime * 1000 << "ms); ";
toWindow << "Tickrate: " << tickRate << " (" << (1.0 / tickRate * 1000) << "ms); ";
- toWindow << "Sections: " << sectionRate << " (" << (1.0 / sectionRate * 1000) << "ms); ";
window->setTitle(toWindow.str());
HandleEvents();
@@ -64,17 +61,6 @@ void Core::Exec() {
glCheckError();
RenderFrame();
- if (isRendersShouldBeCreated) {
- availableChunksMutex.lock();
- for (auto &it:renders) {
- auto pair = std::make_pair(it, RenderSection(&gameState->world, it));
- availableChunks.insert(pair);
- }
- renders.clear();
- availableChunksMutex.unlock();
- isRendersShouldBeCreated = false;
- waitRendersCreated.notify_all();
- }
}
}
@@ -112,7 +98,7 @@ void Core::InitSfml(unsigned int WinWidth, unsigned int WinHeight, std::string W
contextSetting.depthBits = 24;
window = new sf::Window(sf::VideoMode(WinWidth, WinHeight), WinTitle, sf::Style::Default, contextSetting);
glCheckError();
- //window->setVerticalSyncEnabled(true);
+ window->setVerticalSyncEnabled(true);
//window->setPosition(sf::Vector2i(sf::VideoMode::getDesktopMode().width / 2, sf::VideoMode::getDesktopMode().height / 2));
window->setPosition(sf::Vector2i(sf::VideoMode::getDesktopMode().width / 2 - window->getSize().x / 2,
sf::VideoMode::getDesktopMode().height / 2 - window->getSize().y / 2));
@@ -180,6 +166,11 @@ void Core::HandleEvents() {
default:
break;
}
+ /*case sf::Event::MouseWheelScrolled:
+ if (!window->hasFocus())
+ break;
+ camera.ProcessMouseScroll(event.mouseWheelScroll.delta);
+ break;*/
default:
break;
}
@@ -220,16 +211,8 @@ void Core::RenderWorld() {
glCheckError();
- toRenderMutex.lock();
for (auto &render : toRender) {
- availableChunksMutex.lock();
- auto iterator = availableChunks.find(render);
- if (iterator == availableChunks.end()) {
- availableChunksMutex.unlock();
- continue;
- }
- /*Section &section = *iterator->second.GetSection();
- //availableChunksMutex.unlock();
+ Section &section = *availableChunks.find(render)->second.GetSection();
std::vector<Vector> sectionCorners = {
Vector(0, 0, 0),
@@ -242,8 +225,8 @@ void Core::RenderWorld() {
Vector(16, 16, 16),
};
bool isBreak = true;
- glm::mat4 vp = projection * view;
for (auto &it:sectionCorners) {
+ glm::mat4 vp = projection * view;
glm::vec3 point(section.GetPosition().GetX() * 16 + it.GetX(),
section.GetPosition().GetY() * 16 + it.GetY(),
section.GetPosition().GetZ() * 16 + it.GetZ());
@@ -258,14 +241,10 @@ void Core::RenderWorld() {
glm::vec3(section.GetPosition().GetX() * 16,
section.GetPosition().GetY() * 16,
section.GetPosition().GetZ() * 16)) > 30.0f) {
- availableChunksMutex.unlock();
continue;
}
- //availableChunksMutex.lock();*/
- iterator->second.Render(renderState);
- availableChunksMutex.unlock();
+ availableChunks.find(render)->second.Render(renderState);
}
- toRenderMutex.unlock();
glCheckError();
}
@@ -287,7 +266,6 @@ void Core::PrepareToRendering() {
}
void Core::UpdateChunksToRender() {
- return;
Vector playerChunk = Vector(floor(gameState->g_PlayerX / 16.0f), 0, floor(gameState->g_PlayerZ / 16.0f));
static Vector previousPlayerChunk = playerChunk;
static bool firstTime = true;
@@ -332,126 +310,4 @@ void Core::UpdateGameState() {
tickRate = 1 / delta.getElapsedTime().asSeconds();
}
LOG(INFO) << "GameState thread is stopped";
-}
-
-void Core::UpdateSections() {
- glm::vec3 playerPosition = gameState->Position();
- float playerPitch = gameState->Pitch();
- float playerYaw = gameState->Yaw();
- sf::Clock delta;
- std::vector<Vector> chunksToRender;
- auto currentSectionIterator = chunksToRender.begin();
- while (isRunning) {
- delta.restart();
- if (glm::length(glm::distance(gameState->Position(), playerPosition)) > 5.0f) {
- chunksToRender.clear();
- playerPosition = gameState->Position();
- Vector playerChunk = Vector(floor(playerPosition.x / 16.0f), 0, floor(playerPosition.z / 16.0f));
- for (auto &it:gameState->world.GetSectionsList()) {
- Vector chunkPosition = it;
- chunkPosition.SetY(0);
- Vector delta = chunkPosition - playerChunk;
- if (delta.GetMagnitude() > ChunkDistance) continue;
- chunksToRender.push_back(it);
- }
- std::sort(chunksToRender.begin(), chunksToRender.end(), [playerChunk](auto first, auto second) {
- glm::vec3 fDistance = first - playerChunk;
- glm::vec3 sDistance = second - playerChunk;
- return glm::length(fDistance) < glm::length(sDistance);
- });
- for (auto &it:chunksToRender) {
- availableChunksMutex.lock();
- if (availableChunks.find(it) == availableChunks.end()) {
- availableChunksMutex.unlock();
- renders.push_back(it);
- } else
- availableChunksMutex.unlock();
- }
- if (!renders.empty()) {
- std::mutex mutex;
- std::unique_lock<std::mutex> lock(mutex);
- isRendersShouldBeCreated = true;
- while (isRendersShouldBeCreated)
- waitRendersCreated.wait(lock);
- }
- currentSectionIterator = chunksToRender.begin();
- toRenderMutex.lock();
- toRender = chunksToRender;
- toRenderMutex.unlock();
- }
- if (currentSectionIterator != chunksToRender.end()) {
- availableChunksMutex.lock();
- auto iterator = availableChunks.find(*currentSectionIterator);
- if (iterator != availableChunks.end() && iterator->second.IsNeedUpdate()) {
- RenderSection rs = std::move(iterator->second);
- availableChunks.erase(iterator);
- auto pair = std::make_pair(*currentSectionIterator, rs);
- availableChunksMutex.unlock();
-
- pair.second.UpdateState(assetManager->GetTextureAtlasIndexes());
-
- availableChunksMutex.lock();
- availableChunks.insert(pair);
- }
- availableChunksMutex.unlock();
- currentSectionIterator = std::next(currentSectionIterator);
- }
- if (gameState->Pitch() != playerPitch || gameState->Yaw() != playerYaw) {
- playerPitch = gameState->Pitch();
- playerYaw = gameState->Yaw();
- const std::vector<Vector> sectionCorners = {
- Vector(0, 0, 0),
- Vector(0, 0, 16),
- Vector(0, 16, 0),
- Vector(0, 16, 16),
- Vector(16, 0, 0),
- Vector(16, 0, 16),
- Vector(16, 16, 0),
- Vector(16, 16, 16),
- };
- const glm::mat4 projection = glm::perspective(45.0f, (float)width() / (float)height(), 0.1f, 10000000.0f);
- const glm::mat4 view = gameState->GetViewMatrix();
- const glm::mat4 vp = projection * view;
- for (auto& section: toRender) {
- bool isCulled = true;
- for (auto &it : sectionCorners) {
- glm::vec3 point(section.GetX() * 16 + it.GetX(),
- section.GetY() * 16 + it.GetY(),
- section.GetZ() * 16 + it.GetZ());
- glm::vec4 p = vp * glm::vec4(point, 1);
- glm::vec3 res = glm::vec3(p) / p.w;
- if (res.x < 1 && res.x > -1 && res.y < 1 && res.y > -1 && res.z > 0) {
- isCulled = false;
- break;
- }
- }
- bool isVisible = !isCulled || glm::length(gameState->Position() -
- glm::vec3(section.GetX() * 16, section.GetY() * 16, section.GetZ() * 16)) < 30.0f;
- availableChunksMutex.lock();
- auto iter = availableChunks.find(section);
- if (iter != availableChunks.end())
- iter->second.SetEnabled(isVisible);
- availableChunksMutex.unlock();
-
- }
- }
- using namespace std::chrono_literals;
- std::this_thread::sleep_for(5ms);
- sectionRate = delta.getElapsedTime().asSeconds();
- delta.restart();
- }
-}
-
-MyMutex::MyMutex(std::string name) {
- str = name;
-}
-
-void MyMutex::lock() {
- LOG(WARNING) << "Thread " << std::this_thread::get_id() << " locked mutex " << str;
- mtx.lock();
-}
-
-void MyMutex::unlock() {
- LOG(WARNING) << "Thread " << std::this_thread::get_id() << " unlocked mutex " << str;
- mtx.unlock();
} \ No newline at end of file
diff --git a/src/graphics/RenderSection.cpp b/src/graphics/RenderSection.cpp
index ae072d6..b07759a 100644
--- a/src/graphics/RenderSection.cpp
+++ b/src/graphics/RenderSection.cpp
@@ -1,5 +1,4 @@
#include <graphics/RenderSection.hpp>
-#include <thread>
const GLfloat vertices[] = {
0, 0, 0,
@@ -43,6 +42,7 @@ std::map<GLuint, int> RenderSection::refCounterVao;
RenderSection::RenderSection(World *world, Vector position) : sectionPosition(position), world(world) {
+
if (VboVertices == magicUniqueConstant) {
glGenBuffers(1, &VboVertices);
glGenBuffers(1, &VboUvs);
@@ -138,7 +138,6 @@ RenderSection::~RenderSection() {
refCounterVao[Vao]--;
if (refCounterVbo[VboTextures] <= 0)
glDeleteBuffers(1, &VboTextures);
-
if (refCounterVbo[VboModels] <= 0)
glDeleteBuffers(1, &VboTextures);
if (refCounterVbo[VboColors] <= 0)
@@ -150,9 +149,9 @@ RenderSection::~RenderSection() {
void RenderSection::UpdateState(const std::map<BlockTextureId, glm::vec4> &textureAtlas) {
Section &section = world->GetSection(sectionPosition);
- models.clear();
- textures.clear();
- colors.clear();
+ std::vector<glm::mat4> models;
+ std::vector<glm::vec4> textures;
+ std::vector<glm::vec3> colors;
for (int y = 0; y < 16; y++) {
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) {
@@ -296,27 +295,24 @@ void RenderSection::UpdateState(const std::map<BlockTextureId, glm::vec4> &textu
}
}
}
- numOfFaces = textures.size();
- hash = section.GetHash();
-}
-void RenderSection::Render(RenderState &state) {
- if (!isEnabled) return;
- if (!models.empty()) {
- glBindBuffer(GL_ARRAY_BUFFER, VboTextures);
- glBufferData(GL_ARRAY_BUFFER, textures.size() * sizeof(glm::vec4), textures.data(), GL_DYNAMIC_DRAW);
- textures.clear();
+ glBindBuffer(GL_ARRAY_BUFFER, VboTextures);
+ glBufferData(GL_ARRAY_BUFFER, textures.size() * sizeof(glm::vec4), textures.data(), GL_DYNAMIC_DRAW);
- glBindBuffer(GL_ARRAY_BUFFER, VboModels);
- glBufferData(GL_ARRAY_BUFFER, models.size() * sizeof(glm::mat4), models.data(), GL_DYNAMIC_DRAW);
- models.clear();
+ glBindBuffer(GL_ARRAY_BUFFER, VboModels);
+ glBufferData(GL_ARRAY_BUFFER, models.size() * sizeof(glm::mat4), models.data(), GL_DYNAMIC_DRAW);
- glBindBuffer(GL_ARRAY_BUFFER, VboColors);
- glBufferData(GL_ARRAY_BUFFER, colors.size() * sizeof(glm::vec3), colors.data(), GL_DYNAMIC_DRAW);
- colors.clear();
+ glBindBuffer(GL_ARRAY_BUFFER, VboColors);
+ glBufferData(GL_ARRAY_BUFFER, colors.size() * sizeof(glm::vec3), colors.data(), GL_DYNAMIC_DRAW);
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- }
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ glCheckError();
+
+ numOfFaces = textures.size();
+}
+
+void RenderSection::Render(RenderState &state) {
state.SetActiveVao(Vao);
glDrawArraysInstanced(GL_TRIANGLES, 0, 6, numOfFaces);
glCheckError();
@@ -334,23 +330,9 @@ RenderSection::RenderSection(const RenderSection &other) {
this->sectionPosition = other.sectionPosition;
this->Vao = other.Vao;
this->numOfFaces = other.numOfFaces;
- this->models = other.models;
- this->textures = other.textures;
- this->colors = other.colors;
- this->hash = other.hash;
refCounterVbo[VboTextures]++;
refCounterVbo[VboModels]++;
refCounterVbo[VboColors]++;
refCounterVao[Vao]++;
}
-
-void RenderSection::SetEnabled(bool isEnabled) {
- this->isEnabled = isEnabled;
-}
-
-bool RenderSection::IsNeedUpdate() {
- size_t currentHash = world->GetSection(sectionPosition).GetHash();
- bool isNeedUpdate = currentHash != hash;
- return isNeedUpdate;
-} \ No newline at end of file
diff --git a/src/main.cpp b/src/main.cpp
index 85fe70d..7bc0fb6 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,5 +1,6 @@
-#include "core/Core.hpp"
-#include <core/Event.hpp>
+#include "Core.hpp"
+#include "Event.hpp"
+#include "Utility.hpp"
const char *getTimeSinceProgramStart(void) {
static auto initialTime = std::chrono::steady_clock().now();
@@ -29,7 +30,7 @@ int main() {
LOG(WARNING)<<"Sizeof EventData is "<<sizeof(EventData);
Core core;
- core.Exec();
+ core.ExecuteRenderLoop();
return 0;
} \ No newline at end of file
diff --git a/src/network/Network.cpp b/src/network/Network.cpp
index 798756d..91cb481 100644
--- a/src/network/Network.cpp
+++ b/src/network/Network.cpp
@@ -1,12 +1,8 @@
#include <network/Network.hpp>
Network::Network(std::string address, unsigned short port) {
- try {
- socket = new Socket(address, port);
- stream = new StreamSocket(socket);
- } catch (std::exception &e) {
- LOG(FATAL)<<e.what();
- }
+ socket = new Socket(address, port);
+ stream = new StreamSocket(socket);
}
Network::~Network() {
diff --git a/src/network/Stream.cpp b/src/network/Stream.cpp
index 2545b48..447b13f 100644
--- a/src/network/Stream.cpp
+++ b/src/network/Stream.cpp
@@ -30,10 +30,11 @@ short StreamInput::ReadShort() {
}
unsigned short StreamInput::ReadUShort() {
- unsigned short value;
- ReadData((unsigned char *) &value, 2);
- endswap(value);
- return value;
+ unsigned char buff[2];
+ ReadData(buff, 2);
+ unsigned short val = *(reinterpret_cast<unsigned short *>(buff));
+ endswap(val);
+ return val;
}
int StreamInput::ReadInt() {
diff --git a/src/world/GameState.cpp b/src/world/GameState.cpp
index d3a6bd3..79e2f1b 100644
--- a/src/world/GameState.cpp
+++ b/src/world/GameState.cpp
@@ -1,4 +1,4 @@
-#include <world/GameState.hpp>
+#include <GameState.hpp>
GameState::GameState(NetworkClient *Net, bool &quit) : nc(Net), isRunning(quit) {
Front = glm::vec3(0.0f, 0.0f, -1.0f);
diff --git a/src/world/Section.cpp b/src/world/Section.cpp
index ff2a4fb..d97d163 100644
--- a/src/world/Section.cpp
+++ b/src/world/Section.cpp
@@ -36,10 +36,8 @@ Block &Section::GetBlock(Vector pos) {
return m_blocks[pos.GetY() * 256 + pos.GetZ() * 16 + pos.GetX()];
}
-double totalParsingTime = 0;
-
void Section::Parse() {
- if (!m_blocks.empty())
+ if (m_dataBlocks == nullptr)
return;
long long *longArray = reinterpret_cast<long long *>(m_dataBlocks);
@@ -47,28 +45,23 @@ void Section::Parse() {
endswap(&longArray[i]);
std::vector<unsigned short> blocks;
blocks.reserve(4096);
- {
- auto begin = std::chrono::steady_clock::now();
- int bitPos = 0;
- unsigned short t = 0;
- for (size_t i = 0; i < m_dataBlocksLen; i++) {
- for (int j = 0; j < 8; j++) {
- t |= (m_dataBlocks[i] & 0x01) ? 0x80 : 0x00;
- t >>= 1;
- m_dataBlocks[i] >>= 1;
- bitPos++;
- if (bitPos >= m_bitsPerBlock) {
- bitPos = 0;
- t >>= m_bitsPerBlock - 1;
- blocks.push_back(t);
- t = 0;
- }
+ int bitPos = 0;
+ unsigned short t = 0;
+ for (size_t i = 0; i < m_dataBlocksLen; i++) {
+ for (int j = 0; j < 8; j++) {
+ t |= (m_dataBlocks[i] & 0x01) ? 0x80 : 0x00;
+ t >>= 1;
+ m_dataBlocks[i] >>= 1;
+ bitPos++;
+ if (bitPos >= m_bitsPerBlock) {
+ bitPos = 0;
+ t >>= m_bitsPerBlock - 1;
+ blocks.push_back(t);
+ t = 0;
}
}
- auto end = std::chrono::steady_clock::now();
- std::chrono::duration<double, std::milli> time = end - begin;
- totalParsingTime += time.count();
}
+
std::vector<byte> light;
light.reserve(4096);
for (int i = 0; i < 2048; i++) {
@@ -83,6 +76,9 @@ void Section::Parse() {
Block block(blockId >> 4, blockId & 0xF);
m_blocks.push_back(block);
}
+ if ((light.size() + blocks.size()) / 2 != 4096) {
+ throw 118;
+ }
delete[] m_dataBlocks;
m_dataBlocksLen = 0;
m_dataBlocks = nullptr;
@@ -135,13 +131,3 @@ Section::Section(const Section &other) {
Vector Section::GetPosition() {
return worldPosition;
}
-
-size_t Section::GetHash() {
- if (m_blocks.empty()) return 0;
-
- unsigned char *from = reinterpret_cast<unsigned char *>(m_blocks.data());
- size_t length = m_blocks.size() * sizeof(Block);
-
- std::string str(from, from + length);
- return std::hash<std::string>{}(str);
-} \ No newline at end of file