* Initial commit.

:)
This commit is contained in:
iProgramInCpp
2023-07-30 22:22:02 +03:00
commit 9642818a88
613 changed files with 151754 additions and 0 deletions

View File

@@ -0,0 +1,357 @@
#include <RakPeer.h>
#include "ClientSideNetworkHandler.hpp"
// This lets you make the client shut up and not log events in the debug console.
#define VERBOSE_CLIENT
#if defined(ORIGINAL_CODE) || defined(VERBOSE_CLIENT)
#define puts_ignorable(str) puts(str)
#define printf_ignorable(str, ...) printf(str, __VA_ARGS__)
#else
#define puts_ignorable(str)
#define printf_ignorable(str, ...)
#endif
ClientSideNetworkHandler::ClientSideNetworkHandler(Minecraft* pMinecraft, RakNetInstance* pRakNetInstance)
{
m_pMinecraft = pMinecraft;
m_pRakNetInstance = pRakNetInstance;
m_pServerPeer = m_pRakNetInstance->getPeer();
}
void ClientSideNetworkHandler::levelGenerated(Level* level)
{
m_pLevel = level;
requestNextChunk();
}
void ClientSideNetworkHandler::onConnect(const RakNet::RakNetGUID& rakGuid) // server guid
{
RakNet::RakNetGUID localGuid = ((RakNet::RakPeer*)m_pServerPeer)->GetMyGUID();
printf_ignorable("onConnect, server guid: %s, local guid: %s\n", rakGuid.ToString(), localGuid.ToString());
m_serverGUID = rakGuid;
LoginPacket* pLoginPkt = new LoginPacket;
pLoginPkt->m_str = RakNet::RakString(m_pMinecraft->m_pUser->field_0.c_str());
m_pRakNetInstance->send(pLoginPkt);
}
void ClientSideNetworkHandler::onUnableToConnect()
{
puts_ignorable("onUnableToConnect");
}
void ClientSideNetworkHandler::onDisconnect(const RakNet::RakNetGUID& rakGuid)
{
puts_ignorable("onDisconnect");
if (m_pLevel)
m_pLevel->field_11 = false;
m_pMinecraft->m_gui.addMessage("Disconnected from server");
}
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, MessagePacket* pMsgPkt)
{
puts_ignorable("MessagePacket");
m_pMinecraft->m_gui.addMessage(pMsgPkt->m_str.C_String());
}
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, StartGamePacket* pStartGamePkt)
{
puts_ignorable("StartGamePacket");
m_pMinecraft->getLevelSource()->deleteLevel("_LastJoinedServer");
m_pLevel = new Level(
m_pMinecraft->getLevelSource()->selectLevel("_LastJoinedServer", true),
"temp",
pStartGamePkt->field_4,
pStartGamePkt->field_8);
m_pLevel->field_11 = true;
auto pLocalPlayer = new LocalPlayer(m_pMinecraft, m_pLevel, m_pMinecraft->m_pUser, m_pLevel->m_pDimension->field_50);
pLocalPlayer->m_guid = ((RakNet::RakPeer*)m_pServerPeer)->GetMyGUID();
pLocalPlayer->m_EntityID = pStartGamePkt->field_C;
pLocalPlayer->moveTo(
pStartGamePkt->field_10,
pStartGamePkt->field_14,
pStartGamePkt->field_18,
pLocalPlayer->m_yaw,
pLocalPlayer->m_pitch);
m_pMinecraft->setLevel(m_pLevel, "ClientSideNetworkHandler -> setLevel", pLocalPlayer);
}
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, AddPlayerPacket* pAddPlayerPkt)
{
puts_ignorable("AddPlayerPacket");
if (!m_pLevel) return;
Player* pPlayer = new Player(m_pLevel);
pPlayer->m_EntityID = pAddPlayerPkt->m_id;
m_pLevel->addEntity(pPlayer);
pPlayer->moveTo(
pAddPlayerPkt->m_x,
pAddPlayerPkt->m_y,
pAddPlayerPkt->m_z,
pPlayer->m_yaw,
pPlayer->m_pitch);
pPlayer->m_name = pAddPlayerPkt->m_name;
pPlayer->m_guid = pAddPlayerPkt->m_guid;
m_pMinecraft->m_gui.addMessage(pPlayer->m_name + " joined the game");
}
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, RemoveEntityPacket* pRemoveEntityPkt)
{
if (!m_pLevel) return;
Entity* pEnt = m_pLevel->getEntity(pRemoveEntityPkt->m_id);
#if defined(ORIGINAL_CODE) || UINTPTR_MAX == UINT32_MAX
// @NOTE: On x64 systems, this won't print the right things.
printf_ignorable("RemoveEntityPacket %d %d", pEnt, m_pMinecraft->m_pLocalPlayer);
#else
printf_ignorable("RemoveEntityPacket %p %p", pEnt, m_pMinecraft->m_pLocalPlayer);
#endif
if (pEnt)
m_pLevel->removeEntity(pEnt);
}
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, MovePlayerPacket* packet)
{
if (!m_pLevel) return;
Entity* pEntity = m_pLevel->getEntity(packet->m_id);
if (!pEntity)
{
LogMsg("No player with id %d", packet->m_id);
return;
}
pEntity->lerpTo(packet->m_x, packet->m_y, packet->m_z, packet->m_yaw, packet->m_pitch, 3);
}
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, PlaceBlockPacket* pPlaceBlockPkt)
{
puts_ignorable("PlaceBlockPacket");
Player* pPlayer = (Player*)m_pLevel->getEntity(pPlaceBlockPkt->m_playerID);
if (!pPlayer)
{
LogMsg("No player with id %d", pPlaceBlockPkt->m_playerID);
return;
}
pPlayer->swing();
// @BUG: Not buffering the update.
if (!areAllChunksLoaded())
return;
int x = pPlaceBlockPkt->m_x;
int y = pPlaceBlockPkt->m_y;
int z = pPlaceBlockPkt->m_z;
int tile = pPlaceBlockPkt->m_tile;
int face = pPlaceBlockPkt->m_face;
if (!m_pLevel->mayPlace(tile, x, y, z, true))
return;
Tile* pTile = Tile::tiles[tile];
if (!m_pLevel->setTile(x, y, z, tile))
return;
Tile::tiles[tile]->setPlacedOnFace(m_pLevel, x, y, z, face);
Tile::tiles[tile]->setPlacedBy(m_pLevel, x, y, z, pPlayer);
const Tile::SoundType* pSound = pTile->m_pSound;
m_pLevel->playSound(float(x) + 0.5f, float(y) + 0.5f, float(z) + 0.5f, "step." + pSound->m_name, 0.5f * (1.0f + pSound->field_18), 0.8f * pSound->field_1C);
}
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, RemoveBlockPacket* pRemoveBlockPkt)
{
puts_ignorable("RemoveBlockPacket");
Player* pPlayer = (Player*)m_pLevel->getEntity(pRemoveBlockPkt->m_playerID);
if (!pPlayer)
{
LogMsg("No player with id %d", pRemoveBlockPkt->m_playerID);
return;
}
pPlayer->swing();
// @BUG: Not buffering the update.
if (!areAllChunksLoaded())
return;
int x = pRemoveBlockPkt->m_x;
int y = pRemoveBlockPkt->m_y;
int z = pRemoveBlockPkt->m_z;
Tile* pTile = Tile::tiles[m_pLevel->getTile(x, y, z)];
int data = m_pLevel->getData(x, y, z);
bool setTileResult = m_pLevel->setTile(x, y, z, TILE_AIR);
if (pTile && setTileResult)
{
const Tile::SoundType* pSound = pTile->m_pSound;
m_pLevel->playSound(float(x) + 0.5f, float(y) + 0.5f, float(z) + 0.5f, "step." + pSound->m_name, 0.5f * (1.0f + pSound->field_18), 0.8f * pSound->field_1C);
pTile->destroy(m_pLevel, x, y, z, data);
}
}
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, UpdateBlockPacket* pkt)
{
if (!areAllChunksLoaded())
{
m_bufferedBlockUpdates.push_back(SBufferedBlockUpdate(pkt->m_x, pkt->m_y, pkt->m_z, pkt->m_tile, pkt->m_data));
return;
}
m_pLevel->setTileAndData(pkt->m_x, pkt->m_y, pkt->m_z, pkt->m_tile, pkt->m_data);
}
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, ChunkDataPacket* pChunkDataPkt)
{
if (!m_pLevel)
{
puts("Level @ handle ChunkDataPacket is 0");
return;
}
LevelChunk* pChunk = m_pLevel->getChunkSource()->create(pChunkDataPkt->m_x, pChunkDataPkt->m_z);
if (!pChunk || pChunk->isEmpty())
{
puts("Failed to find write-able chunk");
// @BUG: Not trying again.
return;
}
int x16 = 16 * pChunkDataPkt->m_x;
int z16 = 16 * pChunkDataPkt->m_z;
bool updated = false;
int minY = 128, maxY = 0;
int minX = 16, minZ = 16;
int maxX = 0, maxZ = 0;
for (int k = 0; k < 256; k++)
{
uint8_t updMap;
pChunkDataPkt->m_data.Read(updMap);
if (!updMap)
continue;
for (int j = 0; j < 8; j++)
{
if ((updMap >> j) & 1)
{
int yPos = j * 16;
TileID tiles[16];
uint8_t datas[16 / 2];
pChunkDataPkt->m_data.Read((char*)tiles, 16 * sizeof(TileID));
pChunkDataPkt->m_data.Read((char*)datas, 16 / 2);
for (int i = 0; i < 16; i++)
{
m_pLevel->setTileNoUpdate(x16 + (k & 0xF), yPos + i, z16 + (k >> 4), tiles[i]);
}
int idx = ((k & 0xF) << 11) | ((k >> 4) << 7) + yPos;
memcpy(&pChunk->m_tileData[idx >> 1], datas, sizeof datas);
}
int ymin = 16 * (1 << j);
if (minY >= ymin)
minY = ymin;
if (maxY < ymin + 15)
maxY = ymin + 15;
}
if (minX >= (k & 0xF))
minX = k & 0xF;
if (minZ >= (k >> 4))
minZ = k >> 4;
if (maxX <= (k & 0xF))
maxX = k & 0xF;
if (maxZ <= (k >> 4))
maxZ = k >> 4;
updated = true;
}
if (updated)
m_pLevel->setTilesDirty(minX + x16, minY, minZ, maxX + x16, maxY, maxZ + z16);
pChunk->m_bUnsaved = true;
if (areAllChunksLoaded())
flushAllBufferedUpdates();
else
requestNextChunk();
}
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, PlayerEquipmentPacket* pPlayerEquipmentPkt)
{
Player* pPlayer = (Player*)m_pLevel->getEntity(pPlayerEquipmentPkt->m_playerID);
if (!pPlayer)
return;
#ifndef ORIGINAL_CODE
if (!Item::items[pPlayerEquipmentPkt->m_itemID])
{
LogMsg("That item %d doesn't actually exist!", pPlayerEquipmentPkt->m_itemID);
return;
}
#endif
if (pPlayer->m_guid == m_pServerPeer->GetMyGUID())
{
puts("Attempted to modify local player's inventory");
return;
}
pPlayer->m_pInventory->setSelectionSlotItemId(0, pPlayerEquipmentPkt->m_itemID);
pPlayer->m_pInventory->selectSlot(0);
}
bool ClientSideNetworkHandler::areAllChunksLoaded()
{
return m_chunksRequested > 255;
}
void ClientSideNetworkHandler::requestNextChunk()
{
if (areAllChunksLoaded())
return;
// @BUG: The return value of areAllChunksLoaded() is actually true even before the
// 256th chunk is loaded.
m_pRakNetInstance->send(new RequestChunkPacket(m_chunksRequested % 16, m_chunksRequested / 16));
m_chunksRequested++;
}
void ClientSideNetworkHandler::flushAllBufferedUpdates()
{
for (const SBufferedBlockUpdate& u : m_bufferedBlockUpdates)
{
m_pLevel->setTileAndData(u.x, u.y, u.z, u.tile, u.data);
}
}

