diff options
30 files changed, 2018 insertions, 1666 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index a52494c..c019765 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,14 +12,13 @@ set(SRC_GAMESTATE src/gamestate/GameState.hpp src/gamestate/GameState.cpp) set(SRC_GRAPHICS src/graphics/Texture.cpp src/graphics/Shader.cpp src/graphics/Camera3D.cpp) set(SRC_GUI src/gui/Gui.cpp src/gui/Widget.cpp) set(SRC_NBT src/nbt/Nbt.hpp) -set(SRC_NETWORK src/network/Network.cpp src/network/NetworkClient.cpp) -set(SRC_PACKET src/packet/Field.cpp src/packet/FieldParser.cpp src/packet/Packet.cpp src/packet/PacketBuilder.cpp - src/packet/PacketParser.cpp) +set(SRC_NETWORK src/network/Network.cpp src/network/NetworkClient.cpp src/network/Socket.cpp src/network/Stream.cpp + src/network/Packet.hpp) set(SRC_UTILITY src/utility/Vector.hpp src/utility/utility.cpp) set(SRC_WORLD src/world/Block.cpp src/world/Section.cpp src/world/World.cpp) set(SOURCE_FILES src/main.cpp ${SRC_CORE} ${SRC_GAMESTATE} ${SRC_GRAPHICS} ${SRC_GUI} ${SRC_GRAPHICS} ${SRC_GUI} - ${SRC_NBT} ${SRC_NETWORK} ${SRC_PACKET} ${SRC_UTILITY} ${SRC_WORLD} src/graphics/Frustrum.cpp src/graphics/Frustrum.hpp) + ${SRC_NBT} ${SRC_NETWORK} ${SRC_UTILITY} ${SRC_WORLD} src/graphics/Frustrum.cpp src/graphics/Frustrum.hpp src/world/Collision.cpp src/world/Collision.hpp) add_executable(AltCraft ${SOURCE_FILES}) @@ -28,10 +27,10 @@ add_executable(AltCraft ${SOURCE_FILES}) ################ #Configure easlylogging++ -#set(LOGGER_DEFINITIONS "-DELPP_THREAD_SAFE") +set(LOGGER_DEFINITIONS "-DELPP_THREAD_SAFE") if (LINUX) set(LOGGER_DENITIONS "${LOGGER_DEFINITIPNS} -DELPP_FEATURE_CRASH_LOG -DELPP_STL_LOGGING") -endif() +endif () add_definitions(${LOGGER_DEFINITIONS}) #Set compiler's flags and setup platfrom-dependent libraries @@ -56,7 +55,7 @@ target_include_directories(AltCraft PUBLIC ./depedencies/include) target_link_libraries(AltCraft deps) #Setup SFML -set (SFML_ROOT "${CMAKE_SOURCE_DIR}/SFML-2.4.2") +set(SFML_ROOT "${CMAKE_SOURCE_DIR}/SFML-2.4.2") find_package(SFML 2.3 COMPONENTS system window graphics network REQUIRED) if (SFML_FOUND) target_link_libraries(AltCraft ${SFML_LIBRARIES}) @@ -88,5 +87,5 @@ endif () ################# add_custom_command(TARGET AltCraft PRE_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_directory - ${CMAKE_SOURCE_DIR}/cwd $<TARGET_FILE_DIR:AltCraft>)
\ No newline at end of file + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_SOURCE_DIR}/cwd $<TARGET_FILE_DIR:AltCraft>)
\ No newline at end of file diff --git a/src/core/Core.cpp b/src/core/Core.cpp index 9ad36ba..bb5bc12 100644 --- a/src/core/Core.cpp +++ b/src/core/Core.cpp @@ -140,8 +140,8 @@ Core::Core() { glCheckError(); InitGlew(); glCheckError(); - client = new NetworkClient("127.0.0.1", 25565, "HelloOne"); - gameState = new GameState(client); + client = new NetworkClient("127.0.0.1", 25565, "HelloOne", isRunning); + gameState = new GameState(client, isRunning); std::thread loop = std::thread(&Core::UpdateGameState, this); std::swap(loop, gameStateLoopThread); assetManager = new AssetManager; @@ -177,9 +177,14 @@ void Core::Exec() { } std::ostringstream toWindow; - glm::highp_vec3 camPos(camera.Position); + auto camPos = gameState->Position(); + auto velPos = glm::vec3(gameState->g_PlayerVelocityX, gameState->g_PlayerVelocityY, + gameState->g_PlayerVelocityZ); toWindow << std::setprecision(2) << std::fixed; - toWindow << "Pos: " << camPos.x << ", " << camPos.y << ", " << camPos.z << "; "; + toWindow << "Pos: " << camPos.x << ", " << camPos.y - 1.12 << ", " << camPos.z << "; "; + toWindow << "Health: " << gameState->g_PlayerHealth<<"; "; + //toWindow << "OG: " << gameState->g_OnGround << "; "; + toWindow << "Vel: " << velPos.x << ", " << velPos.y << ", " << velPos.z << "; "; toWindow << "FPS: " << (1.0f / deltaTime) << " "; toWindow << " (" << deltaTime * 1000 << "ms) "; window->setTitle(toWindow.str()); @@ -227,7 +232,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)); @@ -283,52 +288,47 @@ void Core::HandleEvents() { case sf::Keyboard::T: SetMouseCapture(!isMouseCaptured); break; - case sf::Keyboard::Z: - camera.MovementSpeed /= 2; - break; - case sf::Keyboard::X: - camera.MovementSpeed *= 2; - break; case sf::Keyboard::M: std::sort(toRender.begin(), toRender.end(), [this](const Vector &lhs, const Vector &rhs) { - return glm::length((glm::vec3) lhs - camera.Position) < - glm::length((glm::vec3) rhs - camera.Position); + return glm::length((glm::vec3) lhs - gameState->Position()) < + glm::length((glm::vec3) rhs - gameState->Position()); }); LOG(WARNING) << "Render list is optimized"; break; - case sf::Keyboard::K: - ChunkDistance++; - LOG(INFO)<<"Increased render distance: "<<ChunkDistance; - break; case sf::Keyboard::L: - ChunkDistance--; - LOG(INFO)<<"Decreased render distance: "<<ChunkDistance; + ChunkDistance++; + LOG(INFO) << "Increased render distance: " << ChunkDistance; break; - case sf::Keyboard::O: - UpdateChunksToRender(); - LOG(INFO)<<"Render list is updated"; + case sf::Keyboard::K: + if (ChunkDistance > 1) { + ChunkDistance--; + LOG(INFO) << "Decreased render distance: " << ChunkDistance; + } break; default: break; } - case sf::Event::MouseWheelScrolled: - if (!window->hasFocus()) - break; - camera.ProcessMouseScroll(event.mouseWheelScroll.delta); - break; + /*case sf::Event::MouseWheelScrolled: + if (!window->hasFocus()) + break; + camera.ProcessMouseScroll(event.mouseWheelScroll.delta); + break;*/ default: break; } } if (window->hasFocus()) { if (sf::Keyboard::isKeyPressed(sf::Keyboard::W)) - camera.ProcessKeyboard(Camera_Movement::FORWARD, deltaTime); + gameState->HandleMovement(GameState::FORWARD, deltaTime); if (sf::Keyboard::isKeyPressed(sf::Keyboard::S)) - camera.ProcessKeyboard(Camera_Movement::BACKWARD, deltaTime); + gameState->HandleMovement(GameState::BACKWARD, deltaTime); if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) - camera.ProcessKeyboard(Camera_Movement::LEFT, deltaTime); + gameState->HandleMovement(GameState::LEFT, deltaTime); if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) - camera.ProcessKeyboard(Camera_Movement::RIGHT, deltaTime); + gameState->HandleMovement(GameState::RIGHT, deltaTime); + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Space)) + gameState->HandleMovement(GameState::JUMP, deltaTime); + UpdateChunksToRender(); } } @@ -337,7 +337,9 @@ void Core::HandleMouseCapture() { 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; - camera.ProcessMouseMovement(mouseXDelta, mouseYDelta); + const float Sensetivity = 0.7f; + gameState->HandleRotation(mouseXDelta * Sensetivity, mouseYDelta * Sensetivity); + //camera.ProcessMouseMovement(mouseXDelta, mouseYDelta); } void Core::RenderGui(Gui &Target) { @@ -354,8 +356,8 @@ void Core::RenderWorld() { GLint blockLoc = glGetUniformLocation(shader->Program, "Block"); GLint stateLoc = glGetUniformLocation(shader->Program, "State"); GLint timeLoc = glGetUniformLocation(shader->Program, "time"); - glm::mat4 projection = glm::perspective(camera.Zoom, (float) width() / (float) height(), 0.1f, 10000000.0f); - glm::mat4 view = camera.GetViewMatrix(); + glm::mat4 projection = glm::perspective(45.0f, (float) width() / (float) height(), 0.1f, 10000000.0f); + glm::mat4 view = gameState->GetViewMatrix(); glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection)); glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view)); glUniform1f(timeLoc, absTime); @@ -365,7 +367,7 @@ void Core::RenderWorld() { glBindVertexArray(VAO); for (auto §ionPos : toRender) { - Section §ion = gameState->world.m_sections.find(sectionPos)->second; + Section §ion = gameState->world.sections.find(sectionPos)->second; std::vector<Vector> sectionCorners = { Vector(0, 0, 0), @@ -389,10 +391,9 @@ void Core::RenderWorld() { break; } } - if (isBreak && glm::length( - camera.Position - glm::vec3(sectionPos.GetX() * 16, sectionPos.GetY() * 16, sectionPos.GetZ() * 16)) > + if (isBreak && glm::length(gameState->Position() - + glm::vec3(sectionPos.GetX() * 16, sectionPos.GetY() * 16, sectionPos.GetZ() * 16)) > 30) { - //zLOG(ERROR)<<"CULL"; continue; } @@ -502,32 +503,6 @@ void Core::PrepareToWorldRendering() { TextureCoordinates tc = assetManager->GetTextureByBlock(BlockTextureId(id, state, side)); textureCoordinates.push_back(glm::vec4(tc.x, tc.y, tc.w, tc.h)); indexes.push_back(index); - /*LOG(ERROR) << "Encoded texture (" << id << " " << state << " " << side << ") as " << index << " (" - << std::bitset<19>(index) << ")" << " = " << tc.x << "," << tc.y << "," << tc.w << "," - << tc.h;*/ - /*LOG(FATAL)<<std::bitset<18>(index); - side = 0x7; - id = 0xFFF; - state = 0xF; - LOG(WARNING) << "side: " << side << " id: " << id << " state: " << state; - int i, si, st, index = 0; - si = side << 15; - i = id<<3; - st = state; - index = i | si | st; - LOG(FATAL) << std::bitset<18>(index) << " (" << index << "): " << std::bitset<18>(si) << " " - << std::bitset<18>(i) << " " << std::bitset<18>(st);*/ - /*if (rand() == 73) //Almost impossible(Almost==1/32768) - { - int index = 393233; - LOG(WARNING) << std::bitset<20>(index) << "(" << index << ")"; - int side = (index & 0xE0000) >> 16; - int id = (index & 0xFF0) >> 4; - int state = index & 0xF; - LOG(WARNING) << std::bitset<20>(side) << " " << std::bitset<20>(id) << " " - << std::bitset<20>(state); - LOG(FATAL) << side << " " << id << " " << state; - }*/ side++; } while (side < 6); } @@ -585,10 +560,17 @@ void Core::PrepareToWorldRendering() { } void Core::UpdateChunksToRender() { - camera.Position = glm::vec3(gameState->g_PlayerX, gameState->g_PlayerY, gameState->g_PlayerZ); - toRender.clear(); Vector playerChunk = Vector(floor(gameState->g_PlayerX / 16.0f), 0, floor(gameState->g_PlayerZ / 16.0f)); - for (auto &it:gameState->world.m_sections) { + static Vector previousPlayerChunk = playerChunk; + static bool firstTime = true; + static int previousRenderDistance = ChunkDistance; + if (previousPlayerChunk == playerChunk && !firstTime && ChunkDistance == previousRenderDistance) { + return; + } + previousPlayerChunk = playerChunk; + previousRenderDistance = ChunkDistance; + toRender.clear(); + for (auto &it:gameState->world.sections) { Vector chunkPosition = it.first; chunkPosition.SetY(0); Vector delta = chunkPosition - playerChunk; @@ -596,9 +578,10 @@ void Core::UpdateChunksToRender() { continue; toRender.push_back(it.first); } - LOG(INFO) << "Chunks to render: " << toRender.size(); + if (firstTime) + LOG(INFO) << "Chunks to render: " << toRender.size(); for (auto &it:toRender) { - Section §ion = gameState->world.m_sections.find(it)->second; + Section §ion = gameState->world.sections.find(it)->second; std::vector<glm::mat4> models; std::vector<glm::vec2> blocks; for (int y = 0; y < 16; y++) { @@ -635,26 +618,31 @@ void Core::UpdateChunksToRender() { toRenderModels[it] = models; } std::sort(toRender.begin(), toRender.end(), [this](const Vector &lhs, const Vector &rhs) { - return glm::length((glm::vec3) lhs - camera.Position) < glm::length((glm::vec3) rhs - camera.Position); + return glm::length((glm::vec3) lhs - gameState->Position()) < + glm::length((glm::vec3) rhs - gameState->Position()); }); - LOG(INFO) << "Chunks is prepared to rendering..."; + if (firstTime) + LOG(INFO) << "Chunks is prepared to rendering..."; + firstTime = false; } void Core::UpdateGameState() { el::Helpers::setThreadName("Game"); LOG(INFO) << "GameState thread is started"; + sf::Clock delta; while (isRunning) { - gameState->Update(); - if (toRender.size() > 0) - break; + float deltaTime = delta.getElapsedTime().asSeconds(); + delta.restart(); + gameState->Update(deltaTime); + } LOG(INFO) << "GameState thread is stopped"; } void Core::DrawLine(glm::vec3 from, glm::vec3 to, glm::vec3 color) { shader2->Use(); - glm::mat4 projection = glm::perspective(camera.Zoom, (float) width() / (float) height(), 0.1f, 10000000.0f); - glm::mat4 view = camera.GetViewMatrix(); + glm::mat4 projection = glm::perspective(45.0f, (float) width() / (float) height(), 0.1f, 10000000.0f); + glm::mat4 view = gameState->GetViewMatrix(); glUniformMatrix4fv(glGetUniformLocation(shader2->Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); glUniformMatrix4fv(glGetUniformLocation(shader2->Program, "view"), 1, GL_FALSE, glm::value_ptr(view)); @@ -686,7 +674,3 @@ void Core::DrawLine(glm::vec3 from, glm::vec3 to, glm::vec3 color) { glEnable(GL_DEPTH_TEST); } -void Core::UpdateOptimizedRender() { - - LOG(INFO) << "Render list is optimized"; -} diff --git a/src/core/Core.hpp b/src/core/Core.hpp index 97a51fd..cc355db 100644 --- a/src/core/Core.hpp +++ b/src/core/Core.hpp @@ -61,16 +61,13 @@ class Core { std::thread gameStateLoopThread; - Camera3D camera; Shader *shader,*shader2; //Cube verticies, Cube VAO, Cube UVs, TextureIndexes UBO, TextureData UBO, TextureData2 UBO, Blocks VBO, Models VBO, Line VAO, Lines VBO GLuint VBO, VAO, VBO2, UBO, UBO2, VBO3, VBO4, VAO2, VBO5; std::vector<Vector> toRender; std::vector<Vector> optimizedRender; - void UpdateOptimizedRender(); - - int ChunkDistance = 4; + int ChunkDistance = 2; std::map<Vector, std::vector<glm::mat4>> toRenderModels; std::map<Vector, std::vector<glm::vec2>> toRenderBlocks; diff --git a/src/gamestate/GameState.cpp b/src/gamestate/GameState.cpp index 5c5b9c4..3f3469d 100644 --- a/src/gamestate/GameState.cpp +++ b/src/gamestate/GameState.cpp @@ -1,131 +1,397 @@ #include "GameState.hpp" -GameState::GameState(NetworkClient *Net) : nc(Net) { - Packet *response = nc->GetPacket(); - if (response->GetId() != 0x02) { - LOG(ERROR) << "Response id is " << response->GetId(); - throw std::runtime_error("Response id is not 0x02"); - } - PacketParser::Parse(*response, Login); - g_PlayerUuid = response->GetField(0).GetString(); - g_PlayerName = response->GetField(1).GetString(); - delete response; - m_networkState = ConnectionState::Play; - LOG(INFO) << g_PlayerName << "'s UUID is " << g_PlayerUuid; +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() { - Packet *packetPtr; - - try { - packetPtr = nc->GetPacket(); - if (packetPtr == nullptr) - return; - PacketParser::Parse(*packetPtr, m_networkState); - } catch (std::exception &e) { - LOG(ERROR) << "Catched exception during packet pulling: " << e.what(); - return; - } - Packet &packet = *packetPtr; - nlohmann::json json; - - switch (packet.GetId()) { - case 0x23: - g_PlayerEid = packet.GetField(0).GetInt(); - g_Gamemode = (packet.GetField(1).GetUByte() & 0b11111011); - g_Dimension = packet.GetField(2).GetInt(); - g_Difficulty = packet.GetField(3).GetUByte(); - g_MaxPlayers = packet.GetField(4).GetUByte(); - g_LevelType = packet.GetField(5).GetString(); - g_ReducedDebugInfo = packet.GetField(6).GetBool(); - LOG(INFO) << "Gamemode is " << g_Gamemode << ", Difficulty is " << (int) g_Difficulty - << ", Level Type is " << g_LevelType; - break; - case 0x0D: - g_Difficulty = packet.GetField(0).GetUByte(); - LOG(INFO) << "Difficulty now is " << (int) g_Difficulty; - break; - case 0x43: - g_SpawnPosition = packet.GetField(0).GetPosition(); - LOG(INFO) << "Spawn position is " << g_SpawnPosition.GetX() << "," << g_SpawnPosition.GetY() << "," - << g_SpawnPosition.GetZ(); - break; - case 0x2B: - g_PlayerInvulnerable = (packet.GetField(0).GetByte() & 0x01) != 0; - g_PlayerFlying = (packet.GetField(0).GetByte() & 0x02) != 0; - g_PlayerAllowFlying = (packet.GetField(0).GetByte() & 0x04) != 0; - g_PlayerCreativeMode = (packet.GetField(0).GetByte() & 0x08) != 0; - g_PlayerFlyingSpeed = packet.GetField(1).GetFloat(); - g_PlayerFovModifier = packet.GetField(2).GetFloat(); - LOG(INFO) << "FOV modifier is " << g_PlayerFovModifier; - break; - case 0x2E: - if ((packet.GetField(5).GetByte() & 0x10) != 0) { - g_PlayerPitch += packet.GetField(4).GetFloat(); - } else { - g_PlayerPitch = packet.GetField(4).GetFloat(); - }; - - if ((packet.GetField(5).GetByte() & 0x08) != 0) { - g_PlayerYaw += packet.GetField(3).GetFloat(); - } else { - g_PlayerYaw = packet.GetField(3).GetFloat(); - } - - if ((packet.GetField(5).GetByte() & 0x01) != 0) { - g_PlayerX += packet.GetField(0).GetDouble(); - } else { - g_PlayerX = packet.GetField(0).GetDouble(); - } - - if ((packet.GetField(5).GetByte() & 0x02) != 0) { - g_PlayerY += packet.GetField(1).GetDouble(); - } else { - g_PlayerY = packet.GetField(1).GetDouble(); - } - - if ((packet.GetField(5).GetByte() & 0x04) != 0) { - g_PlayerZ += packet.GetField(2).GetDouble(); - } else { - g_PlayerZ = packet.GetField(2).GetDouble(); - } - - g_IsGameStarted = true; - nc->AddPacketToQueue(PacketBuilder::CPlay0x03(0)); - nc->AddPacketToQueue(PacketBuilder::CPlay0x00(packet.GetField(6).GetVarInt())); - LOG(INFO) << "Game is started!"; - LOG(INFO) << "PlayerPos is " << g_PlayerX << ", " << g_PlayerY << ", " << g_PlayerZ << "\tAngle: " - << g_PlayerYaw - << "," << g_PlayerPitch; - break; - case 0x1A: - json = nlohmann::json::parse(packet.GetField(0).GetString()); - LOG(INFO) << "Disconnect reason: " << json["text"].get<std::string>(); - throw 119; - break; - case 0x20: - world.ParseChunkData(packet); - break; - case 0x07: - LOG(INFO) << "Statistics: "; - for (int i = 0; i < packet.GetField(0).GetVarInt(); i++) { - LOG(INFO) << "\t" << packet.GetField(1).GetArray()[0].GetString() << ": " - << packet.GetField(1).GetArray()[1].GetVarInt(); - } - break; - default: - break; - } - if (g_IsGameStarted) { - std::chrono::steady_clock clock; - static auto timeOfPreviousSendedPpalPacket(clock.now()); - std::chrono::duration<double, std::milli> delta = clock.now() - timeOfPreviousSendedPpalPacket; - if (delta.count() >= 50) { - nc->AddPacketToQueue( - PacketBuilder::CPlay0x0D(g_PlayerX, g_PlayerY, g_PlayerZ, g_PlayerYaw, g_PlayerPitch, true)); - timeOfPreviousSendedPpalPacket = clock.now(); - } - } - - delete packetPtr; +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; + 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; + if (std::abs(g_PlayerVelocityX) > 0.01) + g_PlayerVelocityX -= AirResistance * deltaTime * (g_PlayerVelocityX > 0 ? 1 : -1); + else + g_PlayerVelocityX = 0; + if (std::abs(g_PlayerVelocityZ) > 0.01) + g_PlayerVelocityZ -= AirResistance * deltaTime * (g_PlayerVelocityZ > 0 ? 1 : -1); + else + g_PlayerVelocityZ = 0;*/ + 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(); + if (ptr == nullptr) + return; + 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<1) { + 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; + } +} + +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; + break; + } + g_PlayerVelocityX = vel.x; + g_PlayerVelocityY = vel.y; + g_PlayerVelocityZ = vel.z; + const double MaxSpeed = 5.0; + /*if (g_PlayerVelocityX > MaxSpeed || g_PlayerVelocityX < -MaxSpeed) + g_PlayerVelocityX = MaxSpeed * (g_PlayerVelocityX > 0 ? 1 : -1); + if (g_PlayerVelocityZ > MaxSpeed || g_PlayerVelocityZ < -MaxSpeed) + g_PlayerVelocityZ = MaxSpeed * (g_PlayerVelocityZ > 0 ? 1 : -1);*/ + + + /*bool isCollides = world.isPlayerCollides(g_PlayerX, g_PlayerY, g_PlayerZ); + if (isCollides) { + SetPosition(previousPos); + return; + } + auto updatePacket = std::make_shared<PacketPlayerPosition>(g_PlayerX, g_PlayerY, g_PlayerZ, true); + nc->SendPacket(updatePacket);*/ +} + +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() { + return glm::lookAt(this->Position(), this->Position() + 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 - 0.5, g_PlayerY + 1.12, g_PlayerZ - 0.5); +} + +void GameState::SetPosition(glm::vec3 Position) { + g_PlayerX = Position.x + 0.5; + g_PlayerY = Position.y - 1.12; + g_PlayerZ = Position.z + 0.5; } diff --git a/src/gamestate/GameState.hpp b/src/gamestate/GameState.hpp index 8817f4c..27338fb 100644 --- a/src/gamestate/GameState.hpp +++ b/src/gamestate/GameState.hpp @@ -1,41 +1,70 @@ #pragma once #include <nlohmann/json.hpp> +#include <glm/glm.hpp> +#include <glm/gtc/matrix_transform.hpp> #include "../world/World.hpp" #include "../network/NetworkClient.hpp" -#include "../packet/PacketParser.hpp" -#include "../packet/PacketBuilder.hpp" +#include "../utility/Vector.hpp" class GameState { - NetworkClient *nc; + NetworkClient *nc; public: - GameState(NetworkClient *NetClient); - - World world; - - void Update(); - - std::string g_PlayerUuid; - std::string g_PlayerName; - ConnectionState m_networkState; - bool g_IsGameStarted; - int g_PlayerEid; - int g_Gamemode; - int g_Dimension; - byte g_Difficulty; - byte g_MaxPlayers; - std::string g_LevelType; - bool g_ReducedDebugInfo; - Vector g_SpawnPosition; - bool g_PlayerInvulnerable; - bool g_PlayerFlying; - bool g_PlayerAllowFlying; - bool g_PlayerCreativeMode; - float g_PlayerFlyingSpeed; - float g_PlayerFovModifier; - float g_PlayerPitch; - float g_PlayerYaw; - double g_PlayerX; - double g_PlayerY; - double g_PlayerZ; + GameState(NetworkClient *NetClient, bool &quit); + + void Update(float deltaTime); + + //Navigation + enum Direction { + FORWARD, BACKWARD, LEFT, RIGHT, JUMP + }; + void HandleMovement(GameState::Direction direction, float deltaTime); + void HandleRotation(double yaw, double pitch); + glm::mat4 GetViewMatrix(); + void updateCameraVectors(); + + float Yaw(); + float Pitch(); + void SetYaw(float yaw); + void SetPitch(float pitch); + + glm::vec3 Position(); + void SetPosition(glm::vec3 Position); + glm::vec3 Front; + glm::vec3 Up; + glm::vec3 Right; + glm::vec3 WorldUp; + + //Everything other + World world; + bool &isRunning; + + std::string g_PlayerUuid; + std::string g_PlayerName; + bool g_IsGameStarted; + int g_PlayerEid; + int g_Gamemode; + int g_Dimension; + byte g_Difficulty; + byte g_MaxPlayers; + std::string g_LevelType; + bool g_ReducedDebugInfo; + Vector g_SpawnPosition; + bool g_PlayerInvulnerable; + bool g_PlayerFlying; + bool g_PlayerAllowFlying; + bool g_PlayerCreativeMode; + float g_PlayerFlyingSpeed; + float g_PlayerFovModifier; + float g_PlayerPitch; + float g_PlayerYaw; + double g_PlayerX; + double g_PlayerY; + double g_PlayerZ; + float g_PlayerHealth; + + bool g_OnGround = true; + double g_PlayerVelocityX = 0; + double g_PlayerVelocityY = 0; + double g_PlayerVelocityZ = 0; }; diff --git a/src/network/Network.cpp b/src/network/Network.cpp index 4ce424c..59c4e00 100644 --- a/src/network/Network.cpp +++ b/src/network/Network.cpp @@ -1,101 +1,215 @@ #include "Network.hpp" +#include <iostream> -Network::Network(std::string address, unsigned short port) : m_address(address), m_port(port) { - LOG(INFO) << "Connecting to server " << m_address << ":" << m_port; - sf::Socket::Status status = m_socket.connect(sf::IpAddress(m_address), m_port); - m_socket.setBlocking(true); - if (status != sf::Socket::Done) { - if (status == sf::Socket::Error) { - LOG(ERROR) << "Can't connect to remote server"; - } else { - LOG(ERROR) << "Connection failed with unknown reason"; - throw std::runtime_error("Connection is failed"); - throw 13; - } - } - LOG(INFO) << "Connected to server"; +Network::Network(std::string address, unsigned short port) { + socket = new Socket(address, port); + stream = new StreamSocket(socket); } Network::~Network() { - m_socket.disconnect(); - LOG(INFO) << "Disconnected"; -} - -void Network::SendHandshake(std::string username) { - //Handshake packet - Packet handshakePacket = PacketBuilder::CHandshaking0x00(316, m_address, m_port, 2); - SendPacket(handshakePacket); - - //LoginStart packet - Field fName; - fName.SetString(username); - Packet loginPacket(0); - loginPacket.AddField(fName); - SendPacket(loginPacket); + delete stream; + delete socket; } -void DumpPacket(Packet &packet, std::string DumpName) { - return; - byte *buff = new byte[packet.GetLength()]; - packet.CopyToBuff(buff); - std::ofstream fs(DumpName, std::ios::out | std::ios::binary); - fs.write(reinterpret_cast<const char *>(buff), packet.GetLength()); - fs.close(); - delete buff; +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; } -static int pn = 0; - void Network::SendPacket(Packet &packet) { - m_socket.setBlocking(true); - byte *packetData = new byte[packet.GetLength()]; - packet.CopyToBuff(packetData); - m_socket.send(packetData, packet.GetLength()); - std::ostringstream out; - out << "s" << pn++ << "-"; - out << "0x" << (packet.GetId() < 15 ? "0" : "") << std::hex << packet.GetId() << std::dec; - DumpPacket(packet, out.str()); - - delete[] packetData; + StreamCounter packetSize; + packetSize.WriteVarInt(packet.GetPacketId()); + packet.ToStream(&packetSize); + stream->WriteVarInt(packetSize.GetCountedSize()); + stream->WriteVarInt(packet.GetPacketId()); + packet.ToStream(stream); } -Packet Network::ReceivePacket() { - byte bufLen[5] = {0}; - size_t rec = 0; - for (int i = 0; i < 5; i++) { - byte buff = 0; - size_t r = 0; - m_socket.receive(&buff, 1, r); - rec += r; - bufLen[i] = buff; - if ((buff & 0b10000000) == 0) { - break; - } - } - Field fLen = FieldParser::Parse(VarIntType, bufLen); - size_t packetLen = fLen.GetVarInt() + fLen.GetLength(); - if (packetLen > 1024 * 1024 * 15) - LOG(WARNING) << "OMG SIZEOF PACKAGE IS " << packetLen; - if (packetLen < rec) { - return Packet(bufLen); - } - byte *bufPack = new byte[packetLen]; - std::copy(bufLen, bufLen + rec, bufPack); - size_t dataLen = rec; - while (m_socket.receive(bufPack + dataLen, packetLen - dataLen, rec) == sf::Socket::Done && dataLen < packetLen) { - dataLen += rec; +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 (dataLen < packetLen) { - LOG(ERROR) << "Received data is " << dataLen << " but " << packetLen << " is promoted"; - throw std::runtime_error("Data is losted"); - } else { - Packet p(bufPack); - delete[] bufPack; + if (packet.get() != nullptr) + packet->FromStream(&stream); + return packet; +} - std::ostringstream out; - out << "r" << pn++ << "-"; - out << "0x" << (p.GetId() < 15 ? "0" : "") << std::hex << p.GetId() << std::dec; - DumpPacket(p, out.str()); - return p; +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; } + return nullptr; } diff --git a/src/network/Network.hpp b/src/network/Network.hpp index 84f2e7f..1281289 100644 --- a/src/network/Network.hpp +++ b/src/network/Network.hpp @@ -1,28 +1,26 @@ #pragma once -#include <string> -#include <easylogging++.h> -#include <SFML/Network.hpp> -#include "../packet/Packet.hpp" -#include "../packet/PacketBuilder.hpp" - +#include <memory> +#include "Socket.hpp" +#include "Packet.hpp" + +enum ConnectionState { + Handshaking, + Login, + Play, + Status, +}; class Network { -public: - Network(std::string address, unsigned short port); - - ~Network(); - - void SendHandshake(std::string username); + Socket *socket; + StreamSocket *stream; - void SendPacket(Packet &packet); - - Packet ReceivePacket(); - -private: - std::string m_address; - unsigned short m_port; - sf::TcpSocket m_socket; - bool m_isCommpress=false; -}; + std::shared_ptr<Packet> ReceivePacketByPacketId(int packetId, ConnectionState state, StreamInput &stream); +public: + Network(std::string address, unsigned short port); + ~Network(); + std::shared_ptr<Packet> ReceivePacket(ConnectionState state = Play); + void SendPacket(Packet &packet); + std::shared_ptr<Packet> ParsePacketPlay(PacketNamePlayCB id); +};
\ No newline at end of file diff --git a/src/network/NetworkClient.cpp b/src/network/NetworkClient.cpp index fd957a5..b8d880d 100644 --- a/src/network/NetworkClient.cpp +++ b/src/network/NetworkClient.cpp @@ -1,107 +1,94 @@ #include "NetworkClient.hpp" +#include "Packet.hpp" -ServerInfo NetworkClient::ServerPing(std::string address, unsigned short port) { - ServerInfo info; - Network network(address, port); - Packet packet_handshake = PacketBuilder::CHandshaking0x00(316, address, port, 1); - network.SendPacket(packet_handshake); - Packet packet_request(0); - network.SendPacket(packet_request); - Packet packet_response = network.ReceivePacket(); - PacketParser::Parse(packet_response, Login); - //std::string json = static_cast<FieldString *>(packet_response_parsed.GetFieldById(0))->GetValue(); - std::string json = packet_response.GetField(0).GetString(); - try { - nlohmann::json j = nlohmann::json::parse(json); - info.protocol = j["version"]["protocol"].get<int>(); - info.version = j["version"]["name"].get<std::string>(); - info.players_max = j["players"]["max"].get<int>(); - info.players_online = j["players"]["online"].get<int>(); - info.description = j["description"]["text"].get<std::string>(); - for (auto t:j["description"]["extra"]) { - info.description += t["text"].get<std::string>(); - } - if (!j["favicon"].is_null()) - info.favicon = j["favicon"].get<std::string>(); - info.json = json; - for (auto t:j["players"]["sample"]) { - std::pair<std::string, std::string> player; - player.first = t["id"].get<std::string>(); - player.second = t["name"].get<std::string>(); - info.players.push_back(player); - } - } catch (const nlohmann::detail::exception e) { - std::cerr << "Parsed json is not valid (" << e.id << "): " << e.what() << std::endl; - } - //Ping - Packet packet_ping(0x01); - Field payload; - payload.SetLong(771235); - packet_ping.AddField(payload); - std::chrono::high_resolution_clock clock; - auto t1 = clock.now(); - network.SendPacket(packet_ping); - Packet pong = network.ReceivePacket(); - auto t2 = clock.now(); - pong.ParseField(Long); - if (pong.GetField(0).GetLong() == 771235) { - std::chrono::duration<double, std::milli> pingTime = t2 - t1; - info.ping = pingTime.count(); - } - return info; -} +NetworkClient::NetworkClient(std::string address, unsigned short port, std::string username, bool &quit) + : network(address, port), isRunning(quit) { + state = Handshaking; -NetworkClient::NetworkClient(std::string address, unsigned short port, std::string username) : m_network(address, - port) { - m_network.SendHandshake(username); - Update(); - m_networkThread = std::thread(&NetworkClient::MainLoop, this); -} + PacketHandshake handshake; + handshake.protocolVersion = 335; + handshake.serverAddress = "127.0.0.1"; + handshake.serverPort = 25565; + handshake.nextState = 2; + network.SendPacket(handshake); + state = Login; -NetworkClient::~NetworkClient() { - LOG(INFO)<<"NC stopping..."; - isContinue=false; - m_networkThread.join(); - LOG(INFO)<<"NC is stopped"; -} + PacketLoginStart loginStart; + loginStart.Username = "HelloOne"; + network.SendPacket(loginStart); -Packet * NetworkClient::GetPacket() { - if (m_received.size() < 1) - return nullptr; - Packet packet = m_received.front(); - m_received.pop(); - return new Packet(packet); + 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); } -void NetworkClient::AddPacketToQueue(Packet packet) { - m_toSend.push(packet); +NetworkClient::~NetworkClient() { + isActive = false; + networkThread.join(); } -void NetworkClient::Update() { - if (m_toSend.size() > 0) { - m_network.SendPacket(m_toSend.front()); - m_toSend.pop(); - } - Packet received = m_network.ReceivePacket(); - if (received.GetId() == 0x1F) { - PacketParser::Parse(received); - Packet response = PacketBuilder::CPlay0x0B(received.GetField(0).GetVarInt()); - m_network.SendPacket(response); - return; - } - m_updateMutex.lock(); - m_received.push(received); - m_updateMutex.unlock(); +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::MainLoop() { - el::Helpers::setThreadName("Network"); - try { - while (isContinue) { - Update(); - } - } catch (int e){ - LOG(ERROR)<<"Catched exception in NC: "<<e; - } +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/network/NetworkClient.hpp index 14745a5..bf7aa4e 100644 --- a/src/network/NetworkClient.hpp +++ b/src/network/NetworkClient.hpp @@ -1,45 +1,25 @@ #pragma once -#include <queue> #include <thread> +#include <queue> #include <mutex> -#include <nlohmann/json.hpp> #include "Network.hpp" -#include "../packet/PacketParser.hpp" -#include "../packet/PacketBuilder.hpp" -struct ServerInfo{ - std::string version; - int protocol = 0; - int players_max = 0; - int players_online = 0; - std::vector<std::pair<std::string, std::string>> players; - std::string description; - double ping = 0; - std::string favicon; - std::string json; -}; class NetworkClient { + Network network; + std::thread networkThread; + std::mutex toSendMutex; + std::mutex toReceiveMutex; + std::queue <std::shared_ptr<Packet>> toSend; + std::queue <std::shared_ptr<Packet>> toReceive; + bool isActive=true; + bool &isRunning; + ConnectionState state; + void NetworkLoop(); public: - NetworkClient(std::string address, unsigned short port, std::string username); - ~NetworkClient(); - - void Update(); - - void MainLoop(); - - Packet * GetPacket(); - void AddPacketToQueue(Packet packet); - - static ServerInfo ServerPing(std::string address,unsigned short port); -private: - std::mutex m_updateMutex; - std::thread m_networkThread; - bool isContinue=true; - NetworkClient (const NetworkClient&); - NetworkClient&operator=(const NetworkClient&); - Network m_network; - std::queue <Packet> m_received; - std::queue <Packet> m_toSend; -}; + NetworkClient(std::string address, unsigned short port, std::string username, bool &quit); + ~NetworkClient(); + std::shared_ptr <Packet> ReceivePacket(); + void SendPacket(std::shared_ptr<Packet> packet); +};
\ No newline at end of file diff --git a/src/network/Packet.hpp b/src/network/Packet.hpp new file mode 100644 index 0000000..9249a34 --- /dev/null +++ b/src/network/Packet.hpp @@ -0,0 +1,492 @@ +#pragma once + +#include <easylogging++.h> +#include "Stream.hpp" + +enum PacketNameLoginSB { + LoginStart = 0x00, + EncryptionResponse = 0x01, +}; +enum PacketNamePlaySB { + TeleportConfirm, + PrepareCraftingGrid, + TabCompleteSB, + ChatMessageSB, + ClientStatus, + ClientSettings, + ConfirmTransactionSB, + EnchantItem, + ClickWindow, + CloseWindowSB, + PluginMessageSB, + UseEntity, + KeepAliveSB, + Player, + PlayerPosition, + PlayerPositionAndLookSB, + PlayerLook, + VehicleMoveSB, + SteerBoat, + PlayerAbilitiesSB, + PlayerDigging, + EntityAction, + SteerVehicle, + CraftingBookData, + ResourcePackStatus, + AdvancementTab, + HeldItemChangeSB, + CreativeInventoryAction, + UpdateSign, + AnimationSB, + Spectate, + PlayerBlockPlacement, + UseItem, +}; + +enum PacketNameHandshakingCB { + Handshake = 0x00, +}; +enum PacketNameLoginCB { + Disconnect = 0x00, + EncryptionRequest = 0x01, + LoginSuccess = 0x02, + SetCompression = 0x03, +}; +enum PacketNamePlayCB { + SpawnObject = 0x00, + SpawnExperienceOrb, + SpawnGlobalEntity, + SpawnMob, + SpawnPainting, + SpawnPlayer, + AnimationCB, + Statistics, + BlockBreakAnimation, + UpdateBlockEntity, + BlockAction, + BlockChange, + BossBar, + ServerDifficulty, + TabCompleteCB, + ChatMessageCB, + MultiBlockChange, + ConfirmTransactionCB, + CloseWindowCB, + OpenWindow, + WindowItems, + WindowProperty, + SetSlot, + SetCooldown, + PluginMessageCB, + NamedSoundEffect, + DisconnectPlay, + EntityStatus, + Explosion, + UnloadChunk, + ChangeGameState, + KeepAliveCB, + ChunkData, + Effect, + Particle, + JoinGame, + Map, + EntityRelativeMove, + EntityLookAndRelativeMove, + EntityLook, + Entity, + VehicleMove, + OpenSignEditor, + PlayerAbilitiesCB, + CombatEvent, + PlayerListItem, + PlayerPositionAndLookCB, + UseBed, + UnlockRecipes, + DestroyEntities, + RemoveEntityEffect, + ResourcePackSend, + Respawn, + EntityHeadLook, + SelectAdvancementTab, + WorldBorder, + Camera, + HeldItemChangeCB, + DisplayScoreboard, + EntityMetadata, + AttachEntity, + EntityVelocity, + EntityEquipment, + SetExperience, + UpdateHealth, + ScoreboardObjective, + SetPassengers, + Teams, + UpdateScore, + SpawnPosition, + TimeUpdate, + Title, + SoundEffect, + PlayerListHeaderAndFooter, + CollectItem, + EntityTeleport, + Advancements, + EntityProperties, + EntityEffect, +}; + +struct Packet { + virtual ~Packet() = default; + virtual void ToStream(StreamOutput *stream) = 0; + virtual void FromStream(StreamInput *stream) = 0; + virtual int GetPacketId() = 0; +}; + +struct PacketHandshake : Packet { + void ToStream(StreamOutput *stream) override { + stream->WriteVarInt(protocolVersion); + stream->WriteString(serverAddress); + stream->WriteUShort(serverPort); + stream->WriteVarInt(nextState); + } + + void FromStream(StreamInput *stream) override { + protocolVersion = stream->ReadVarInt(); + serverAddress = stream->ReadString(); + serverPort = stream->ReadUShort(); + nextState = stream->ReadVarInt(); + } + + int GetPacketId() override { + return PacketNameHandshakingCB::Handshake; + } + + int protocolVersion; + std::string serverAddress; + unsigned short serverPort; + int nextState; +}; + +struct PacketLoginStart : Packet { + void ToStream(StreamOutput *stream) override { + stream->WriteString(Username); + } + + void FromStream(StreamInput *stream) override { + Username = stream->ReadString(); + } + + int GetPacketId() override { + return PacketNameLoginSB::LoginStart; + } + + std::string Username; +}; + +struct PacketLoginSuccess : Packet { + void ToStream(StreamOutput *stream) override { + stream->WriteString(Uuid); + stream->WriteString(Username); + } + + void FromStream(StreamInput *stream) override { + Uuid = stream->ReadString(); + Username = stream->ReadString(); + } + + int GetPacketId() override { + return PacketNameLoginCB::LoginSuccess; + } + + std::string Uuid; + std::string Username; +}; + +struct PacketJoinGame : Packet { + void ToStream(StreamOutput *stream) override { + stream->WriteInt(EntityId); + stream->WriteUByte(Gamemode); + stream->WriteInt(Dimension); + stream->WriteUByte(Difficulty); + stream->WriteUByte(MaxPlayers); + stream->WriteString(LevelType); + stream->WriteBool(ReducedDebugInfo); + } + + void FromStream(StreamInput *stream) override { + EntityId = stream->ReadInt(); + Gamemode = stream->ReadUByte(); + Dimension = stream->ReadInt(); + Difficulty = stream->ReadUByte(); + MaxPlayers = stream->ReadUByte(); + LevelType = stream->ReadString(); + ReducedDebugInfo = stream->ReadBool(); + } + + int GetPacketId() override { + return PacketNamePlayCB::JoinGame; + } + + int EntityId; + unsigned char Gamemode; + int Dimension; + unsigned char Difficulty; + unsigned char MaxPlayers; + std::string LevelType; + bool ReducedDebugInfo; +}; + +struct PacketDisconnectPlay : Packet { + void ToStream(StreamOutput *stream) override { + + } + + void FromStream(StreamInput *stream) override { + Reason = stream->ReadChat(); + } + + int GetPacketId() override { + return PacketNamePlayCB::DisconnectPlay; + } + + std::string Reason; +}; + +struct PacketSpawnPosition : Packet { + void ToStream(StreamOutput *stream) override { + + } + + void FromStream(StreamInput *stream) override { + Location = stream->ReadPosition(); + } + + int GetPacketId() override { + return PacketNamePlayCB::SpawnPosition; + } + + Vector Location; +}; + +struct PacketKeepAliveCB : Packet { + void ToStream(StreamOutput *stream) override { + stream->WriteVarInt(KeepAliveId); + } + + void FromStream(StreamInput *stream) override { + KeepAliveId = stream->ReadVarInt(); + } + + int GetPacketId() override { + return PacketNamePlayCB::KeepAliveCB; + } + + int KeepAliveId; +}; + +struct PacketKeepAliveSB : Packet { + void ToStream(StreamOutput *stream) override { + stream->WriteVarInt(KeepAliveId); + } + + void FromStream(StreamInput *stream) override { + KeepAliveId = stream->ReadVarInt(); + } + + int GetPacketId() override { + return PacketNamePlaySB::KeepAliveSB; + } + + int KeepAliveId; + + PacketKeepAliveSB(int KeepAliveId) : KeepAliveId(KeepAliveId) {} +}; + +struct PacketPlayerPositionAndLookCB : Packet { + void ToStream(StreamOutput *stream) override { + + } + + void FromStream(StreamInput *stream) override { + X = stream->ReadDouble(); + Y = stream->ReadDouble(); + Z = stream->ReadDouble(); + Yaw = stream->ReadFloat(); + Pitch = stream->ReadFloat(); + Flags = stream->ReadUByte(); + TeleportId = stream->ReadVarInt(); + } + + int GetPacketId() override { + return PacketNamePlayCB::PlayerPositionAndLookCB; + } + + double X; + double Y; + double Z; + float Yaw; + float Pitch; + unsigned char Flags; + int TeleportId; +}; + +struct PacketTeleportConfirm : Packet { + void ToStream(StreamOutput *stream) override { + stream->WriteVarInt(TeleportId); + } + + void FromStream(StreamInput *stream) override { + TeleportId = stream->ReadVarInt(); + } + + int GetPacketId() override { + return PacketNamePlaySB::TeleportConfirm; + } + + int TeleportId; + + PacketTeleportConfirm(int TeleportId) : TeleportId(TeleportId) {} +}; + +struct PacketClientStatus : Packet { + void ToStream(StreamOutput *stream) override { + stream->WriteVarInt(ActionId); + } + + void FromStream(StreamInput *stream) override { + ActionId = stream->ReadVarInt(); + } + + int GetPacketId() override { + return PacketNamePlaySB::ClientStatus; + } + + int ActionId; + + PacketClientStatus(int ActionId) : ActionId(ActionId) {} +}; + +struct PacketPlayerPositionAndLookSB : Packet { + void ToStream(StreamOutput *stream) override { + stream->WriteDouble(X); + stream->WriteDouble(FeetY); + stream->WriteDouble(Z); + stream->WriteFloat(Yaw); + stream->WriteFloat(Pitch); + stream->WriteBool(OnGround); + } + + void FromStream(StreamInput *stream) override { + + } + + int GetPacketId() override { + return PacketNamePlaySB::PlayerPositionAndLookSB; + } + + + double X; + double FeetY; + double Z; + float Yaw; + float Pitch; + bool OnGround; + + PacketPlayerPositionAndLookSB(double X, double FeetY, double Z, + float Yaw, float Pitch, bool OnGround) : X(X), FeetY(FeetY), Z(Z), Yaw(Yaw), + Pitch(Pitch), OnGround(OnGround) {} +}; + +struct PacketChunkData : Packet { + void ToStream(StreamOutput *stream) override { + + } + + void FromStream(StreamInput *stream) override { + ChunkX = stream->ReadInt(); + ChunkZ = stream->ReadInt(); + GroundUpContinuous = stream->ReadBool(); + PrimaryBitMask = stream->ReadVarInt(); + Size = stream->ReadVarInt(); + Data = stream->ReadByteArray(Size); + NumberOfBlockEntities = stream->ReadVarInt(); + } + + int GetPacketId() override { + return PacketNamePlayCB::ChunkData; + } + + int ChunkX; + int ChunkZ; + bool GroundUpContinuous; + int PrimaryBitMask; + int Size; + std::vector<unsigned char> Data; + int NumberOfBlockEntities; + //std::vector<NbtTag> BlockEntities; +}; + +struct PacketPlayerPosition : Packet { + void ToStream(StreamOutput *stream) override { + stream->WriteDouble(X); + stream->WriteDouble(FeetY); + stream->WriteDouble(Z); + stream->WriteBool(OnGround); + } + + void FromStream(StreamInput *stream) override { + + } + + int GetPacketId() override { + return PacketNamePlaySB::PlayerPosition; + } + + double X; + double FeetY; + double Z; + bool OnGround; + + PacketPlayerPosition(double X, double Y, double Z, bool ground) : X(X), FeetY(Y), Z(Z), OnGround(ground) {} +}; + +struct PacketPlayerLook : Packet { + void ToStream(StreamOutput *stream) override { + stream->WriteFloat(Yaw); + stream->WriteFloat(Pitch); + stream->WriteBool(OnGround); + } + + void FromStream(StreamInput *stream) override { + + } + + int GetPacketId() override { + return PacketNamePlaySB::PlayerLook; + } + + float Yaw; + float Pitch; + bool OnGround; + + PacketPlayerLook(float Yaw, float Pitch, bool ground) : Yaw(Yaw), Pitch(Pitch), OnGround(ground) {} +}; + +struct PacketUpdateHealth : Packet { + void ToStream(StreamOutput *stream) override { + + } + + void FromStream(StreamInput *stream) override { + Health = stream->ReadFloat(); + Food = stream->ReadVarInt(); + FoodSaturation = stream->ReadFloat(); + } + + int GetPacketId() override { + return PacketNamePlayCB::UpdateHealth; + } + + float Health; + int Food; + float FoodSaturation; +};
\ No newline at end of file diff --git a/src/network/Socket.cpp b/src/network/Socket.cpp new file mode 100644 index 0000000..2bbf49a --- /dev/null +++ b/src/network/Socket.cpp @@ -0,0 +1,29 @@ +#include "Socket.hpp" + +Socket::Socket(std::string address, unsigned short port) { + sf::Socket::Status connectionStatus = socket.connect(sf::IpAddress(address), port); + if (connectionStatus == sf::Socket::Status::Error) + throw std::runtime_error("Can't connect to remote server"); + else if (connectionStatus != sf::Socket::Status::Done) + throw std::runtime_error("Connection failed with unknown reason"); +} + +Socket::~Socket() { + socket.disconnect(); +} + +void Socket::Read(unsigned char *buffPtr, size_t buffLen) { + size_t received = 0; + socket.receive(buffPtr, buffLen, received); + size_t totalReceived = received; + while (totalReceived < buffLen) { + if (socket.receive(buffPtr + totalReceived, buffLen - totalReceived, received) != sf::Socket::Done) + throw std::runtime_error("Raw socket data receiving is failed"); + totalReceived += received; + } +} + +void Socket::Write(unsigned char *buffPtr, size_t buffLen) { + if (socket.send(buffPtr, buffLen) != sf::Socket::Done) + throw std::runtime_error("Raw socket data sending is failed"); +} diff --git a/src/network/Socket.hpp b/src/network/Socket.hpp new file mode 100644 index 0000000..ee449b3 --- /dev/null +++ b/src/network/Socket.hpp @@ -0,0 +1,45 @@ +#pragma once + +#include <string> +#include <SFML/Network.hpp> + +/** + * Platform independent class for working with platform dependent hardware socket + * @brief Wrapper around raw sockets + * @warning Connection state is based on lifetime of Socket object instance, ie connected at ctor and disconnect at dtor + * @todo Replace SFML's socket with WinSock and POSIX's socket implementation + */ +class Socket { + sf::TcpSocket socket; +public: + /** + * Constructs Socket class instance from IP's string and Port number and connects to remote server + * @param[in] address IP address of remote server. String should be ANSI and contains 4 one-byte values separated by dots + * @param[in] port target port of remote server to connect + * @throw std::runtime_error if connection is failed + */ + Socket(std::string address, unsigned short port); + + /** + * Destruct Socket instance and disconnect from server + * @warning There is no way to force disconnect, except use delete for manually allocated objects and scope of visibility for variables on stack + */ + ~Socket(); + + /** + * Reads data from socket and write to buffer + * @warning This is blocking function, and execution flow will not be returned until all required data is sended + * @warning Reported buffer length must be <= actual size of buffer, or memory corruption will be caused + * @param[out] buffPtr Pointer to buffer, where data must be placed + * @param[in] buffLen Length of data, that must be readed from server and writed to buffer + */ + void Read(unsigned char *buffPtr, size_t buffLen); + + /** + * Writes data from buffer to socket + * @warning This is blocking function, and execution flow will not be returned until all required data is received + * @param[in] buffPtr Pointer to buffer that contain data to send + * @param[in] buffLen Length of buffer + */ + void Write(unsigned char *buffPtr, size_t buffLen); +};
\ No newline at end of file diff --git a/src/network/Stream.cpp b/src/network/Stream.cpp new file mode 100644 index 0000000..a0c6cb0 --- /dev/null +++ b/src/network/Stream.cpp @@ -0,0 +1,334 @@ +#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 char buff[2]; + ReadData(buff, 2); + unsigned short val = *(reinterpret_cast<unsigned short *>(buff)); + endswap(val); + return val; +} + +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) { + +} + +void StreamOutput::WriteUByte(unsigned char value) { + endswap(value); + WriteData(&value,1); +} + +void StreamOutput::WriteShort(short value) { + +} + +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) { + +} + +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) { + +} + +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) { + +} + +void StreamOutput::WriteEntityMetadata(std::vector<unsigned char> value) { + +} + +void StreamOutput::WriteSlot(std::vector<unsigned char> value) { + +} + +void StreamOutput::WriteNbtTag(std::vector<unsigned char> value) { + +} + +void StreamOutput::WritePosition(Vector value) { + +} + +void StreamOutput::WriteAngle(unsigned char value) { + +} + +void StreamOutput::WriteUuid(std::vector<unsigned char> value) { + +} + +void StreamOutput::WriteByteArray(std::vector<unsigned char> value) { + +} + +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) { + 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/network/Stream.hpp new file mode 100644 index 0000000..5babb08 --- /dev/null +++ b/src/network/Stream.hpp @@ -0,0 +1,115 @@ +#pragma once + +#include <algorithm> +#include <string> +#include <stdexcept> +#include <vector> +#include <cstring> +#include <nlohmann/json.hpp> +#include <easylogging++.h> +#include "Socket.hpp" +#include "../utility/Vector.hpp" + +class Stream { +protected: + template<class T> + void endswap(T &obj) { + unsigned char *raw = reinterpret_cast<unsigned char *>(&obj); + std::reverse(raw, raw + sizeof(T)); + } + + void endswap(unsigned char *arr, size_t arrLen) { + std::reverse(arr, arr + arrLen); + } + +public: + virtual ~Stream() {}; +}; + +class StreamInput : Stream { + virtual void ReadData(unsigned char *buffPtr, size_t buffLen) = 0; +public: + virtual ~StreamInput() = default; + bool ReadBool(); + signed char ReadByte(); + unsigned char ReadUByte(); + short ReadShort(); + unsigned short ReadUShort(); + int ReadInt(); + long long ReadLong(); + float ReadFloat(); + double ReadDouble(); + std::string ReadString(); + std::string ReadChat(); + int ReadVarInt(); + long long ReadVarLong(); + std::vector<unsigned char> ReadEntityMetadata(); + std::vector<unsigned char> ReadSlot(); + std::vector<unsigned char> ReadNbtTag(); + Vector ReadPosition(); + unsigned char ReadAngle(); + std::vector<unsigned char> ReadUuid(); + std::vector<unsigned char> ReadByteArray(size_t arrLength); +}; + +class StreamOutput : Stream { + virtual void WriteData(unsigned char *buffPtr, size_t buffLen) = 0; +public: + virtual ~StreamOutput() = default; + void WriteBool(bool value); + void WriteByte(signed char value); + void WriteUByte(unsigned char value); + void WriteShort(short value); + void WriteUShort(unsigned short value); + void WriteInt(int value); + void WriteLong(long long value); + void WriteFloat(float value); + void WriteDouble(double value); + void WriteString(std::string value); + void WriteChat(std::string value); + void WriteVarInt(int value); + void WriteVarLong(long long value); + void WriteEntityMetadata(std::vector<unsigned char> value); + void WriteSlot(std::vector<unsigned char> value); + void WriteNbtTag(std::vector<unsigned char> value); + void WritePosition(Vector value); + void WriteAngle(unsigned char value); + void WriteUuid(std::vector<unsigned char> value); + void WriteByteArray(std::vector<unsigned char> value); +}; + +class StreamBuffer : public StreamInput, public StreamOutput { + unsigned char *buffer; + unsigned char *bufferPtr; + size_t bufferLength; + + void ReadData(unsigned char *buffPtr, size_t buffLen) override; + void WriteData(unsigned char *buffPtr, size_t buffLen) override; + +public: + StreamBuffer(unsigned char *data, size_t dataLen); + StreamBuffer(size_t bufferLen); + ~StreamBuffer(); + + std::vector<unsigned char> GetBuffer(); +}; + +class StreamCounter : public StreamOutput { + void WriteData(unsigned char *buffPtr, size_t buffLen) override; + + size_t size; +public: + StreamCounter(size_t initialSize = 0); + ~StreamCounter(); + + size_t GetCountedSize(); +}; + +class StreamSocket : public StreamInput, public StreamOutput { + Socket *socket; + void ReadData(unsigned char *buffPtr, size_t buffLen) override; + void WriteData(unsigned char *buffPtr, size_t buffLen) override; +public: + StreamSocket(Socket *socketPtr); + ~StreamSocket() = default; +};
\ No newline at end of file diff --git a/src/packet/Field.cpp b/src/packet/Field.cpp deleted file mode 100644 index 9be2469..0000000 --- a/src/packet/Field.cpp +++ /dev/null @@ -1,303 +0,0 @@ -#include "Field.hpp" - -Field::Field() { -} - -Field::Field(const Field &other) : m_dataLength(other.m_dataLength), m_type(other.m_type) { - - m_data = new byte[m_dataLength]; - std::copy(other.m_data,other.m_data+m_dataLength,m_data); -} - -void Field::swap(Field &other) { - std::swap(other.m_dataLength, m_dataLength); - std::swap(other.m_data, m_data); - std::swap(other.m_type, m_type); -} - -Field &Field::operator=(Field other) { - other.swap(*this); - return *this; -} - -Field::~Field() { - Clear(); -} - -size_t Field::GetLength() { - if (m_data != nullptr && m_dataLength == 0) - throw 102; - return m_dataLength; -} - -void Field::Clear() { - m_dataLength = 0; - delete[] m_data; - m_data = nullptr; -} - -void Field::CopyToBuff(byte *ptr) { - if (m_dataLength > 0) - std::copy(m_data,m_data+m_dataLength,ptr); -} - -void Field::SetRaw(byte *ptr, size_t len, FieldType type) { - Clear(); - m_dataLength = len; - m_type = type; - m_data = new byte[m_dataLength]; - std::copy(ptr,ptr+m_dataLength,m_data); -} - -int Field::GetVarInt() { - - size_t readed; - return VarIntRead(m_data, readed); - -} - -void Field::SetVarInt(int value) { - Clear(); - m_type = VarIntType; - m_data = new byte[5]; - m_dataLength = VarIntWrite(value, m_data); -} - -int Field::GetInt() { - int value = *(reinterpret_cast<int *>(m_data)); - endswap(&value); - return value; -} - -void Field::SetInt(int value) { - Clear(); - m_type = Int; - m_data = new byte[4]; - m_dataLength = 4; - int *p = reinterpret_cast<int *>(m_data); - *p = value; - endswap(p); -} - -bool Field::GetBool() { - return *m_data != 0x00; -} - -void Field::SetBool(bool value) { - Clear(); - m_type = Boolean; - m_data = new byte[1]; - m_dataLength = 1; - *m_data = value ? 0x01 : 0x00; -} - -unsigned short Field::GetUShort() { - unsigned short *p = reinterpret_cast<unsigned short *>(m_data); - unsigned short t = *p; - endswap(&t); - return t; -} - -void Field::SetUShort(unsigned short value) { - Clear(); - m_type = UnsignedShort; - m_dataLength = 2; - m_data = new byte[2]; - unsigned short *p = reinterpret_cast<unsigned short *>(m_data); - *p = value; - endswap(p); -} - -std::string Field::GetString() { - Field fLen; - byte *ptr = m_data; - size_t l; - int val = VarIntRead(ptr, l); - ptr += l; - std::string s((char *) ptr, val); - return s; -} - -void Field::SetString(std::string value) { - Clear(); - m_type = String; - Field fLen; - fLen.SetVarInt(value.size()); - m_dataLength = value.size() + fLen.GetLength(); - m_data = new byte[m_dataLength]; - byte *p = m_data; - fLen.CopyToBuff(p); - p += fLen.GetLength(); - std::copy(value.begin(),value.end(),p); -} - -long long Field::GetLong() { - long long t = *reinterpret_cast<long long *>(m_data); - endswap(&t); - return t; -} - -void Field::SetLong(long long value) { - Clear(); - m_type = Long; - m_dataLength = 8; - m_data = new byte[m_dataLength]; - long long *p = reinterpret_cast<long long *>(m_data); - *p = value; - endswap(p); -} - -FieldType Field::GetType() { - return m_type; -} - -byte Field::GetUByte() { - byte t = *reinterpret_cast<byte *>(m_data); - endswap(&t); - return t; -} - -void Field::SetUByte(byte value) { - Clear(); - m_type = UnsignedByte; - endswap(&value); - m_dataLength = 1; - m_data = new byte[m_dataLength]; - byte *p = reinterpret_cast<byte *>(m_data); - *p = value; -} - -sbyte Field::GetByte() { - sbyte t = *reinterpret_cast<sbyte *>(m_data); - endswap(&t); - return t; -} - -void Field::SetByte(sbyte value) { - Clear(); - m_type = Byte8_t; - endswap(&value); - m_dataLength = 1; - m_data = new byte[m_dataLength]; - sbyte *p = reinterpret_cast<sbyte *>(m_data); - *p = value; -} - -float Field::GetFloat() { - float t = *reinterpret_cast<float *>(m_data); - endswap(&t); - return t; -} - -void Field::SetFloat(float value) { - Clear(); - m_type = Float; - endswap(&value); - m_dataLength = 4; - m_data = new byte[m_dataLength]; - float *p = reinterpret_cast<float *>(m_data); - *p = value; -} - -Vector Field::GetPosition() { - unsigned long long t = *reinterpret_cast<unsigned long long *>(m_data); - endswap(&t); - 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); - } - Vector val(x,y,z); - return val; -} - -void Field::SetPosition(Vector value) { - Clear(); - m_type = Position; - m_dataLength = 8; - m_data = new byte[m_dataLength]; - unsigned long long *t = reinterpret_cast<unsigned long long *>(m_data); - unsigned long long x = ((unsigned long long) value.GetX()) << 38; - unsigned long long y = ((unsigned long long) value.GetY()) << 26; - unsigned long long z = value.GetZ(); - endswap(&x); - endswap(&z); - endswap(&y); - *t = x | y | z; -} - -double Field::GetDouble() { - double t = *reinterpret_cast<double *>(m_data); - endswap(&t); - return t; -} - -void Field::SetDouble(double value) { - Clear(); - m_type = Double; - endswap(&value); - m_dataLength = 8; - m_data = new byte[m_dataLength]; - double *p = reinterpret_cast<double *>(m_data); - *p = value; -} - -size_t Field::GetFieldLength(FieldType type) { - switch (type) { - case UnknownType: - return 0; - case Boolean: - return 1; - case Byte8_t: - return 1; - case UnsignedByte: - return 1; - case Short: - return 2; - case UnsignedShort: - return 2; - case Int: - return 4; - case Long: - return 8; - case Float: - return 4; - case Double: - return 8; - case Position: - return 8; - case Angle: - return 4; - case Uuid: - return 16; - default: - return 0; - } -} - -std::vector<Field> Field::GetArray() { - /*std::vector<Field> vec; - if (m_type<20){ - size_t fieldLen=GetFieldLength(m_type); - byte* ptr = m_data; - for (int i=0;i<m_dataLength/fieldLen;i++){ - Field f; - f.SetRaw(ptr,fieldLen,m_type); - vec.push_back(f); - ptr+=fieldLen; - } - return vec; - }*/ - return m_childs; -} - -void Field::Attach(Field field) { - m_childs.push_back(field); -} diff --git a/src/packet/Field.hpp b/src/packet/Field.hpp deleted file mode 100644 index c33cd1c..0000000 --- a/src/packet/Field.hpp +++ /dev/null @@ -1,121 +0,0 @@ -#pragma once - -#include <cstddef> -#include <cstdint> -#include <cmath> -#include <string> -#include <vector> - -#include "../utility/utility.h" -#include "../utility/Vector.hpp" - -typedef unsigned char byte; -typedef signed char sbyte; - -enum FieldType { - UnknownType = 0, - Boolean, //Bool - Byte8_t, //int8_t - UnsignedByte, //uint8_t - Short, //int16_t - UnsignedShort, //uint16_t - Int, //int32_t - Long, //int64_t - Float, //float - Double, //double - Position, //PositionI - Angle, //uint8_t - Uuid, //byte* (2 bytes) - //Unknown-length data - - String = 100, //std::string - Chat, //std::string - VarIntType, //int32_t - VarLong, //int64_t - ChunkSection, //byte* - EntityMetadata, //byte* - Slot, //byte* - NbtTag, //byte* - ByteArray, //byte* -}; - -class Field { -public: - Field(); - - Field(const Field &other); - - void swap(Field &other); - - Field &operator=(Field other); - - ~Field(); - - size_t GetLength(); - - void Clear(); - - void CopyToBuff(byte *ptr); - - void SetRaw(byte *ptr, size_t len = 0, FieldType type = UnknownType); - - FieldType GetType(); - - void Attach(Field field); - - static size_t GetFieldLength(FieldType type); - - //Cpp-types setters/getters for binary content of MC's data types - - int GetVarInt(); - - void SetVarInt(int value); - - int GetInt(); - - void SetInt(int value); - - bool GetBool(); - - void SetBool(bool value); - - unsigned short GetUShort(); - - void SetUShort(unsigned short value); - - std::string GetString(); - - void SetString(std::string value); - - long long GetLong(); - - void SetLong(long long value); - - byte GetUByte(); - - void SetUByte(byte value); - - sbyte GetByte(); - - void SetByte(sbyte value); - - float GetFloat(); - - void SetFloat(float value); - - Vector GetPosition(); - - void SetPosition(Vector value); - - double GetDouble(); - - void SetDouble(double value); - - std::vector<Field> GetArray(); - -private: - size_t m_dataLength = 0; - byte *m_data = nullptr; - FieldType m_type = UnknownType; - std::vector<Field> m_childs; -}; diff --git a/src/packet/FieldParser.cpp b/src/packet/FieldParser.cpp deleted file mode 100644 index 295e78f..0000000 --- a/src/packet/FieldParser.cpp +++ /dev/null @@ -1,105 +0,0 @@ -#include "FieldParser.hpp" - -Field FieldParser::Parse(FieldType type, byte *data, size_t len) { - switch (type) { - case VarIntType: - return ParseVarInt(data, len); - case Boolean: - return ParseBool(data); - case String: - return ParseString(data); - case Long: - return ParseLong(data); - case Int: - return ParseInt(data); - case UnsignedByte: - return ParseUByte(data); - case Byte8_t: - return ParseByte(data); - case Float: - return ParseFloat(data); - case Position: - return ParsePosition(data); - case Double: - return ParseDouble(data); - case ByteArray: - return ParseByteArray(data, len); - default: - throw 105; - } -} - -Field FieldParser::ParseString(byte *data) { - Field fLen = ParseVarInt(data, 0); - Field f; - f.SetRaw(data, fLen.GetLength() + fLen.GetVarInt(), String); - return f; -} - -Field FieldParser::ParseBool(byte *data) { - Field f; - f.SetRaw(data, 1, Boolean); - return f; -} - -Field FieldParser::ParseVarInt(byte *data, size_t len) { - if (len != 0) { - Field f; - f.SetRaw(data, len, VarIntType); - return f; - } - int val = VarIntRead(data, len); - Field f; - f.SetVarInt(val); - return f; -} - -Field FieldParser::ParseLong(byte *data) { - Field f; - f.SetRaw(data, 8, Long); - return f; -} - -Field FieldParser::ParseInt(byte *data) { - Field f; - f.SetRaw(data, 4, Int); - return f; -} - -Field FieldParser::ParseUByte(byte *data) { - Field f; - f.SetRaw(data, 1, UnsignedByte); - return f; -} - -Field FieldParser::ParseByte(byte *data) { - Field f; - f.SetRaw(data, 1, Byte8_t); - return f; -} - -Field FieldParser::ParseFloat(byte *data) { - Field f; - f.SetRaw(data, 4, Float); - return f; -} - -Field FieldParser::ParsePosition(byte *data) { - Field f; - f.SetRaw(data, 8, Position); - return f; -} - -Field FieldParser::ParseDouble(byte *data) { - Field f; - f.SetRaw(data, 8, Double); - return f; -} - -Field FieldParser::ParseByteArray(byte *data, size_t len) { - if (len == 0) - throw 119; - Field f; - f.SetRaw(data, len, Byte8_t); - return f; -} diff --git a/src/packet/FieldParser.hpp b/src/packet/FieldParser.hpp deleted file mode 100644 index f256b34..0000000 --- a/src/packet/FieldParser.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include "Field.hpp" - -class FieldParser { -public: - static Field ParseVarInt(byte *data, size_t len); - - static Field ParseBool(byte *data); - - static Field ParseString(byte *data); - - static Field Parse(FieldType type, byte* data, size_t len=0); - - static Field ParseLong(byte *data); - - static Field ParseInt(byte *data); - - static Field ParseUByte(byte *data); - - static Field ParseByte(byte *data); - - static Field ParseFloat(byte *data); - - static Field ParsePosition(byte *data); - - static Field ParseDouble(byte *data); - - static Field ParseByteArray(byte *data, size_t len); -};
\ No newline at end of file diff --git a/src/packet/Packet.cpp b/src/packet/Packet.cpp deleted file mode 100644 index 68cc3c3..0000000 --- a/src/packet/Packet.cpp +++ /dev/null @@ -1,101 +0,0 @@ -#include "Packet.hpp" - -Packet::Packet(int id) { - Field fLen; - fLen.SetVarInt(0); - m_fields.push_back(fLen); - Field fId; - fId.SetVarInt(id); - m_fields.push_back(fId); -} - -Packet Packet::operator=(Packet other) { - other.swap(*this); - return *this; -} - -void Packet::swap(Packet &other) { - std::swap(m_fields, other.m_fields); - std::swap(m_data, other.m_data); - std::swap(m_parsePtr, other.m_parsePtr); - std::swap(m_dataLength, other.m_dataLength); -} - -void Packet::CopyToBuff(byte *ptr) { - m_fields[0].SetVarInt(GetLength() - m_fields[0].GetLength()); - for (auto &it:m_fields) { - it.CopyToBuff(ptr); - ptr += it.GetLength(); - } -} - -void Packet::ParseField(FieldType type, size_t len) { - if (type == ByteArray && len == 0) - throw 118; - Field f = FieldParser::Parse(type, m_parsePtr, len); - m_fields.push_back(f); - m_parsePtr += f.GetLength(); - if (m_parsePtr == m_data + m_dataLength) { - delete[] m_data; - m_data = nullptr; - m_dataLength = 0; - m_parsePtr = nullptr; - } -} - -Packet::Packet(byte *data) { - Field fLen = FieldParser::Parse(VarIntType, data); - data += fLen.GetLength(); - Field fId = FieldParser::Parse(VarIntType, data); - data += fId.GetLength(); - m_dataLength = fLen.GetVarInt() - fId.GetLength(); - m_data = new byte[m_dataLength]; - std::copy(data, data + m_dataLength, m_data); - m_parsePtr = m_data; - m_fields.push_back(fLen); - m_fields.push_back(fId); -} - -Field &Packet::GetField(int id) { - if (id < -2 || id >= (int) m_fields.size() - 2) - throw 111; - return m_fields[id + 2]; -} - -size_t Packet::GetLength() { - size_t len = 0; - for (auto &it:m_fields) { - len += it.GetLength(); - } - return len + m_dataLength; -} - -void Packet::AddField(Field field) { - m_fields.push_back(field); -} - -int Packet::GetId() { - return m_fields[1].GetVarInt(); -} - -Packet::Packet(const Packet &other) { - if (other.m_dataLength > 0) { - m_dataLength = other.m_dataLength; - m_data = new byte[m_dataLength]; - m_parsePtr = m_data + (other.m_data - other.m_parsePtr); - std::copy(other.m_data, other.m_data + m_dataLength, m_data); - } - m_fields = other.m_fields; -} - -void Packet::ParseFieldArray(Field &field, FieldType type, size_t len) { - Field f = FieldParser::Parse(type, m_parsePtr, len); - field.Attach(f); - m_parsePtr += f.GetLength(); - if (m_parsePtr == m_data + m_dataLength) { - delete[] m_data; - m_data = nullptr; - m_dataLength = 0; - m_parsePtr = nullptr; - } -} diff --git a/src/packet/Packet.hpp b/src/packet/Packet.hpp deleted file mode 100644 index 68a5d5e..0000000 --- a/src/packet/Packet.hpp +++ /dev/null @@ -1,130 +0,0 @@ -#pragma once - -#include <vector> -#include "Field.hpp" -#include "FieldParser.hpp" - -enum ConnectionState { - Login, - Handshaking, - Play, - Status, -}; - -enum PacketsClientBound{ - SpawnObject=0x00, - SpawnExperienceOrb, - SpawnGlobalEntity, - SpawnMob, - SpawnPainting, - SpawnPlayer, - Animation, - Statistics, - BlockBreakAnimation, - UpdateBlockEntity, - BlockAction, - BlockChange, - BossBar, - ServerDifficulty, - Tab, - ChatMessage, - MultiBlockChange, - ConfirmTransaction, - CloseWindowEvent, - OpenWindow, - WindowItems, - WindowProperty, - SetSlot, - SetCooldown, - PluginMessage, - NamedSoundEffect, - Disconnect, - EntityStatus, - Explosion, - UnloadChunk, - ChangeGameState, - KeepAlive, - ChunkData, - Effect, - Particle, - JoinGame, - Map, - EntityRelativeMove, - EntityLookAndRelativeMove, - EntityLook, - Entity, - VehicleMove, - OpenSignEditor, - PlayerAbilities, - CombatEvent, - PlayerListItem, - PlayerPositionAndLook, - UseBed, - DestroyEntities, - RemoveEntityEffect, - ResourcePackSend, - Respawn, - EntityHeadLook, - WorldBorder, - Camera, - HeldItemChange, - DisplayScoreboard, - EntityMetadata_, - AttachEntity, - EntityVelocity, - EntityEquipment, - SetExperience, - UpdateHealth, - ScoreboardObjective, - SetPassengers, - Teams, - UpdateScore, - SpawnPosition, - TimeUpdate, - Title, - SoundEffect, - PlayerListHeaderAndFooter, - CollectItem, - EntityTeleport, - EntityProperties, - EntityEffect, -}; - -class Packet { -public: - Packet(int id); - - Packet(byte *data); - - Packet(const Packet &other); - - ~Packet() { - delete[] m_data; - } - - int GetId(); - - void AddField(Field field); - - void ParseField(FieldType type, size_t len = 0); - - void ParseFieldArray(Field &field, FieldType type, size_t len); - - Field & GetField(int id); - - size_t GetLength(); - - void CopyToBuff(byte *ptr); - - void swap(Packet &other); - - Packet operator=(Packet other); - -private: - Packet(); - - std::vector<Field> m_fields; - byte *m_data = nullptr; - byte *m_parsePtr = nullptr; - size_t m_dataLength = 0; -};
\ No newline at end of file diff --git a/src/packet/PacketBuilder.cpp b/src/packet/PacketBuilder.cpp deleted file mode 100644 index 4083ea3..0000000 --- a/src/packet/PacketBuilder.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "PacketBuilder.hpp" - -Packet PacketBuilder::CHandshaking0x00(int protocolVerison, std::string address, unsigned short port, int nextState) { - Packet handshakePacket(0); - Field fProtocol; - fProtocol.SetVarInt(protocolVerison); - Field fAddress; - fAddress.SetString(address); - Field fPort; - fPort.SetUShort(port); - Field fNextState; - fNextState.SetVarInt(nextState); - handshakePacket.AddField(fProtocol); - handshakePacket.AddField(fAddress); - handshakePacket.AddField(fPort); - handshakePacket.AddField(fNextState); - return handshakePacket; -} - -Packet PacketBuilder::CPlay0x0B(int keepAliveId) { - Packet keepAlivePacket(0x0B); - Field fKeepAlive; - fKeepAlive.SetVarInt(keepAliveId); - keepAlivePacket.AddField(fKeepAlive); - return keepAlivePacket; -} - -Packet PacketBuilder::CPlay0x03(int actionId) { - Packet clientStatusPacket(0x03); - Field fActionId; - fActionId.SetVarInt(actionId); - clientStatusPacket.AddField(fActionId); - return clientStatusPacket; -} - -Packet PacketBuilder::CPlay0x00(int teleportId) { - Packet teleportConfirmPacket(0x00); - Field fTeleportId; - fTeleportId.SetVarInt(teleportId); - teleportConfirmPacket.AddField(fTeleportId); - return teleportConfirmPacket; -} - -Packet PacketBuilder::CPlay0x0D(double x, double y, double z, float yaw, float pitch, bool onGround) { - Packet playerPositionAndLookPacket(0x0D); - Field fX; - Field fY; - Field fZ; - Field fYaw; - Field fPitch; - Field fOnGround; - fX.SetDouble(x); - fY.SetDouble(y); - fZ.SetDouble(z); - fYaw.SetFloat(yaw); - fPitch.SetFloat(pitch); - fOnGround.SetBool(onGround); - playerPositionAndLookPacket.AddField(fX); - playerPositionAndLookPacket.AddField(fY); - playerPositionAndLookPacket.AddField(fZ); - playerPositionAndLookPacket.AddField(fYaw); - playerPositionAndLookPacket.AddField(fPitch); - playerPositionAndLookPacket.AddField(fOnGround); - return playerPositionAndLookPacket; -} diff --git a/src/packet/PacketBuilder.hpp b/src/packet/PacketBuilder.hpp deleted file mode 100644 index 2fcb737..0000000 --- a/src/packet/PacketBuilder.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - - -#include "Packet.hpp" - -class PacketBuilder { -public: - static Packet CHandshaking0x00(int protocolVerison, std::string address, unsigned short port, int nextState); - static Packet CPlay0x0B(int keepAliveId); - - static Packet CPlay0x03(int actionId); - - static Packet CPlay0x00(int teleportId); - - static Packet CPlay0x0D(double x, double y, double z, float yaw, float pitch, bool onGround); -}; - diff --git a/src/packet/PacketParser.cpp b/src/packet/PacketParser.cpp deleted file mode 100644 index a609011..0000000 --- a/src/packet/PacketParser.cpp +++ /dev/null @@ -1,147 +0,0 @@ -#include "PacketParser.hpp" - -void PacketParser::Parse(Packet &packet, ConnectionState state, bool ClientBound) { - if (ClientBound) { - switch (state) { - case Login: - ParseLogin(packet); - break; - case Handshaking: - break; - case Play: - ParsePlay(packet); - break; - case Status: - - break; - } - } else { - ParseServerBound(packet, state); - } -} - -void PacketParser::ParseServerBound(Packet &packet, ConnectionState state) { - if (packet.GetLength() != state) - throw 107; -} - -void PacketParser::ParseLogin(Packet &packet) { - switch (packet.GetId()) { - case 0x00: - ParseLogin0x00(packet); - break; - case 0x02: - ParseLogin0x02(packet); - break; - default: { - - //throw 112; - } - } -} - -void PacketParser::ParsePlay(Packet &packet) { - switch (packet.GetId()) { - case 0x23: - ParsePlay0x23(packet); - break; - case 0x1F: - ParsePlay0x1F(packet); - break; - case 0x0D: - ParsePlay0x0D(packet); - break; - case 0x2B: - ParsePlay0x2B(packet); - break; - case 0x43: - ParsePlay0x43(packet); - break; - case 0x2E: - ParsePlay0x2E(packet); - break; - case 0x1A: - ParsePlay0x1A(packet); - break; - case 0x20: - ParsePlay0x20(packet); - break; - case 0x07: - ParsePlay0x07(packet); - default: - //throw 113; - break; - } -} - -void PacketParser::ParseLogin0x00(Packet &packet) { - packet.ParseField(String); -} - -void PacketParser::ParseLogin0x02(Packet &packet) { - packet.ParseField(String); - packet.ParseField(String); -} - -void PacketParser::ParsePlay0x23(Packet &packet) { - packet.ParseField(Int); - packet.ParseField(UnsignedByte); - packet.ParseField(Int); - packet.ParseField(UnsignedByte); - packet.ParseField(UnsignedByte); - packet.ParseField(String); - packet.ParseField(Boolean); -} - -void PacketParser::ParsePlay0x1F(Packet &packet) { - packet.ParseField(VarIntType); -} - -void PacketParser::ParsePlay0x0D(Packet &packet) { - packet.ParseField(UnsignedByte); -} - -void PacketParser::ParsePlay0x2B(Packet &packet) { - packet.ParseField(Byte8_t); - packet.ParseField(Float); - packet.ParseField(Float); -} - -void PacketParser::ParsePlay0x43(Packet &packet) { - packet.ParseField(Position); -} - -void PacketParser::ParsePlay0x2E(Packet &packet) { - packet.ParseField(Double); - packet.ParseField(Double); - packet.ParseField(Double); - packet.ParseField(Float); - packet.ParseField(Float); - packet.ParseField(Byte8_t); - packet.ParseField(VarIntType); -} - -void PacketParser::ParsePlay0x1A(Packet &packet) { - packet.ParseField(String); -} - -void PacketParser::ParsePlay0x20(Packet &packet) { - packet.ParseField(Int); - packet.ParseField(Int); - packet.ParseField(Boolean); - packet.ParseField(VarIntType); - packet.ParseField(VarIntType); - packet.ParseField(ByteArray, packet.GetField(4).GetVarInt()); - packet.ParseField(VarIntType); - //packet.ParseField(NbtTag); - //packet.GetField(7).SetArray(packet.GetField(6).GetVarInt()); -} - -void PacketParser::ParsePlay0x07(Packet &packet) { - packet.ParseField(VarIntType); - packet.AddField(Field()); - for (int i = 0; i < packet.GetField(0).GetVarInt(); i++) { - packet.ParseFieldArray(packet.GetField(1), String, 0); - packet.ParseFieldArray(packet.GetField(1), VarIntType, 0); - } -} diff --git a/src/packet/PacketParser.hpp b/src/packet/PacketParser.hpp deleted file mode 100644 index 8ca6195..0000000 --- a/src/packet/PacketParser.hpp +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - - -#include "Packet.hpp" - -class PacketParser { -public: - static void Parse(Packet &packet, ConnectionState state = Play, bool ClientBound = true); - - static void ParseServerBound(Packet &packet, ConnectionState state); - - static void ParseLogin(Packet &packet); - - static void ParsePlay(Packet &packet); - - static void ParseLogin0x00(Packet &packet); - - static void ParseLogin0x02(Packet &packet); - - static void ParsePlay0x23(Packet &packet); - - static void ParsePlay0x1F(Packet &packet); - - static void ParsePlay0x0D(Packet &packet); - - static void ParsePlay0x2B(Packet &packet); - - static void ParsePlay0x43(Packet &packet); - - static void ParsePlay0x2E(Packet &packet); - - static void ParsePlay0x1A(Packet &packet); - - static void ParsePlay0x20(Packet &packet); - - static void ParsePlay0x07(Packet &packet); -}; - diff --git a/src/world/Collision.cpp b/src/world/Collision.cpp new file mode 100644 index 0000000..4f2c837 --- /dev/null +++ b/src/world/Collision.cpp @@ -0,0 +1,28 @@ +#include "Collision.hpp" + +bool TestCollision(AABB first, AABB second) { + double firstXl = first.x; + double firstXr = first.x + first.w; + + double firstYl = first.y; + double firstYr = first.y + first.h; + + double firstZl = first.z; + double firstZr = first.z + first.l; + + + double secondXl = second.x; + double secondXr = second.x + second.w; + + double secondYl = second.y; + double secondYr = second.y + second.h; + + double secondZl = second.z; + double secondZr = second.z + second.l; + + bool collidesOnX = firstXr >= secondXl && firstXl <= secondXr; + bool collidesOnY = firstYr >= secondYl && firstYl <= secondYr; + bool collidesOnZ = firstZr >= secondZl && firstZl <= secondZr; + + return collidesOnX && collidesOnY && collidesOnZ; +} diff --git a/src/world/Collision.hpp b/src/world/Collision.hpp new file mode 100644 index 0000000..b88fbf7 --- /dev/null +++ b/src/world/Collision.hpp @@ -0,0 +1,8 @@ +#pragma once + +struct AABB { + double x,y,z; + double w,l,h; +}; + +bool TestCollision(AABB first, AABB second);
\ No newline at end of file diff --git a/src/world/Section.cpp b/src/world/Section.cpp index 63c7f97..8f94ad7 100644 --- a/src/world/Section.cpp +++ b/src/world/Section.cpp @@ -1,7 +1,8 @@ #include "Section.hpp" + Section::Section(byte *dataBlocks, size_t dataBlocksLength, byte *dataLight, byte *dataSky, byte bitsPerBlock, - std::vector<unsigned short> palette) { + std::vector<unsigned short> palette) { m_dataBlocksLen = dataBlocksLength; m_dataBlocks = new byte[m_dataBlocksLen]; std::copy(dataBlocks, dataBlocks + m_dataBlocksLen, m_dataBlocks); @@ -93,30 +94,22 @@ void Section::Parse() { m_dataSkyLight = nullptr; parseWaiter.notify_all(); - /*static std::map<Block,int> totalBlocks; - for (int x=0;x<16;x++) - for (int y=0;y<16;y++) - for (int z=0;z<16;z++) - totalBlocks[GetBlock(Vector(x,y,z))]++; - LOG(ERROR)<<"Logging chunk"; - for (auto& it:totalBlocks){ - LOG(WARNING)<<it.first.id<<":"<<(int)it.first.state<<" = "<<it.second; - }*/ } Section &Section::operator=(Section other) { - other.swap(*this); + std::swap(*this,other); return *this; } -void Section::swap(Section &other) { - std::swap(other.m_dataBlocksLen, m_dataBlocksLen); - std::swap(other.m_dataBlocks, m_dataBlocks); - std::swap(other.m_dataLight, m_dataLight); - std::swap(other.m_dataSkyLight, m_dataSkyLight); - std::swap(other.m_blocks, m_blocks); - std::swap(other.m_palette, m_palette); - std::swap(other.m_bitsPerBlock, m_bitsPerBlock); +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) { diff --git a/src/world/Section.hpp b/src/world/Section.hpp index 36fc91a..657fc13 100644 --- a/src/world/Section.hpp +++ b/src/world/Section.hpp @@ -5,38 +5,39 @@ #include <condition_variable> #include <easylogging++.h> #include "Block.hpp" -#include "../packet/Field.hpp" +#include "../utility/Vector.hpp" +#include "../utility/utility.h" const int SECTION_WIDTH = 16; const int SECTION_LENGTH = 16; const int SECTION_HEIGHT = 16; class Section { - std::vector<unsigned short> m_palette; - byte *m_dataBlocks = nullptr; - size_t m_dataBlocksLen; - byte *m_dataLight = nullptr; - byte *m_dataSkyLight = nullptr; - byte m_bitsPerBlock = 0; - std::vector<Block> m_blocks; - std::condition_variable parseWaiter; + std::vector<unsigned short> m_palette; + byte *m_dataBlocks = nullptr; + size_t m_dataBlocksLen; + byte *m_dataLight = nullptr; + byte *m_dataSkyLight = nullptr; + byte m_bitsPerBlock = 0; + std::vector<Block> m_blocks; + std::condition_variable parseWaiter; - Section(); + Section(); public: - void Parse(); + void Parse(); - Section(byte *dataBlocks, size_t dataBlocksLength, byte *dataLight, byte *dataSky, byte bitsPerBlock, - std::vector<unsigned short> palette); + Section(byte *dataBlocks, size_t dataBlocksLength, byte *dataLight, byte *dataSky, byte bitsPerBlock, + std::vector<unsigned short> palette); - ~Section(); + ~Section(); - Block &GetBlock(Vector pos); + Block &GetBlock(Vector pos); - Section &operator=(Section other); + Section &operator=(Section other); - void swap(Section &other); + friend void swap(Section &a, Section& b); - Section(const Section &other); + Section(const Section &other); };
\ No newline at end of file diff --git a/src/world/World.cpp b/src/world/World.cpp index 2220627..394598b 100644 --- a/src/world/World.cpp +++ b/src/world/World.cpp @@ -1,84 +1,39 @@ #include "World.hpp" -void World::ParseChunkData(Packet packet) { - int chunkX = packet.GetField(0).GetInt(); - int chunkZ = packet.GetField(1).GetInt(); - bool isGroundContinuous = packet.GetField(2).GetBool(); - std::bitset<16> bitmask(packet.GetField(3).GetVarInt()); - int entities = packet.GetField(5).GetVarInt(); - - size_t dataLen = packet.GetField(5).GetLength(); - byte *content = new byte[dataLen]; - byte *contentOrigPtr = content; - packet.GetField(5).CopyToBuff(content); - - if (isGroundContinuous) - dataLen -= 256; - - byte *biomes = content + packet.GetField(5).GetLength() - 256; +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]) { - size_t len = 0; - Vector chunkPosition = Vector(chunkX, i, chunkZ); - if (!m_sections.insert(std::make_pair(chunkPosition, ParseSection(content, len))).second) - LOG(ERROR) << "Chunk not created: " << chunkPosition; - auto sectionIter = m_sections.find(chunkPosition); - if (sectionIter == m_sections.end()) - LOG(ERROR) << "Created chunk not found: " << chunkPosition; - else - sectionIter->second.Parse(); - content += len; + Vector chunkPosition = Vector(packet->ChunkX, i, packet->ChunkZ); + Section section = ParseSection(&chunkData); + auto it = sections.find(chunkPosition); + if (it == sections.end()) { + sections.insert(std::make_pair(chunkPosition, section)); + } else { + using std::swap; + swap(it->second, section); + } + sections.find(chunkPosition)->second.Parse(); } } - delete[] contentOrigPtr; } -Section World::ParseSection(byte *data, size_t &dataLen) { - dataLen = 0; - - Field fBitsPerBlock = FieldParser::Parse(UnsignedByte, data); - byte bitsPerBlock = fBitsPerBlock.GetUByte(); - data += fBitsPerBlock.GetLength(); - dataLen += fBitsPerBlock.GetLength(); - - Field fPaletteLength = FieldParser::Parse(VarIntType, data); - int paletteLength = fPaletteLength.GetVarInt(); - data += fPaletteLength.GetLength(); - dataLen += fPaletteLength.GetLength(); - +Section World::ParseSection(StreamInput *data) { + unsigned char bitsPerBlock = data->ReadUByte(); + int paletteLength = data->ReadVarInt(); std::vector<unsigned short> palette; - if (paletteLength > 0) { - for (unsigned char i = 0; i < paletteLength; i++) { - endswap(&i); - Field f = FieldParser::Parse(VarIntType, data); - data += f.GetLength(); - dataLen += f.GetLength(); - palette.push_back(f.GetVarInt()); - endswap(&i); - } + for (int i = 0; i < paletteLength; i++) { + palette.push_back(data->ReadVarInt()); } - - Field fDataLength = FieldParser::Parse(VarIntType, data); - data += fDataLength.GetLength(); - dataLen += fDataLength.GetLength(); - - int dataLength = fDataLength.GetVarInt(); - size_t dataSize = dataLength * 8; - dataLen += dataSize; - byte *dataBlocks = data; - - data += 2048; - dataLen += 2048; - byte *dataLight = data; - - byte *dataSky = nullptr; - if (m_dimension == 0) { - data += 2048; - dataLen += 2048; - dataSky = data; - } - - return Section(dataBlocks, dataSize, dataLight, dataSky, bitsPerBlock, palette); + 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(dataArray.data(), dataArray.size(), blockLight.data(), + (skyLight.size() > 0 ? skyLight.data() : nullptr), bitsPerBlock, palette); } World::~World() { @@ -86,4 +41,56 @@ World::~World() { World::World() { -}
\ No newline at end of file +} + +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.5; + playerColl.w = PlayerWidth; + playerColl.y = Y - 0.5f; + playerColl.h = PlayerHeight; + playerColl.z = Z - PlayerLength / 2 - 0.5; + 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.5, + (y + it->first.GetY() * 16) - 0.5, + (z + it->first.GetZ() * 16) - 0.5, 1, 1, 1}; + if (TestCollision(playerColl, blockColl)) + return true; + } + } + } + } + return false; +} diff --git a/src/world/World.hpp b/src/world/World.hpp index b33499c..e315baf 100644 --- a/src/world/World.hpp +++ b/src/world/World.hpp @@ -8,27 +8,30 @@ #include <bitset> #include <easylogging++.h> #include "Block.hpp" -#include "../packet/Packet.hpp" #include "Section.hpp" +#include "../network/Packet.hpp" +#include "Collision.hpp" class World { - //utility vars - World(const World &other); + //utility vars + World(const World &other); - World &operator=(const World &other); + World &operator=(const World &other); - //game vars - int m_dimension = 0; + //game vars + int dimension = 0; - //game methods - Section ParseSection(byte *data, size_t &dataLen); + //game methods + Section ParseSection(StreamInput *data); public: - World(); + World(); - ~World(); + ~World(); - void ParseChunkData(Packet packet); + void ParseChunkData(std::shared_ptr<PacketChunkData> packet); - std::map<Vector, Section> m_sections; + std::map<Vector, Section> sections; + + bool isPlayerCollides(double X, double Y, double Z); };
\ No newline at end of file |