#include "DedicatedServer.h" #include "config/ServerProperties.h" #include "PacketReader.h" #include #include namespace Feather { DedicatedServer::DedicatedServer(ServerProperties* properties) : m_properties(properties), m_listener(properties->serverPort.GetValue(), this), m_status() { m_status.descriptionText = properties->motd.GetValue(); m_status.maxPlayers = properties->maxPlayers; m_worldManager.LoadWorld(m_properties->levelName); while (1) { auto [clients, clientsLock] = m_clients.borrow(); for (auto& client : clients) { auto [data, clientLock] = client.GetTCPClient()->GetData().borrow(); if (data.empty()) continue; uint32_t offset = 0; while (offset != data.size()) { auto reader = PacketReader(&data[offset]); Protocol::ProcessPacket(*this, client, reader, client.GetContext().GetState()); offset += reader.Size(); } data.clear(); } // TODO: Move to tick thread !! { using namespace Protocol; using namespace std::chrono; // TODO: high_resolution_clock on mingw is innacurate and slow static auto lastKeepAlive = high_resolution_clock::now(); auto now = high_resolution_clock::now(); milliseconds td = duration_cast(now - lastKeepAlive); if (td >= 1000ms) { lastKeepAlive = now; Play::ClientboundKeepAlive keepAlive = { // MC probably sends time since epoch .id = duration_cast(now.time_since_epoch()).count(), }; for (auto &client : clients) { client.SendMessage(keepAlive); } } } } } DedicatedServer::~DedicatedServer() { } void DedicatedServer::OnClientConnect(Network::TCPClientHandle&& client) { const auto& address = client->GetAddress(); Log::Info("New connection from {}:{}", address.ip, address.port); auto [clients, lock] = m_clients.borrow(); clients.emplace_back(std::move(client)); } void DedicatedServer::OnClientDisconnect(const Network::TCPClient* client) { const auto& address = client->GetAddress(); Log::Info("Disconnected from {}:{}", address.ip, address.port); auto [clients, lock] = m_clients.borrow(); clients.remove_if([&](MinecraftClient& other) { return other.GetTCPClient().get() == client; }); } using namespace Protocol; void DedicatedServer::HandleUnknownPacket(MinecraftClient &client, int32_t id, const PacketReader &packet) { Log::Trace("Got unknown packet with ID {} from client.", id); } void DedicatedServer::HandleLegacyPing(MinecraftClient& client) { Log::Info("Got legacy server list ping."); } #pragma region Handshake & Status template <> void DedicatedServer::HandlePacket(MinecraftClient& client, const Handholding::ServerboundHandshake& handshake) { Log::Info("Client Intention Packet: version={}, serverIp={}, port={}, intention={}\n", handshake.protocolVersion, handshake.serverIP.c_str(), handshake.port, handshake.intention ); client.GetContext().SetState(handshake.intention); } template <> void DedicatedServer::HandlePacket(MinecraftClient& client, const Status::ServerboundRequest& request) { Log::Info("Client sent STATUS_PING_REQUEST"); Status::ClientboundResponse message = { .jsonResponse = m_status.GetServerStatusJSON() }; client.SendMessage(message); } template <> void DedicatedServer::HandlePacket(MinecraftClient& client, const Status::ServerboundPing& ping) { Log::Info("Client sent STATUS_PING: {}", ping.timestamp); Status::ClientboundPong message = { .timestamp = ping.timestamp }; client.SendMessage(message); } #pragma endregion template <> void DedicatedServer::HandlePacket(MinecraftClient& client,const Login::ServerboundStart& start) { //Login::ClientboundSuccess success = //{ // .uuid = { 4658857991808325907ull, 7518717155607718277ull }, // .username = start.username //}; std::string uuid = "ecb99913-96a8-40a7-8529-a2ca6ad95768"; Login::ClientboundSuccess success = { .uuid = uuid, .username = start.username }; client.SendMessage(success); client.GetContext().SetState(ProtocolState::Play); std::string type = "default"; Play::ClientboundJoinGame join = { .entityId = 0, .gamemode = 0, .dimension = 0, .seedHash = 0, .maxPlayers = uint8_t(m_properties->maxPlayers.GetValue()), .levelType = type, .viewDistance = m_properties->viewDistance, .reducedDebugInfo = false, .enableRespawnScreen = true }; client.SendMessage(join); Play::ClientboundSpawnPosition spawnPos = { .location = BlockPos(0, 64, 0), }; client.SendMessage(spawnPos); using RelativeFlags = Play::ClientboundPlayerPositionAndLook::RelativeFlags; Play::ClientboundPlayerPositionAndLook playerPos = { .x = 0, .y = 64, .z = 0, .xRot = 0, .yRot = 0, .flags = (RelativeFlags)0, .id = 0, }; client.SendMessage(playerPos); } template <> void DedicatedServer::HandlePacket(MinecraftClient& client, const Play::ServerboundKeepAlive& keepAlive) { // TODO: check these and kick clients that don't send em right or at all } }