View File

@@ -0,0 +1,53 @@
#pragma once
#include "NetEventCallback.hpp"
#include "Minecraft.hpp"
#include "RakNetInstance.hpp"
struct SBufferedBlockUpdate
{
int x, z;
uint8_t y;
uint8_t tile, data;
SBufferedBlockUpdate(int x, int y, int z, TileID tile, int data) :
x(x), y(uint8_t(y)), z(z), tile(uint8_t(tile)), data(uint8_t(data))
{}
};
class ClientSideNetworkHandler : public NetEventCallback
{
public:
ClientSideNetworkHandler(Minecraft*, RakNetInstance*);
void levelGenerated(Level*) override;
void onConnect(const RakNet::RakNetGUID&) override;
void onDisconnect(const RakNet::RakNetGUID&) override;
void onUnableToConnect() override;
void handle(const RakNet::RakNetGUID&, MessagePacket*) override;
void handle(const RakNet::RakNetGUID&, StartGamePacket*) override;
void handle(const RakNet::RakNetGUID&, AddPlayerPacket*) override;
void handle(const RakNet::RakNetGUID&, RemoveEntityPacket*) override;
void handle(const RakNet::RakNetGUID&, MovePlayerPacket*) override;
void handle(const RakNet::RakNetGUID&, PlaceBlockPacket*) override;
void handle(const RakNet::RakNetGUID&, RemoveBlockPacket*) override;
void handle(const RakNet::RakNetGUID&, UpdateBlockPacket*) override;
void handle(const RakNet::RakNetGUID&, ChunkDataPacket*) override;
void handle(const RakNet::RakNetGUID&, PlayerEquipmentPacket*) override;
bool areAllChunksLoaded();
void requestNextChunk();
void flushAllBufferedUpdates(); // inlined
private:
Minecraft* m_pMinecraft = NULL;
Level* m_pLevel = NULL;
RakNetInstance* m_pRakNetInstance = NULL;
RakNet::RakPeerInterface* m_pServerPeer = NULL;
int m_field_14;
RakNet::RakNetGUID m_serverGUID;
int m_field_24;
std::vector<SBufferedBlockUpdate> m_bufferedBlockUpdates;
int m_chunksRequested = 0;
};

