summaryrefslogtreecommitdiffstats
path: root/src/network
diff options
context:
space:
mode:
Diffstat (limited to 'src/network')
-rw-r--r--src/network/Network.cpp284
-rw-r--r--src/network/Network.hpp42
-rw-r--r--src/network/NetworkClient.cpp175
-rw-r--r--src/network/NetworkClient.hpp52
-rw-r--r--src/network/Packet.hpp492
-rw-r--r--src/network/Socket.cpp29
-rw-r--r--src/network/Socket.hpp45
-rw-r--r--src/network/Stream.cpp334
-rw-r--r--src/network/Stream.hpp115
9 files changed, 1331 insertions, 237 deletions
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