Files
mcpe/source/network/RakNetInstance.cpp
Brent f12a3c1c61 Visual Studio Project Overhaul + Cleanup (#80)
* Visual Studio Project Overhaul + Cleanup
* SDL2 project for Windows
* Re-added game client icon to SDL2 code
* Renamed "AppPlatform_windows" to "AppPlatform_win32" (this is the name of the Windows API and is not representative of the architecture type)
* Renamed "LoggerWindows" to "LoggerWin32"
* Renamed "SoundSystemWindows to "SoundSystemDS" (DirectSound). This may be used for the 360, so it wouldn't really be Windows-specific then.
* Moved "ClientSideNetworkHandler" from "network" to "client/network". We don't need it being compiled for the server if the client's the only thing that needs it.
* I wonder if this still works on macOS...

* Bugfixes & Fixed for macOS

* Options::savePropertiesToFile Logging Bugfix

* Silence Winsock Deprecation Warnings in RakNet

* VS Project Improvements
- Replaced 50 billion relative paths with $(MC_ROOT)
- Added $(RAKNET_PATH) variable to override RakNet location
- Re-added gitignore for .vcxproj.user files
- Added debugging config to Directory.Builds.props
- Slimmed down project configurations for SDL2

* VS Project Config Bugfixes
- Fixed RakNet header path for additional includes

* RakNet Target for XCode

* XCode Project Config Fixes

* Packet logging

* Network VS Project Filter Fix

* Fix RakNet Packet ID Length
We previously didn't have consistency between old and new C++ regarding PacketType enum length. Now we do. This is required or else it completely breaks networking between the versions.

* Additional RakNet Error Handling

* Disable packet logging

* * Fix CMakeLists.txt

This reflects the relocation of ClientSideNetworkHandler.cpp.

* * Also add renderer/GL/GL.cpp to the CMakeLists.txt

* * Replace libpng with stb_image

* * Fix buggy water behavior.

* * Put the CMakeLists of the SDL project in debug mode

* Visual Studio 2010 Support

* * Change the SdlIoCallbacks from an array to a single member.

This fixes compilation of the sdl2 target on VS.

* * Fix missing _error label.

* Revert "* Fix missing _error label."

This reverts commit 99a057fc84049a16c864bd840fb439a008af5c74.

* Revert "* Replace libpng with stb_image"

* info_updateGame Tiles

---------

Co-authored-by: Brent Da Mage <BrentDaMage@users.noreply.github.com>
Co-authored-by: iProgramInCpp <iprogramincpp@gmail.com>
2023-10-22 10:08:59 +03:00

314 lines
7.5 KiB
C++

/********************************************************************
Minecraft: Pocket Edition - Decompilation Project
Copyright (C) 2023 iProgramInCpp
The following code is licensed under the BSD 1 clause license.
SPDX-License-Identifier: BSD-1-Clause
********************************************************************/
#include "RakNetInstance.hpp"
#include "MinecraftPackets.hpp"
#include "GetTime.h"
//#define LOG_PACKETS
#ifdef LOG_PACKETS
#define LOG_PACKET(str, ...) LOG_I(str, __VA_ARGS__)
#else
#define LOG_PACKET(str, ...)
#endif
RakNetInstance::RakNetInstance()
{
m_bIsHost = false;
m_pRakPeerInterface = RakNet::RakPeerInterface::GetInstance();
m_pRakPeerInterface->SetOccasionalPing(true);
}
RakNetInstance::~RakNetInstance()
{
if (m_pRakPeerInterface)
{
m_pRakPeerInterface->Shutdown(100);
RakNet::RakPeerInterface::DestroyInstance(m_pRakPeerInterface);
m_pRakPeerInterface = nullptr;
}
}
void RakNetInstance::announceServer(const std::string& name)
{
if (m_bIsHost && m_pRakPeerInterface->IsActive())
{
RakNet::RakString rs;
rs += "MCCPP;Demo;"; // @NOTE: still adding 'Demo' despite not actually being a demo.
rs += name.c_str();
RakNet::BitStream bs;
rs.Serialize(&bs);
m_pRakPeerInterface->SetOfflinePingResponse((const char*)bs.GetData(), bs.GetNumberOfBytesUsed());
}
}
void RakNetInstance::clearServerList()
{
m_servers.clear();
}
bool RakNetInstance::connect(const char* host, int port)
{
RakNet::SocketDescriptor sd;
disconnect();
if (m_pRakPeerInterface->Startup(4, &sd, 1) != RakNet::RAKNET_STARTED)
return false;
LOG_I("Connecting to %s", host);
// Was evaluated to a bool, CONNECTION_ATTEMPT_STARTED is 0
return m_pRakPeerInterface->Connect(host, port, nullptr, 0) != RakNet::CONNECTION_ATTEMPT_STARTED;
}
void RakNetInstance::disconnect()
{
if (m_pRakPeerInterface->IsActive())
m_pRakPeerInterface->Shutdown(500);
m_bIsHost = false;
m_bPingingForHosts = false;
}
RakNet::RakPeerInterface* RakNetInstance::getPeer()
{
return m_pRakPeerInterface;
}
std::vector<PingedCompatibleServer>* RakNetInstance::getServerList()
{
return &m_servers;
}
bool RakNetInstance::host(const std::string& name, int port, int maxConnections)
{
if (m_pRakPeerInterface->IsActive())
m_pRakPeerInterface->Shutdown(500);
RakNet::SocketDescriptor sd(port, nullptr);
m_pRakPeerInterface->SetMaximumIncomingConnections(maxConnections);
int result = m_pRakPeerInterface->Startup(maxConnections, &sd, 1);
m_bIsHost = true;
m_bPingingForHosts = false;
return result == RakNet::RAKNET_STARTED;
}
bool RakNetInstance::isMyLocalGuid(const RakNet::RakNetGUID& guid)
{
if (!m_pRakPeerInterface->IsActive())
return false;
return m_pRakPeerInterface->GetMyGUID() == guid;
}
void RakNetInstance::pingForHosts(int port)
{
if (!m_pRakPeerInterface->IsActive())
{
RakNet::SocketDescriptor sd;
m_pRakPeerInterface->Startup(4, &sd, 1);
}
m_hostPingPort = port;
m_bPingingForHosts = true;
m_startedPingingAt = RakNet::GetTimeMS();
m_pRakPeerInterface->Ping("255.255.255.255", port, true, 0);
}
void RakNetInstance::runEvents(NetEventCallback* callback)
{
while (true)
{
RakNet::Packet* pPacket = m_pRakPeerInterface->Receive();
if (!pPacket)
break;
uint8_t packetType = *(pPacket->data);
RakNet::BitStream* pBitStream = new RakNet::BitStream(pPacket->data + 1, pPacket->length - 1, 0);
LOG_PACKET("Recieved packet from %s (id: %d bitStream: 0x%x length: %u)", pPacket->systemAddress.ToString(), packetType, pBitStream, pPacket->length);
// @NOTE: why -1?
if (packetType >= PACKET_LOGIN - 1)
{
Packet* pUserPacket = MinecraftPackets::createPacket(packetType);
if (pUserPacket)
{
pUserPacket->read(pBitStream);
pUserPacket->handle(pPacket->guid, callback);
delete pUserPacket;
}
else
{
LOG_W("Received unrecognized packet type: %d", packetType);
}
}
else if (packetType > ID_DETECT_LOST_CONNECTIONS)
switch (packetType)
{
case ID_CONNECTION_REQUEST_ACCEPTED:
{
// @BUG: Two players sending connection requests at the same time could cause one of them to fail to connect
m_guid = pPacket->guid;
callback->onConnect(pPacket->guid);
break;
}
case ID_CONNECTION_ATTEMPT_FAILED:
{
callback->onUnableToConnect();
break;
}
case ID_NEW_INCOMING_CONNECTION:
{
callback->onNewClient(pPacket->guid);
break;
}
case ID_DISCONNECTION_NOTIFICATION:
case ID_CONNECTION_LOST:
{
callback->onDisconnect(pPacket->guid);
break;
}
case ID_UNCONNECTED_PONG:
{
unsigned int thing;
RakNet::RakString serverInfo, mccppDemo = "MCCPP;Demo;";
pBitStream->Read(thing);
pBitStream->Read(serverInfo);
// check if the server info starts with MCCPP;Demo;
if (serverInfo.GetLength() < mccppDemo.GetLength())
break;
RakNet::RakString headerSubstr = serverInfo.SubStr(0, unsigned(mccppDemo.GetLength()));
if (mccppDemo.StrCmp(headerSubstr) != 0)
break;
// update the info of a pinged compatible server, if possible.
for (int i = 0; i < m_servers.size(); i++)
{
PingedCompatibleServer& server = m_servers.at(i);
if (server.m_address == pPacket->systemAddress)
{
server.m_lastPinged = RakNet::GetTimeMS();
server.m_name = serverInfo.SubStr(unsigned(mccppDemo.GetLength()), unsigned(serverInfo.GetLength() - mccppDemo.GetLength()));
goto SKIP_ADDING_NEW_ENTRY;
}
}
// Add a new entry.
{
PingedCompatibleServer pcs;
pcs.m_address = pPacket->systemAddress;
pcs.m_lastPinged = RakNet::GetTimeMS();
pcs.m_name = serverInfo.SubStr(unsigned(mccppDemo.GetLength()), unsigned(serverInfo.GetLength() - mccppDemo.GetLength()));
m_servers.push_back(pcs);
}
SKIP_ADDING_NEW_ENTRY:
break;
}
default:
LOG_W("Received unrecognized RakNet packet type: %d", packetType);
break;
}
m_pRakPeerInterface->DeallocatePacket(pPacket);
if (pBitStream)
delete pBitStream;
}
if (m_bPingingForHosts)
{
int timeDiff = RakNet::GetTimeMS() - m_startedPingingAt;
if (timeDiff > 1000)
{
for (std::vector<PingedCompatibleServer>::iterator it = m_servers.begin(); it != m_servers.end(); )
{
if (RakNet::GetTimeMS() - it->m_lastPinged <= 3000)
{
it++;
continue;
}
it = m_servers.erase(it);
}
pingForHosts(m_hostPingPort);
}
}
}
// this broadcasts a packet to all other connected peers
void RakNetInstance::send(Packet* packet)
{
RakNet::BitStream bs;
packet->write(&bs);
uint32_t result;
if (m_bIsHost)
{
result = m_pRakPeerInterface->Send(&bs, HIGH_PRIORITY, RELIABLE, 0, RakNet::UNASSIGNED_RAKNET_GUID, true);
}
else
{
// send it to the host instead
result = m_pRakPeerInterface->Send(&bs, HIGH_PRIORITY, RELIABLE, 0, m_guid, false);
}
if (result != 0)
{
#ifdef LOG_PACKETS
uint8_t packetId;
bs.Read(packetId);
LOG_PACKET("Sent packet (id: %d guid: %s)", packetId, m_bIsHost ? "UNASSIGNED_SYSTEM_ADDRESS" : m_guid.ToString());
#endif
}
else
{
LOG_E("Failed to send packet!");
}
delete packet;
// return 1300; --- ida tells me this returns 1300. Huh
}
// this sends a specific peer a message
void RakNetInstance::send(const RakNet::RakNetGUID& guid, Packet* packet)
{
RakNet::BitStream bs;
packet->write(&bs);
m_pRakPeerInterface->Send(&bs, HIGH_PRIORITY, RELIABLE, 0, guid, false);
delete packet;
// return 1300; --- ida tells me this returns 1300. Huh
}
void RakNetInstance::stopPingForHosts()
{
if (!m_bPingingForHosts)
return;
m_pRakPeerInterface->Shutdown(0);
m_bPingingForHosts = false;
}