View File

@@ -0,0 +1,34 @@
#include "MinecraftPackets.hpp"
Packet* MinecraftPackets::createPacket(int type)
{
switch (type)
{
case PACKET_LOGIN:
return new LoginPacket;
case PACKET_MESSAGE:
return new MessagePacket;
case PACKET_START_GAME:
return new StartGamePacket;
case PACKET_ADD_PLAYER:
return new AddPlayerPacket;
case PACKET_REMOVE_ENTITY:
return new RemoveEntityPacket;
case PACKET_MOVE_PLAYER:
return new MovePlayerPacket;
case PACKET_PLACE_BLOCK:
return new PlaceBlockPacket;
case PACKET_REMOVE_BLOCK:
return new RemoveBlockPacket;
case PACKET_UPDATE_BLOCK:
return new UpdateBlockPacket;
case PACKET_REQUEST_CHUNK:
return new RequestChunkPacket;
case PACKET_CHUNK_DATA:
return new ChunkDataPacket;
case PACKET_PLAYER_EQUIPMENT:
return new PlayerEquipmentPacket;
}
return nullptr;
}

View File

@@ -0,0 +1,10 @@
#pragma once
#include "Packet.hpp"
class MinecraftPackets
{
public:
static Packet* createPacket(int type);
};

View File

@@ -0,0 +1,70 @@
#include "NetEventCallback.hpp"
void NetEventCallback::levelGenerated(Level* level)
{
}
void NetEventCallback::onConnect(const RakNet::RakNetGUID& guid)
{
}
void NetEventCallback::onUnableToConnect()
{
}
void NetEventCallback::onNewClient(const RakNet::RakNetGUID& guid)
{
}
void NetEventCallback::onDisconnect(const RakNet::RakNetGUID& guid)
{
}
void NetEventCallback::handle(const RakNet::RakNetGUID& guid, LoginPacket* packet)
{
}
void NetEventCallback::handle(const RakNet::RakNetGUID& guid, MessagePacket* packet)
{
}
void NetEventCallback::handle(const RakNet::RakNetGUID& guid, StartGamePacket* packet)
{
}
void NetEventCallback::handle(const RakNet::RakNetGUID& guid, AddPlayerPacket* packet)
{
}
void NetEventCallback::handle(const RakNet::RakNetGUID& guid, RemoveEntityPacket* packet)
{
}
void NetEventCallback::handle(const RakNet::RakNetGUID& guid, MovePlayerPacket* packet)
{
}
void NetEventCallback::handle(const RakNet::RakNetGUID& guid, PlaceBlockPacket* packet)
{
}
void NetEventCallback::handle(const RakNet::RakNetGUID& guid, RemoveBlockPacket* packet)
{
}
void NetEventCallback::handle(const RakNet::RakNetGUID& guid, UpdateBlockPacket* packet)
{
}
void NetEventCallback::handle(const RakNet::RakNetGUID& guid, RequestChunkPacket* packet)
{
}
void NetEventCallback::handle(const RakNet::RakNetGUID& guid, ChunkDataPacket* packet)
{
}
void NetEventCallback::handle(const RakNet::RakNetGUID& guid, PlayerEquipmentPacket* packet)
{
}

View File

