#include "Network.hpp" #include #include #include "Socket.hpp" Network::Network(std::string address, unsigned short port) { try { socket = std::make_unique(address, port); stream = std::make_unique(socket.get()); } catch (std::exception &e) { LOG(WARNING) << "Connection failed: " << e.what(); throw; } } Network::~Network() { } std::shared_ptr Network::ReceivePacket(ConnectionState state, bool useCompression) { if (useCompression) { int packetLength = stream->ReadVarInt(); auto packetData = stream->ReadByteArray(packetLength); StreamBuffer streamBuffer(packetData.data(), packetData.size()); int dataLength = streamBuffer.ReadVarInt(); if (dataLength == 0) { auto packetData = streamBuffer.ReadByteArray(packetLength - streamBuffer.GetReadedLength()); StreamBuffer streamBuffer(packetData.data(), packetData.size()); int packetId = streamBuffer.ReadVarInt(); auto packet = ReceivePacketByPacketId(packetId, state, streamBuffer); return packet; } else { std::vector compressedData = streamBuffer.ReadByteArray(packetLength - streamBuffer.GetReadedLength()); std::vector uncompressedData; uncompressedData.resize(dataLength); z_stream zStream; zStream.avail_in = compressedData.size(); zStream.next_in = compressedData.data(); zStream.avail_out = uncompressedData.size(); zStream.next_out = uncompressedData.data(); zStream.zalloc = Z_NULL; zStream.zfree = Z_NULL; zStream.opaque = Z_NULL; if (inflateInit(&zStream) != Z_OK) throw std::runtime_error("Zlib decompression initalization error"); int status = inflate(&zStream, Z_FINISH); switch (status) { case Z_STREAM_END: break; case Z_OK: case Z_STREAM_ERROR: case Z_BUF_ERROR: throw std::runtime_error("Zlib decompression error: " + std::to_string(status)); } if (inflateEnd(&zStream) != Z_OK) throw std::runtime_error("Zlib decompression end error"); StreamBuffer streamBuffer(uncompressedData.data(), uncompressedData.size()); int packetId = streamBuffer.ReadVarInt(); auto packet = ReceivePacketByPacketId(packetId, state, streamBuffer); return packet; } } else { int packetSize = stream->ReadVarInt(); auto packetData = stream->ReadByteArray(packetSize); StreamBuffer streamBuffer(packetData.data(), packetData.size()); int packetId = streamBuffer.ReadVarInt(); auto packet = ReceivePacketByPacketId(packetId, state, streamBuffer); return packet; } } void Network::SendPacket(Packet &packet, int compressionThreshold) { if (compressionThreshold >= 0) { StreamCounter packetSize; packetSize.WriteVarInt(packet.GetPacketId()); packetSize.WriteVarInt(0); packet.ToStream(&packetSize); if (packetSize.GetCountedSize() < compressionThreshold) { stream->WriteVarInt(packetSize.GetCountedSize()); stream->WriteVarInt(0); stream->WriteVarInt(packet.GetPacketId()); packet.ToStream(stream.get()); } else { throw std::runtime_error("Compressing send data not supported"); } } else { StreamCounter packetSize; packetSize.WriteVarInt(packet.GetPacketId()); packet.ToStream(&packetSize); stream->WriteVarInt(packetSize.GetCountedSize()); stream->WriteVarInt(packet.GetPacketId()); packet.ToStream(stream.get()); } stream->Flush(); } std::shared_ptr Network::ReceivePacketByPacketId(int packetId, ConnectionState state, StreamInput &in) { std::shared_ptr < Packet > packet(nullptr); switch (state) { case Handshaking: switch (packetId) { case PacketNameHandshakingCB::Handshake: packet = std::make_shared(); break; } break; case Login: switch (packetId) { case PacketNameLoginCB::LoginSuccess: packet = std::make_shared(); break; case PacketNameLoginCB::SetCompression: packet = std::make_shared(); break; case PacketNameLoginCB::Disconnect: packet = std::make_shared(); break; } break; case Play: packet = ParsePacketPlay((PacketNamePlayCB) packetId); break; case Status: break; } if (packet.get() != nullptr) packet->FromStream(&in); return packet; } std::shared_ptr Network::ParsePacketPlay(PacketNamePlayCB id) { switch (id) { case SpawnObject: return std::make_shared(); case SpawnExperienceOrb: break; case SpawnGlobalEntity: break; case SpawnMob: return std::make_shared(); case SpawnPainting: break; case SpawnPlayer: return std::make_shared(); case AnimationCB: break; case Statistics: break; case BlockBreakAnimation: break; case UpdateBlockEntity: break; case BlockAction: break; case BlockChange: return std::make_shared(); case BossBar: break; case ServerDifficulty: break; case TabCompleteCB: break; case ChatMessageCB: return std::make_shared(); case MultiBlockChange: return std::make_shared(); case ConfirmTransactionCB: return std::make_shared(); case CloseWindowCB: return std::make_shared(); case OpenWindow: return std::make_shared(); case WindowItems: return std::make_shared(); case WindowProperty: return std::make_shared(); case SetSlot: return std::make_shared(); case SetCooldown: break; case PluginMessageCB: break; case NamedSoundEffect: break; case DisconnectPlay: return std::make_shared(); case EntityStatus: break; case Explosion: break; case UnloadChunk: return std::make_shared(); case ChangeGameState: break; case KeepAliveCB: return std::make_shared(); case ChunkData: return std::make_shared(); case Effect: break; case Particle: break; case JoinGame: return std::make_shared(); case Map: break; case EntityRelativeMove: return std::make_shared(); case EntityLookAndRelativeMove: return std::make_shared(); case EntityLook: return std::make_shared(); case EntityCB: break; case VehicleMove: break; case OpenSignEditor: break; case CraftRecipeResponse: break; case PlayerAbilitiesCB: break; case CombatEvent: break; case PlayerListItem: break; case PlayerPositionAndLookCB: return std::make_shared(); case UseBed: break; case DestroyEntities: return std::make_shared(); case RemoveEntityEffect: break; case ResourcePackSend: break; case Respawn: return std::make_shared(); case EntityHeadLook: break; case WorldBorder: break; case Camera: break; case HeldItemChangeCB: break; case DisplayScoreboard: break; case EntityMetadata: break; case AttachEntity: break; case EntityVelocity: return std::make_shared(); case EntityEquipment: break; case SetExperience: break; case UpdateHealth: return std::make_shared(); case ScoreboardObjective: break; case SetPassengers: break; case Teams: break; case UpdateScore: break; case SpawnPosition: return std::make_shared(); case TimeUpdate: return std::make_shared(); case Title: break; case SoundEffect: break; case PlayerListHeaderAndFooter: break; case CollectItem: break; case EntityTeleport: return std::make_shared(); case EntityProperties: break; case EntityEffect: break; case UnlockRecipes: break; case SelectAdvancementTab: break; case Advancements: break; } return nullptr; }