diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/AssetManager.cpp | 185 | ||||
-rw-r--r-- | src/AssetManager.hpp (renamed from src/core/AssetManager.hpp) | 6 | ||||
-rw-r--r-- | src/Block.cpp | 17 | ||||
-rw-r--r-- | src/Block.hpp (renamed from src/world/Block.hpp) | 0 | ||||
-rw-r--r-- | src/Collision.cpp | 28 | ||||
-rw-r--r-- | src/Collision.hpp (renamed from src/world/Collision.hpp) | 0 | ||||
-rw-r--r-- | src/Core.cpp | 59 | ||||
-rw-r--r-- | src/Core.hpp | 23 | ||||
-rw-r--r-- | src/Event.cpp (renamed from src/core/Event.cpp) | 112 | ||||
-rw-r--r-- | src/Event.hpp (renamed from src/core/Event.hpp) | 76 | ||||
-rw-r--r-- | src/GameState.cpp | 383 | ||||
-rw-r--r-- | src/GameState.hpp (renamed from src/world/GameState.hpp) | 6 | ||||
-rw-r--r-- | src/Nbt.hpp | 516 | ||||
-rw-r--r-- | src/Network.cpp | 224 | ||||
-rw-r--r-- | src/Network.hpp (renamed from src/network/Network.hpp) | 0 | ||||
-rw-r--r-- | src/NetworkClient.cpp | 93 | ||||
-rw-r--r-- | src/NetworkClient.hpp (renamed from src/network/NetworkClient.hpp) | 2 | ||||
-rw-r--r-- | src/Packet.hpp (renamed from src/network/Packet.hpp) | 2 | ||||
-rw-r--r-- | src/Render.cpp | 137 | ||||
-rw-r--r-- | src/Render.hpp | 32 | ||||
-rw-r--r-- | src/Renderer.cpp | 15 | ||||
-rw-r--r-- | src/Renderer.hpp | 18 | ||||
-rw-r--r-- | src/RendererSection.cpp | 348 | ||||
-rw-r--r-- | src/RendererSection.hpp | 49 | ||||
-rw-r--r-- | src/RendererWorld.cpp | 1 | ||||
-rw-r--r-- | src/RendererWorld.hpp | 7 | ||||
-rw-r--r-- | src/Section.cpp | 147 | ||||
-rw-r--r-- | src/Section.hpp (renamed from src/world/Section.hpp) | 6 | ||||
-rw-r--r-- | src/Shader.cpp | 115 | ||||
-rw-r--r-- | src/Shader.hpp (renamed from src/graphics/Shader.hpp) | 0 | ||||
-rw-r--r-- | src/Socket.cpp | 29 | ||||
-rw-r--r-- | src/Socket.hpp (renamed from src/network/Socket.hpp) | 0 | ||||
-rw-r--r-- | src/Stream.cpp | 348 | ||||
-rw-r--r-- | src/Stream.hpp (renamed from src/network/Stream.hpp) | 6 | ||||
-rw-r--r-- | src/Texture.cpp | 37 | ||||
-rw-r--r-- | src/Texture.hpp (renamed from src/graphics/Texture.hpp) | 0 | ||||
-rw-r--r-- | src/Utility.cpp | 73 | ||||
-rw-r--r-- | src/Utility.hpp | 65 | ||||
-rw-r--r-- | src/World.cpp | 129 | ||||
-rw-r--r-- | src/World.hpp (renamed from src/world/World.hpp) | 9 | ||||
-rw-r--r-- | src/core/AssetManager.cpp | 2 | ||||
-rw-r--r-- | src/core/Core.cpp | 166 | ||||
-rw-r--r-- | src/core/Core.hpp | 95 | ||||
-rw-r--r-- | src/graphics/Gui.hpp | 8 | ||||
-rw-r--r-- | src/graphics/RenderSection.cpp | 54 | ||||
-rw-r--r-- | src/graphics/RenderSection.hpp | 52 | ||||
-rw-r--r-- | src/graphics/Widget.hpp | 8 | ||||
-rw-r--r-- | src/main.cpp | 7 | ||||
-rw-r--r-- | src/network/Network.cpp | 8 | ||||
-rw-r--r-- | src/network/Stream.cpp | 9 | ||||
-rw-r--r-- | src/world/GameState.cpp | 2 | ||||
-rw-r--r-- | src/world/Section.cpp | 50 |
52 files changed, 2722 insertions, 1042 deletions
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/core/AssetManager.hpp b/src/AssetManager.hpp index 26c7eca..ba5546b 100644 --- a/src/core/AssetManager.hpp +++ b/src/AssetManager.hpp @@ -7,8 +7,8 @@ #include <glm/vec4.hpp> #include <nlohmann/json.hpp> -#include <world/Block.hpp> -#include <graphics/Texture.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) {} @@ -72,4 +72,6 @@ public: 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/world/Block.hpp b/src/Block.hpp index 2f823fe..2f823fe 100644 --- a/src/world/Block.hpp +++ b/src/Block.hpp 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/world/Collision.hpp b/src/Collision.hpp index b88fbf7..b88fbf7 100644 --- a/src/world/Collision.hpp +++ b/src/Collision.hpp 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/core/Event.cpp b/src/Event.cpp index 10b2eaa..ff16178 100644 --- a/src/core/Event.cpp +++ b/src/Event.cpp @@ -1,4 +1,4 @@ -#include <core/Event.hpp> +#include "Event.hpp" #include <easylogging++.h> std::queue <Event> EventAgregator::eventsToHandle; @@ -7,6 +7,72 @@ 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(); @@ -20,7 +86,7 @@ void EventAgregator::EventHandlingLoop() { auto event = queue.front(); listenersMutex.lock(); for (auto& listener : listeners) { - LOG(INFO)<<"Listener notified about event"; + LOG(ERROR)<<"Listener notified about event"; listener->PushEvent(event); } listenersMutex.unlock(); @@ -32,45 +98,3 @@ void EventAgregator::EventHandlingLoop() { queueMutex.unlock(); } } - -void EventAgregator::RegisterListener(EventListener &listener) { - listenersMutex.lock(); - LOG(INFO)<<"Registered handler "<<&listener; - listeners.push_back(&listener); - listenersMutex.unlock(); -} - -void EventAgregator::UnregisterListener(EventListener &listener) { - listenersMutex.lock(); - LOG(INFO)<<"Unregistered handler "<<&listener; - listeners.erase(std::find(listeners.begin(), listeners.end(), &listener)); - listenersMutex.unlock(); -} - - - -EventListener::EventListener() { - EventAgregator::RegisterListener(*this); -} - -EventListener::~EventListener() { - EventAgregator::UnregisterListener(*this); -} - -void EventListener::PushEvent(Event event) { - eventsMutex.lock(); - LOG(INFO)<<"Pushed event to queue"; - events.push(event); - eventsMutex.unlock(); -} - -/*void EventListener::RegisterHandler(EventType type, std::function<void(void*)> handler) { - handlers[type] = handler; -}*/ - -bool EventListener::IsEventsQueueIsNotEmpty() { - eventsMutex.lock(); - bool value = !events.empty(); - eventsMutex.unlock(); - return value; -}
\ No newline at end of file diff --git a/src/core/Event.hpp b/src/Event.hpp index cfa990a..2d830a4 100644 --- a/src/core/Event.hpp +++ b/src/Event.hpp @@ -9,11 +9,18 @@ #include <variant> #include <functional> -#include <Vector.hpp> +#include "Vector.hpp" +#include "Packet.hpp" enum class EventType { Echo, ChunkChanged, + ConnectToServer, + ConnectionSuccessfull, + GlobalAppState, + Disconnect, + SendPacket, + ReceivePacket, }; struct EchoData { @@ -24,7 +31,42 @@ struct ChunkChangedData { Vector chunkPosition; }; -using EventData = std::variant<EchoData, ChunkChangedData>; +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; @@ -49,22 +91,9 @@ public: ~EventListener(); bool IsEventsQueueIsNotEmpty(); - void RegisterHandler(EventType type, HandlerFunc handler) { - handlers[type] = handler; - } - - void 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 RegisterHandler(EventType type, HandlerFunc handler); + + void HandleEvent(); }; class EventAgregator { @@ -83,14 +112,5 @@ class EventAgregator { static void UnregisterListener(EventListener &listener); public: - static void PushEvent(EventType type, EventData data) { - if (!isStarted) { - isStarted = true; - std::thread(&EventAgregator::EventHandlingLoop).detach(); - } - Event event; - event.type = type; - event.data = data; - eventsToHandle.push(event); - } + 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/world/GameState.hpp b/src/GameState.hpp index 6741882..2ac7bc1 100644 --- a/src/world/GameState.hpp +++ b/src/GameState.hpp @@ -4,9 +4,9 @@ #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> -#include <world/World.hpp> -#include <network/NetworkClient.hpp> -#include <Vector.hpp> +#include "World.hpp" +#include "NetworkClient.hpp" +#include "Vector.hpp" class GameState { NetworkClient *nc; diff --git a/src/Nbt.hpp b/src/Nbt.hpp deleted file mode 100644 index 03f5af0..0000000 --- a/src/Nbt.hpp +++ /dev/null @@ -1,516 +0,0 @@ -#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/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/Network.hpp b/src/Network.hpp index 1281289..1281289 100644 --- a/src/network/Network.hpp +++ b/src/Network.hpp 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/network/NetworkClient.hpp b/src/NetworkClient.hpp index 22b1b22..cf41f91 100644 --- a/src/network/NetworkClient.hpp +++ b/src/NetworkClient.hpp @@ -4,7 +4,7 @@ #include <queue> #include <mutex> -#include <network/Network.hpp> +#include "Network.hpp" class NetworkClient { Network network; diff --git a/src/network/Packet.hpp b/src/Packet.hpp index 685e3da..d615332 100644 --- a/src/network/Packet.hpp +++ b/src/Packet.hpp @@ -2,7 +2,7 @@ #include <easylogging++.h> -#include <network/Stream.hpp> +#include "Stream.hpp" enum PacketNameLoginSB { LoginStart = 0x00, 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 §ion = 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/world/Section.hpp b/src/Section.hpp index 2df0cfe..f40fdf9 100644 --- a/src/world/Section.hpp +++ b/src/Section.hpp @@ -7,9 +7,9 @@ #include <easylogging++.h> -#include <world/Block.hpp> -#include <Vector.hpp> -#include <Utility.hpp> +#include "Block.hpp" +#include "Vector.hpp" +#include "Utility.hpp" const int SECTION_WIDTH = 16; const int SECTION_LENGTH = 16; 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/graphics/Shader.hpp b/src/Shader.hpp index 17a434e..17a434e 100644 --- a/src/graphics/Shader.hpp +++ b/src/Shader.hpp 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/network/Socket.hpp b/src/Socket.hpp index 48bcad9..48bcad9 100644 --- a/src/network/Socket.hpp +++ b/src/Socket.hpp 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/network/Stream.hpp b/src/Stream.hpp index a24dfbe..b856d5f 100644 --- a/src/network/Stream.hpp +++ b/src/Stream.hpp @@ -9,9 +9,9 @@ #include <nlohmann/json.hpp> #include <easylogging++.h> -#include <network/Socket.hpp> -#include <Vector.hpp> -#include <Utility.hpp> +#include "Socket.hpp" +#include "Vector.hpp" +#include "Utility.hpp" class Stream { public: 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/graphics/Texture.hpp b/src/Texture.hpp index 5b2afcf..5b2afcf 100644 --- a/src/graphics/Texture.hpp +++ b/src/Texture.hpp 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/World.hpp b/src/World.hpp index 6b09f1f..52493a7 100644 --- a/src/world/World.hpp +++ b/src/World.hpp @@ -5,10 +5,11 @@ #include <easylogging++.h> -#include <world/Block.hpp> -#include <world/Section.hpp> -#include <network/Packet.hpp> -#include <world/Collision.hpp> +#include "Block.hpp" +#include "Section.hpp" +#include "Packet.hpp" +#include "Collision.hpp" +#include "Vector.hpp" class World { std::map<Vector, Section> sections; 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 §ion = *iterator->second.GetSection(); - //availableChunksMutex.unlock(); + Section §ion = *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/core/Core.hpp b/src/core/Core.hpp deleted file mode 100644 index 039b3a3..0000000 --- a/src/core/Core.hpp +++ /dev/null @@ -1,95 +0,0 @@ -#pragma once - -#include <iomanip> -#include <tuple> - -#include <easylogging++.h> -#include <GL/glew.h> -#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> - -struct MyMutex { - std::mutex mtx; - std::string str; - MyMutex(std::string name); - void lock(); - void unlock(); -}; - -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(); - - void UpdateSections(); - - std::thread gameStateLoopThread; - std::thread sectionUpdateLoopThread; - - Shader *shader; - //Cube verticies, Cube VAO, Cube UVs, TextureIndexes UboTextureIndexes, TextureData UboTextureIndexes, TextureData2 UboTextureIndexes, Blocks VBO, Models VBO, Line VAO, Lines VBO - bool isRendersShouldBeCreated=false; - std::condition_variable waitRendersCreated; - std::vector<Vector> renders; - std::mutex toRenderMutex; - std::vector<Vector> toRender; - std::map<Vector, RenderSection> availableChunks; - std::mutex availableChunksMutex; - - int ChunkDistance = 3; - - RenderState renderState; - - double tickRate = 0; - double sectionRate = 0; - -public: - Core(); - - ~Core(); - - void Exec(); -}; diff --git a/src/graphics/Gui.hpp b/src/graphics/Gui.hpp deleted file mode 100644 index e22a0a7..0000000 --- a/src/graphics/Gui.hpp +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -class Gui { - -public: - int WHY=0; - -}; 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 §ion = 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/graphics/RenderSection.hpp b/src/graphics/RenderSection.hpp deleted file mode 100644 index 5973909..0000000 --- a/src/graphics/RenderSection.hpp +++ /dev/null @@ -1,52 +0,0 @@ -#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 <core/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; - 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: - RenderSection(World *world, Vector position); - RenderSection(const RenderSection &other); - ~RenderSection(); - - void UpdateState(const std::map<BlockTextureId, glm::vec4> &textureAtlas); - void Render(RenderState &state); - - void SetEnabled(bool isEnabled); - - Section *GetSection(); - - bool IsNeedUpdate(); -};
\ No newline at end of file diff --git a/src/graphics/Widget.hpp b/src/graphics/Widget.hpp deleted file mode 100644 index c4d5dc1..0000000 --- a/src/graphics/Widget.hpp +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -class Widget { - unsigned int x,y,w,h; -public: - Widget(Widget *parent); - ~Widget(); -}; 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 |