@@ -0,0 +1,43 @@
#pragma once
#include "RakNetTypes.h"
#include "Packet.hpp"
class Packet;
class LoginPacket;
class MessagePacket;
class StartGamePacket;
class AddPlayerPacket;
class RemoveEntityPacket;
class MovePlayerPacket;
class PlaceBlockPacket;
class RemoveBlockPacket;
class UpdateBlockPacket;
class RequestChunkPacket;
class ChunkDataPacket;
class PlayerEquipmentPacket;
#include "Level.hpp"
class Level;
class NetEventCallback
{
public:
virtual ~NetEventCallback() {}
virtual void levelGenerated(Level*);
virtual void onConnect(const RakNet::RakNetGUID&);
virtual void onUnableToConnect();
virtual void onNewClient(const RakNet::RakNetGUID&);
virtual void onDisconnect(const RakNet::RakNetGUID&);
virtual void handle(const RakNet::RakNetGUID&, LoginPacket*);
virtual void handle(const RakNet::RakNetGUID&, MessagePacket*);
virtual void handle(const RakNet::RakNetGUID&, StartGamePacket*);
virtual void handle(const RakNet::RakNetGUID&, AddPlayerPacket*);
virtual void handle(const RakNet::RakNetGUID&, RemoveEntityPacket*);
virtual void handle(const RakNet::RakNetGUID&, MovePlayerPacket*);
virtual void handle(const RakNet::RakNetGUID&, PlaceBlockPacket*);
virtual void handle(const RakNet::RakNetGUID&, RemoveBlockPacket*);
virtual void handle(const RakNet::RakNetGUID&, UpdateBlockPacket*);
virtual void handle(const RakNet::RakNetGUID&, RequestChunkPacket*);
virtual void handle(const RakNet::RakNetGUID&, ChunkDataPacket*);
virtual void handle(const RakNet::RakNetGUID&, PlayerEquipmentPacket*);
};

225
source/Network/Packet.hpp Normal file
View File

@@ -0,0 +1,225 @@
#pragma once
#include <string>
#include "RakNetTypes.h"
#include "BitStream.h"
#include "MessageIdentifiers.h"
#include "NetEventCallback.hpp"
class NetEventCallback;
class LevelChunk;
enum ePacketType : uint8_t
{
PACKET_LOGIN = ID_USER_PACKET_ENUM,
PACKET_MESSAGE,
PACKET_START_GAME,
PACKET_ADD_PLAYER,
PACKET_REMOVE_ENTITY,
PACKET_MOVE_PLAYER,
PACKET_PLACE_BLOCK,
PACKET_REMOVE_BLOCK,
PACKET_UPDATE_BLOCK,
PACKET_REQUEST_CHUNK,
PACKET_CHUNK_DATA,
PACKET_PLAYER_EQUIPMENT,
};
class Packet
{
public:
virtual ~Packet() {}
virtual void write(RakNet::BitStream*) = 0;
virtual void read(RakNet::BitStream*) = 0;
virtual void handle(const RakNet::RakNetGUID&, NetEventCallback*) = 0;
};
class LoginPacket : public Packet
{
public:
LoginPacket() {}
LoginPacket(const std::string& uname) { m_str = RakNet::RakString(uname.c_str()); }
void handle(const RakNet::RakNetGUID&, NetEventCallback* pCallback) override;
void write(RakNet::BitStream*);
void read(RakNet::BitStream*);
public:
RakNet::RakString m_str;
};
class MessagePacket : public Packet
{
public:
MessagePacket() {}
MessagePacket(const std::string& msg)
{
m_str = msg.c_str();
}
void handle(const RakNet::RakNetGUID&, NetEventCallback* pCallback) override;
void write(RakNet::BitStream*);
void read(RakNet::BitStream*);
public:
RakNet::RakString m_str;
};
class StartGamePacket : public Packet
{
public:
void handle(const RakNet::RakNetGUID&, NetEventCallback* pCallback) override;
void write(RakNet::BitStream*);
void read(RakNet::BitStream*);
public:
long field_4;
int field_8;
int field_C;
float field_10;
float field_14;
float field_18;
};
class AddPlayerPacket : public Packet
{
public:
AddPlayerPacket() {}
AddPlayerPacket(const RakNet::RakNetGUID& guid, RakNet::RakString name, int id, float x, float y, float z);
void handle(const RakNet::RakNetGUID&, NetEventCallback* pCallback) override;
void write(RakNet::BitStream*);
void read(RakNet::BitStream*);
public:
int field_4;
RakNet::RakNetGUID m_guid;
int field_14;
RakNet::RakString m_name;
int m_id;
float m_x;
float m_y;
float m_z;
};
class RemoveEntityPacket : public Packet
{
public:
RemoveEntityPacket() {}
RemoveEntityPacket(int id) { m_id = id; }
void handle(const RakNet::RakNetGUID&, NetEventCallback* pCallback) override;
void write(RakNet::BitStream*);
void read(RakNet::BitStream*);
public:
int m_id;
};
class MovePlayerPacket : public Packet
{
public:
MovePlayerPacket() {}
MovePlayerPacket(int id, float x, float y, float z, float pitch, float yaw): m_id(id), m_x(x), m_y(y), m_z(z), m_pitch(pitch), m_yaw(yaw) {}
void handle(const RakNet::RakNetGUID&, NetEventCallback* pCallback) override;
void write(RakNet::BitStream*);
void read(RakNet::BitStream*);
public:
int m_id;
float m_x;
float m_y;
float m_z;
float m_pitch;
float m_yaw;
};
class PlaceBlockPacket : public Packet
{
public:
PlaceBlockPacket() {}
PlaceBlockPacket(int playerID, int x, uint8_t y, int z, uint8_t tile, uint8_t face)
{
m_playerID = playerID;
m_x = x;
m_y = y;
m_z = z;
m_tile = tile;
m_face = face;
}
void handle(const RakNet::RakNetGUID&, NetEventCallback* pCallback) override;
void write(RakNet::BitStream*);
void read(RakNet::BitStream*);
public:
int m_playerID;
int m_x;
int m_z;
uint8_t m_y;
uint8_t m_tile;
uint8_t m_face;
};
class RemoveBlockPacket : public Packet
{
public:
RemoveBlockPacket() {}
RemoveBlockPacket(int id, int x, int y, int z) :m_playerID(id), m_x(x), m_y(uint8_t(y)), m_z(z) {}
void handle(const RakNet::RakNetGUID&, NetEventCallback* pCallback) override;
void write(RakNet::BitStream*);
void read(RakNet::BitStream*);
public:
int m_playerID;
int m_x;
int m_z;
uint8_t m_y;
};
class UpdateBlockPacket : public Packet
{
public:
void handle(const RakNet::RakNetGUID&, NetEventCallback* pCallback) override;
void write(RakNet::BitStream*);
void read(RakNet::BitStream*);
public:
int m_x;
int m_z;
uint8_t m_y;
uint8_t m_tile;
uint8_t m_data;
};
class RequestChunkPacket : public Packet
{
public:
RequestChunkPacket() {}
RequestChunkPacket(int x, int z) { m_x = x; m_z = z; }
void handle(const RakNet::RakNetGUID&, NetEventCallback* pCallback) override;
void write(RakNet::BitStream*);
void read(RakNet::BitStream*);
public:
int m_x;
int m_z;
};
class ChunkDataPacket : public Packet
{
public:
ChunkDataPacket() {}
ChunkDataPacket(int x, int z, LevelChunk* c) :m_x(x), m_z(z), m_pChunk(c) {}
void handle(const RakNet::RakNetGUID&, NetEventCallback* pCallback) override;
void write(RakNet::BitStream*);
void read(RakNet::BitStream*);
public:
int m_x;
int m_z;
RakNet::BitStream m_data;
LevelChunk* m_pChunk;
};
class PlayerEquipmentPacket : public Packet
{
public:
PlayerEquipmentPacket() {}
PlayerEquipmentPacket(int playerID, int itemID): m_playerID(playerID), m_itemID(itemID) {}
void handle(const RakNet::RakNetGUID&, NetEventCallback* pCallback) override;
void write(RakNet::BitStream*);
void read(RakNet::BitStream*);
public:
int m_playerID;
uint8_t m_itemID;
};

View File

@@ -0,0 +1,37 @@
#include "Packet.hpp"
AddPlayerPacket::AddPlayerPacket(const RakNet::RakNetGUID& guid, RakNet::RakString name, int id, float x, float y, float z)
{
m_guid = guid;
m_name = name;
m_id = id;
m_x = x;
m_y = y;
m_z = z;
}
void AddPlayerPacket::handle(const RakNet::RakNetGUID& guid, NetEventCallback* pCallback)
{
pCallback->handle(guid, this);
}
void AddPlayerPacket::write(RakNet::BitStream* bs)
{
bs->Write(PACKET_ADD_PLAYER);
bs->Write(m_guid);
bs->Write(m_name);
bs->Write(m_id);
bs->Write(m_x);
bs->Write(m_y);
bs->Write(m_z);
}
void AddPlayerPacket::read(RakNet::BitStream* bs)
{
bs->Read(m_guid);
bs->Read(m_name);
bs->Read(m_id);
bs->Read(m_x);
bs->Read(m_y);
bs->Read(m_z);
}

View File

@@ -0,0 +1,47 @@
#include "Packet.hpp"
#include "LevelChunk.hpp"
void ChunkDataPacket::handle(const RakNet::RakNetGUID& guid, NetEventCallback* pCallback)
{
pCallback->handle(guid, this);
}
void ChunkDataPacket::write(RakNet::BitStream* bs)
{
bs->Write(PACKET_CHUNK_DATA);
bs->Write(m_x);
bs->Write(m_z);
// Well, we first have to prepare the data.
m_data.Reset();
for (int i = 0; i < 256; i++)
{
m_data.Write(m_pChunk->m_updateMap[i]);
// if nothing was updated:
if (!m_pChunk->m_updateMap[i])
continue;
for (int y = 0; y < 8; y++)
{
if ((m_pChunk->m_updateMap[i] >> y) & 1)
{
int idx = ((i & 0xF) << 11) | ((i >> 4) << 7) + (y * 16);
//write the tile data
m_data.Write((const char*) &m_pChunk->m_pBlockData[idx], 16 * sizeof(TileID));
m_data.Write((const char*) &m_pChunk->m_tileData [idx >> 1], 8);
}
}
}
bs->Write(m_data);
}
void ChunkDataPacket::read(RakNet::BitStream* bs)
{
bs->Read(m_x);
bs->Read(m_z);
bs->Read(m_data);
}

View File

@@ -0,0 +1,17 @@
#include "Packet.hpp"
void LoginPacket::handle(const RakNet::RakNetGUID& guid, NetEventCallback* pCallback)
{
pCallback->handle(guid, this);
}
void LoginPacket::write(RakNet::BitStream* bs)
{
bs->Write(PACKET_LOGIN);
bs->Write(m_str);
}
void LoginPacket::read(RakNet::BitStream* bs)
{
bs->Read(m_str);
}

View File

@@ -0,0 +1,17 @@
#include "Packet.hpp"
void MessagePacket::handle(const RakNet::RakNetGUID& guid, NetEventCallback* pCallback)
{
pCallback->handle(guid, this);
}
void MessagePacket::write(RakNet::BitStream* bs)
{
bs->Write(PACKET_MESSAGE);
bs->Write(m_str);
}
void MessagePacket::read(RakNet::BitStream* bs)
{
bs->Read(m_str);
}

View File

@@ -0,0 +1,27 @@
#include "Packet.hpp"
void MovePlayerPacket::handle(const RakNet::RakNetGUID& guid, NetEventCallback* pCallback)
{
pCallback->handle(guid, this);
}
void MovePlayerPacket::write(RakNet::BitStream* bs)
{
bs->Write(PACKET_MOVE_PLAYER);
bs->Write(m_id);
bs->Write(m_x);
bs->Write(m_y);
bs->Write(m_z);
bs->Write(m_pitch);
bs->Write(m_yaw);
}
void MovePlayerPacket::read(RakNet::BitStream* bs)
{
bs->Read(m_id);
bs->Read(m_x);
bs->Read(m_y);
bs->Read(m_z);
bs->Read(m_pitch);
bs->Read(m_yaw);
}

View File

@@ -0,0 +1,27 @@
#include "Packet.hpp"
void PlaceBlockPacket::handle(const RakNet::RakNetGUID& guid, NetEventCallback* pCallback)
{
pCallback->handle(guid, this);
}
void PlaceBlockPacket::write(RakNet::BitStream* bs)
{
bs->Write(PACKET_PLACE_BLOCK);
bs->Write(m_playerID);
bs->Write(m_x);
bs->Write(m_z);
bs->Write(m_y);
bs->Write(m_tile);
bs->Write(m_face);
}
void PlaceBlockPacket::read(RakNet::BitStream* bs)
{
bs->Read(m_playerID);
bs->Read(m_x);
bs->Read(m_z);
bs->Read(m_y);
bs->Read(m_tile);
bs->Read(m_face);
}

View File

@@ -0,0 +1,19 @@
#include "Packet.hpp"
void PlayerEquipmentPacket::handle(const RakNet::RakNetGUID& guid, NetEventCallback* pCallback)
{
pCallback->handle(guid, this);
}
void PlayerEquipmentPacket::write(RakNet::BitStream* bs)
{
bs->Write(PACKET_PLAYER_EQUIPMENT);
bs->Write(m_playerID);
bs->Write(m_itemID);
}
void PlayerEquipmentPacket::read(RakNet::BitStream* bs)
{
bs->Read(m_playerID);
bs->Read(m_itemID);
}

View File

@@ -0,0 +1,23 @@
#include "Packet.hpp"
void RemoveBlockPacket::handle(const RakNet::RakNetGUID& guid, NetEventCallback* pCallback)
{
pCallback->handle(guid, this);
}
void RemoveBlockPacket::write(RakNet::BitStream* bs)
{
bs->Write(PACKET_REMOVE_BLOCK);
bs->Write(m_playerID);
bs->Write(m_x);
bs->Write(m_z);
bs->Write(m_y);
}
void RemoveBlockPacket::read(RakNet::BitStream* bs)
{
bs->Read(m_playerID);
bs->Read(m_x);
bs->Read(m_z);
bs->Read(m_y);
}

View File

@@ -0,0 +1,17 @@
#include "Packet.hpp"
void RemoveEntityPacket::handle(const RakNet::RakNetGUID& guid, NetEventCallback* pCallback)
{
pCallback->handle(guid, this);
}
void RemoveEntityPacket::write(RakNet::BitStream* bs)
{
bs->Write(PACKET_REMOVE_ENTITY);
bs->Write(m_id);
}
void RemoveEntityPacket::read(RakNet::BitStream* bs)
{
bs->Read(m_id);
}

View File

@@ -0,0 +1,19 @@
#include "Packet.hpp"
void RequestChunkPacket::handle(const RakNet::RakNetGUID& guid, NetEventCallback* pCallback)
{
pCallback->handle(guid, this);
}
void RequestChunkPacket::write(RakNet::BitStream* bs)
{
bs->Write(PACKET_REQUEST_CHUNK);
bs->Write(m_x);
bs->Write(m_z);
}
void RequestChunkPacket::read(RakNet::BitStream* bs)
{
bs->Read(m_x);
bs->Read(m_z);
}

View File

@@ -0,0 +1,27 @@
#include "Packet.hpp"
void StartGamePacket::handle(const RakNet::RakNetGUID& guid, NetEventCallback* pCallback)
{
pCallback->handle(guid, this);
}
void StartGamePacket::write(RakNet::BitStream* bs)
{
bs->Write(PACKET_START_GAME);
bs->Write(field_4);
bs->Write(field_8);
bs->Write(field_C);
bs->Write(field_10);
bs->Write(field_14);
bs->Write(field_18);
}
void StartGamePacket::read(RakNet::BitStream* bs)
{
bs->Read(field_4);
bs->Read(field_8);
bs->Read(field_C);
bs->Read(field_10);
bs->Read(field_14);
bs->Read(field_18);
}

View File

@@ -0,0 +1,25 @@
#include "Packet.hpp"
void UpdateBlockPacket::handle(const RakNet::RakNetGUID& guid, NetEventCallback* pCallback)
{
pCallback->handle(guid, this);
}
void UpdateBlockPacket::write(RakNet::BitStream* bs)
{
bs->Write(PACKET_UPDATE_BLOCK);
bs->Write(m_x);
bs->Write(m_z);
bs->Write(m_y);
bs->Write(m_tile);
bs->Write(m_data);
}
void UpdateBlockPacket::read(RakNet::BitStream* bs)
{
bs->Read(m_x);
bs->Read(m_z);
bs->Read(m_y);
bs->Read(m_tile);
bs->Read(m_data);
}

View File

@@ -0,0 +1,13 @@
#pragma once
#include <string>
#include "RakNetTypes.h"
#include "RakString.h"
struct PingedCompatibleServer
{
RakNet::RakString m_name;
RakNet::SystemAddress m_address;
int m_lastPinged;
};

View File

@@ -0,0 +1,268 @@
#include "RakNetInstance.hpp"
#include "MinecraftPackets.hpp"
#include "GetTime.h"
RakNetInstance::RakNetInstance()
{
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;
return m_pRakPeerInterface->Connect(host, port, nullptr, 0);
}
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;
int packetType = *pPacket->data;
RakNet::BitStream* pBitStream = new RakNet::BitStream(pPacket->data + 1, pPacket->length - 1, 0);
// @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 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 (PingedCompatibleServer& server : m_servers)
{
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;
}
}
m_pRakPeerInterface->DeallocatePacket(pPacket);
if (pBitStream)
delete pBitStream;
}
if (m_bPingingForHosts)
{
int timeDiff = RakNet::GetTimeMS() - m_startedPingingAt;
if (timeDiff > 1000)
{
for (auto 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);
if (m_bIsHost)
{
m_pRakPeerInterface->Send(&bs, HIGH_PRIORITY, RELIABLE, 0, RakNet::AddressOrGUID(), true);
}
else
{
// send it to the host instead
m_pRakPeerInterface->Send(&bs, HIGH_PRIORITY, RELIABLE, 0, m_guid, false);
}
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, true);
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;
}

View File

@@ -0,0 +1,42 @@
#pragma once
#include <string>
#include <vector>
#include "PingedCompatibleServer.hpp"
#include "BitStream.h"
#include "RakPeerInterface.h"
#include "Packet.hpp"
class Packet;
class RakNetInstance
{
public:
RakNetInstance();
~RakNetInstance();
void announceServer(const std::string& name);
void clearServerList();
bool connect(const char* host, int port);
void disconnect();
RakNet::RakPeerInterface* getPeer();
std::vector<PingedCompatibleServer>* getServerList();
bool host(const std::string& name, int port, int maxConnections);
bool isMyLocalGuid(const RakNet::RakNetGUID& guid);
void pingForHosts(int port);
void runEvents(NetEventCallback*);
void send(Packet* packet);
void send(const RakNet::RakNetGUID& guid, Packet* packet);
void stopPingForHosts();
public:
RakNet::RakPeerInterface* m_pRakPeerInterface = nullptr;
bool m_bIsHost = false;
int field_C;
RakNet::RakNetGUID m_guid;
int field_1C;
std::vector<PingedCompatibleServer> m_servers;
bool m_bPingingForHosts;
int m_hostPingPort;
int m_startedPingingAt;
};

View File

@@ -0,0 +1,270 @@
#include "ServerSideNetworkHandler.hpp"
// This lets you make the server shut up and not log events in the debug console.
#define VERBOSE_SERVER
#if defined(ORIGINAL_CODE) || defined(VERBOSE_SERVER)
#define puts_ignorable(str) puts(str)
#define printf_ignorable(str, ...) printf(str, __VA_ARGS__)
#else
#define puts_ignorable(str)
#define printf_ignorable(str, ...)
#endif
ServerSideNetworkHandler::ServerSideNetworkHandler(Minecraft* minecraft, RakNetInstance* rakNetInstance)
{
m_pMinecraft = minecraft;
m_pRakNetInstance = rakNetInstance;
allowIncomingConnections(false);
m_pRakNetPeer = m_pRakNetInstance->getPeer();
}
ServerSideNetworkHandler::~ServerSideNetworkHandler()
{
if (m_pLevel)
m_pLevel->removeListener(this);
}
void ServerSideNetworkHandler::levelGenerated(Level* level)
{
m_pLevel = level;
if (m_pMinecraft->m_pLocalPlayer)
{
m_pMinecraft->m_pLocalPlayer->m_guid = m_pRakNetPeer->GetMyGUID();
}
level->addListener(this);
allowIncomingConnections(m_pMinecraft->m_options.m_bServerVisibleDefault);
}
void ServerSideNetworkHandler::onNewClient(const RakNet::RakNetGUID& guid)
{
printf_ignorable("onNewClient, client guid: %s\n", guid.ToString());
}
void ServerSideNetworkHandler::onDisconnect(const RakNet::RakNetGUID& guid)
{
puts_ignorable("onDisconnect");
for (Player* pPlayer : m_pLevel->m_players)
{
if (pPlayer->m_guid != guid)
continue;
displayGameMessage(pPlayer->m_name + " disconnected from the game");
m_pRakNetInstance->send(new RemoveEntityPacket(pPlayer->m_EntityID));
m_pLevel->removeEntity(pPlayer);
}
}
void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& guid, LoginPacket* packet)
{
if (!m_bAllowIncoming)
return;
puts_ignorable("LoginPacket");
Player* pPlayer = new Player(m_pLevel);
pPlayer->m_guid = guid;
pPlayer->m_name = std::string(packet->m_str.C_String());
StartGamePacket sgp;
sgp.field_4 = m_pLevel->getSeed();
sgp.field_8 = m_pLevel->getLevelData()->field_20;
sgp.field_C = pPlayer->m_EntityID;
sgp.field_10 = pPlayer->m_pos.x;
sgp.field_14 = pPlayer->m_pos.y - pPlayer->field_84;
sgp.field_18 = pPlayer->m_pos.z;
RakNet::BitStream sgpbs;
sgp.write(&sgpbs);
m_pRakNetPeer->Send(&sgpbs, HIGH_PRIORITY, RELIABLE_ORDERED, 0, guid, false);
// send the connecting player info about all other players in the world
for (Player* player : m_pLevel->m_players)
{
AddPlayerPacket app(player->m_guid, RakNet::RakString(player->m_name.c_str()), player->m_EntityID, player->m_pos.x, player->m_pos.y - player->field_84, player->m_pos.z);
RakNet::BitStream appbs;
app.write(&appbs);
m_pRakNetPeer->Send(&appbs, HIGH_PRIORITY, RELIABLE_ORDERED, 0, guid, false);
}
m_pLevel->addEntity(pPlayer);
m_pMinecraft->m_gui.addMessage(pPlayer->m_name + " joined the game");
AddPlayerPacket app(guid, RakNet::RakString(pPlayer->m_name.c_str()), pPlayer->m_EntityID, pPlayer->m_pos.x, pPlayer->m_pos.y - pPlayer->field_84, pPlayer->m_pos.z);
RakNet::BitStream appbs;
app.write(&appbs);
m_pRakNetPeer->Send(&appbs, HIGH_PRIORITY, RELIABLE_ORDERED, 0, guid, true);
}
void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& guid, MovePlayerPacket* packet)
{
//not in the original
puts_ignorable("MovePlayerPacket");
Entity* pEntity = m_pLevel->getEntity(packet->m_id);
if (pEntity)
pEntity->lerpTo(packet->m_x, packet->m_y, packet->m_z, packet->m_yaw, packet->m_pitch, 3);
redistributePacket(packet, guid);
}
void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& guid, PlaceBlockPacket* packet)
{
puts_ignorable("PlaceBlockPacket");
Mob* pMob = (Mob*)m_pLevel->getEntity(packet->m_playerID);
if (!pMob)
return;
TileID tile = packet->m_tile;
int face = packet->m_face;
int x = packet->m_x;
int y = packet->m_y;
int z = packet->m_z;
if (!m_pLevel->mayPlace(tile, x, y, z, true))
return;
if (m_pLevel->setTile(x, y, z, tile))
{
Tile::tiles[tile]->setPlacedOnFace(m_pLevel, x, y, z, face);
Tile::tiles[tile]->setPlacedBy(m_pLevel, x, y, z, pMob);
const Tile::SoundType* pSound = Tile::tiles[tile]->m_pSound;
m_pLevel->playSound(float(x) + 0.5f, float(y) + 0.5f, float(z) + 0.5f, "step." + pSound->m_name, 0.5f * (pSound->field_18 + 1.0f), pSound->field_1C * 0.8f);
}
redistributePacket(packet, guid);
}
void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& guid, RemoveBlockPacket* packet)
{
puts_ignorable("RemoveBlockPacket");
Player* pPlayer = (Player*)m_pLevel->getEntity(packet->m_playerID);
if (!pPlayer)
return;
int x = packet->m_x;
int y = packet->m_y;
int z = packet->m_z;
Tile* pTile = Tile::tiles[m_pLevel->getTile(x, y, z)];
int data = m_pLevel->getData(x, y, z);
bool setTileResult = m_pLevel->setTile(x, y, z, TILE_AIR);
if (pTile && setTileResult)
{
const Tile::SoundType* pSound = pTile->m_pSound;
m_pMinecraft->m_pSoundEngine->play("step." + pSound->m_name, float(x) + 0.5f, float(y) + 0.5f, float(z) + 0.5f, 0.5f * (pSound->field_18 + 1.0f), pSound->field_1C * 0.8f);
// redistribute the packet only if needed
redistributePacket(packet, guid);
}
}
void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& guid, PlayerEquipmentPacket* packet)
{
Player* pPlayer = (Player*)m_pLevel->getEntity(packet->m_playerID);
if (!pPlayer)
{
LogMsg("No player with id %d", packet->m_playerID);
return;
}
#ifndef ORIGINAL_CODE
if (!Item::items[packet->m_itemID])
{
LogMsg("That item %d doesn't actually exist!", packet->m_itemID);
return;
}
#endif
if (pPlayer->m_guid == m_pRakNetPeer->GetMyGUID())
{
puts("Attempted to modify local player's inventory");
return;
}
pPlayer->m_pInventory->setSelectionSlotItemId(0, packet->m_itemID);
pPlayer->m_pInventory->selectSlot(0);
redistributePacket(packet, guid);
}
void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& guid, RequestChunkPacket* packet)
{
puts_ignorable("RequestChunkPacket");
LevelChunk* pChunk = m_pLevel->getChunk(packet->m_x, packet->m_z);
if (!pChunk)
{
LogMsg("No chunk at %d, %d", packet->m_x, packet->m_z);
return;
}
// @NOTE: this allows the client to request empty chunks. Is that okay?
ChunkDataPacket cdp(pChunk->m_chunkX, pChunk->m_chunkZ, pChunk);
RakNet::BitStream bs;
cdp.write(&bs);
m_pRakNetPeer->Send(&bs, HIGH_PRIORITY, RELIABLE_ORDERED, 0, guid, false);
}
void ServerSideNetworkHandler::tileBrightnessChanged(int x, int y, int z)
{
}
void ServerSideNetworkHandler::tileChanged(int x, int y, int z)
{
UpdateBlockPacket ubp;
int tile = m_pLevel->getTile(x, y, z);
int data = m_pLevel->getData(x, y, z);
ubp.m_x = x;
ubp.m_y = y;
ubp.m_z = z;
ubp.m_tile = uint8_t(tile);
ubp.m_data = uint8_t(data);
RakNet::BitStream bs;
ubp.write(&bs);
m_pRakNetPeer->Send(&bs, HIGH_PRIORITY, RELIABLE_ORDERED, 0, RakNet::AddressOrGUID(), true);
}
void ServerSideNetworkHandler::allowIncomingConnections(bool b)
{
if (b)
{
m_pRakNetInstance->announceServer(m_pMinecraft->m_options.m_playerName);
}
else
{
m_pRakNetInstance->announceServer("");
}
m_bAllowIncoming = b;
}
void ServerSideNetworkHandler::displayGameMessage(const std::string& msg)
{
m_pMinecraft->m_gui.addMessage(msg);
m_pRakNetInstance->send(new MessagePacket(msg));
}
void ServerSideNetworkHandler::redistributePacket(Packet* packet, const RakNet::RakNetGUID& source)
{
RakNet::BitStream bs;
packet->write(&bs);
m_pRakNetPeer->Send(&bs, HIGH_PRIORITY, RELIABLE_ORDERED, 0, source, true);
}

View File

@@ -0,0 +1,41 @@
#pragma once
#include "NetEventCallback.hpp"
#include "Minecraft.hpp"
#include "RakNetInstance.hpp"
#include "LevelListener.hpp"
class Minecraft;
class ServerSideNetworkHandler : public NetEventCallback, public LevelListener
{
public:
ServerSideNetworkHandler(Minecraft*, RakNetInstance*);
~ServerSideNetworkHandler();
// Overridden from NetEventCallback
void levelGenerated(Level*) override;
void onNewClient(const RakNet::RakNetGUID&) override;
void onDisconnect(const RakNet::RakNetGUID&) override;
void handle(const RakNet::RakNetGUID&, LoginPacket*) override;
void handle(const RakNet::RakNetGUID&, MovePlayerPacket*) override;
void handle(const RakNet::RakNetGUID&, PlaceBlockPacket*) override;
void handle(const RakNet::RakNetGUID&, RemoveBlockPacket*) override;
void handle(const RakNet::RakNetGUID&, PlayerEquipmentPacket*) override;
void handle(const RakNet::RakNetGUID&, RequestChunkPacket*) override;
// Overridden from LevelListener
void tileBrightnessChanged(int x, int y, int z) override;
void tileChanged(int x, int y, int z) override;
void allowIncomingConnections(bool b);
void displayGameMessage(const std::string&);
void redistributePacket(Packet* packet, const RakNet::RakNetGUID& source);
public:
Minecraft* m_pMinecraft = nullptr;
Level* m_pLevel = nullptr;
RakNetInstance* m_pRakNetInstance = nullptr;
RakNet::RakPeerInterface* m_pRakNetPeer = nullptr;
bool m_bAllowIncoming = false;
};