1
0

Add support for 1.12.1 (#3908)

This commit is contained in:
Bond-009 2017-08-17 16:25:53 +02:00 committed by Mattes D
parent 7bdbfad1bb
commit 238f5bb338
5 changed files with 836 additions and 13 deletions

View File

@ -5,7 +5,7 @@ Cuberite is a Minecraft-compatible multiplayer game server that is written in C+
Cuberite can run on Windows, *nix and Android operating systems. This includes Android phones and tablets as well as Raspberry Pis. Cuberite can run on Windows, *nix and Android operating systems. This includes Android phones and tablets as well as Raspberry Pis.
We currently support Release 1.8 - 1.12 Minecraft protocol versions. We currently support Release 1.8 - 1.12.1 Minecraft protocol versions.
Subscribe to [the newsletter](https://cuberite.org/news/#subscribe) for important updates and project news. Subscribe to [the newsletter](https://cuberite.org/news/#subscribe) for important updates and project news.
@ -15,18 +15,21 @@ Installation
There are several ways to obtain Cuberite. There are several ways to obtain Cuberite.
#### Binaries #### Binaries
- The easiest method is downloading for Windows or Linux from the [Project site](https://cuberite.org/).
- You can use the EasyInstall script for Linux and macOS, which automatically downloads the correct binary. The script is described below. - The easiest method is downloading for Windows or Linux from the [Project site](https://cuberite.org/).
- You can also obtain a binary from the [buildserver archive](https://builds.cuberite.org/). - You can use the EasyInstall script for Linux and macOS, which automatically downloads the correct binary. The script is described below.
- You can also obtain a binary from the [buildserver archive](https://builds.cuberite.org/).
##### The EasyInstall script ##### The EasyInstall script
This script will download the correct binary from the project site. This script will download the correct binary from the project site.
curl -sSfL https://download.cuberite.org | sh curl -sSfL https://download.cuberite.org | sh
#### Compiling #### Compiling
- You can compile automatically for Linux / *nix with the `compile.sh` script. The script is described below.
- You can also compile manually. See [COMPILING.md](https://github.com/cuberite/cuberite/blob/master/COMPILING.md). - You can compile automatically for Linux / *nix with the `compile.sh` script. The script is described below.
- You can also compile manually. See [COMPILING.md](https://github.com/cuberite/cuberite/blob/master/COMPILING.md).
Compiling may provide better performance (1.5-3x as fast) and it supports more operating systems. Compiling may provide better performance (1.5-3x as fast) and it supports more operating systems.
@ -36,7 +39,8 @@ This script downloads the source code and compiles it. The script is smart enoug
sh -c "$(wget -O - https://compile.cuberite.org)" sh -c "$(wget -O - https://compile.cuberite.org)"
#### Hosted services #### Hosted services
- Hosted Cuberite is available via [Gamocosm](https://gamocosm.com/).
- Hosted Cuberite is available via [Gamocosm](https://gamocosm.com/).
Contributing Contributing
------------ ------------

View File

@ -59,6 +59,7 @@ AString cProtocolRecognizer::GetVersionTextFromInt(int a_ProtocolVersion)
case PROTO_VERSION_1_11_0: return "1.11"; case PROTO_VERSION_1_11_0: return "1.11";
case PROTO_VERSION_1_11_1: return "1.11.1"; case PROTO_VERSION_1_11_1: return "1.11.1";
case PROTO_VERSION_1_12: return "1.12"; case PROTO_VERSION_1_12: return "1.12";
case PROTO_VERSION_1_12_1: return "1.12.1";
} }
ASSERT(!"Unknown protocol version"); ASSERT(!"Unknown protocol version");
return Printf("Unknown protocol (%d)", a_ProtocolVersion); return Printf("Unknown protocol (%d)", a_ProtocolVersion);
@ -1107,6 +1108,11 @@ bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRema
m_Protocol = new cProtocol_1_12(m_Client, ServerAddress, ServerPort, NextState); m_Protocol = new cProtocol_1_12(m_Client, ServerAddress, ServerPort, NextState);
return true; return true;
} }
case PROTO_VERSION_1_12_1:
{
m_Protocol = new cProtocol_1_12_1(m_Client, ServerAddress, ServerPort, NextState);
return true;
}
default: default:
{ {
LOGD("Client \"%s\" uses an unsupported protocol (lengthed, version %u (0x%x))", LOGD("Client \"%s\" uses an unsupported protocol (lengthed, version %u (0x%x))",

View File

@ -18,9 +18,9 @@
// Adjust these if a new protocol is added or an old one is removed: // Adjust these if a new protocol is added or an old one is removed:
#define MCS_CLIENT_VERSIONS "1.8.x, 1.9.x, 1.10.x, 1.11.x, 1.12" #define MCS_CLIENT_VERSIONS "1.8.x, 1.9.x, 1.10.x, 1.11.x, 1.12.x"
#define MCS_PROTOCOL_VERSIONS "47, 107, 108, 109, 110, 210, 315, 316, 335" #define MCS_PROTOCOL_VERSIONS "47, 107, 108, 109, 110, 210, 315, 316, 335, 338"
#define MCS_LATEST_PROTOCOL_VERSION 335 #define MCS_LATEST_PROTOCOL_VERSION 338
@ -43,6 +43,7 @@ public:
PROTO_VERSION_1_11_0 = 315, PROTO_VERSION_1_11_0 = 315,
PROTO_VERSION_1_11_1 = 316, PROTO_VERSION_1_11_1 = 316,
PROTO_VERSION_1_12 = 335, PROTO_VERSION_1_12 = 335,
PROTO_VERSION_1_12_1 = 338,
} ; } ;
cProtocolRecognizer(cClientHandle * a_Client); cProtocolRecognizer(cClientHandle * a_Client);

View File

@ -1164,7 +1164,7 @@ void cProtocol_1_12::SendExperience(void)
{ {
ASSERT(m_State == 3); // In game mode? ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x3f); // Experience Packet cPacketizer Pkt(*this, 0x3f); // Set Experience Packet
cPlayer * Player = m_Client->GetPlayer(); cPlayer * Player = m_Client->GetPlayer();
Pkt.WriteBEFloat(Player->GetXpPercentage()); Pkt.WriteBEFloat(Player->GetXpPercentage());
Pkt.WriteVarInt32(static_cast<UInt32>(Player->GetXpLevel())); Pkt.WriteVarInt32(static_cast<UInt32>(Player->GetXpLevel()));
@ -1211,7 +1211,7 @@ void cProtocol_1_12::SendScoreboardObjective(const AString & a_Name, const AStri
void cProtocol_1_12::SendAttachEntity(const cEntity & a_Entity, const cEntity & a_Vehicle) void cProtocol_1_12::SendAttachEntity(const cEntity & a_Entity, const cEntity & a_Vehicle)
{ {
ASSERT(m_State == 3); // In game mode? ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x42); // Set passangers packet cPacketizer Pkt(*this, 0x42); // Set Passengers packet
Pkt.WriteVarInt32(a_Vehicle.GetUniqueID()); Pkt.WriteVarInt32(a_Vehicle.GetUniqueID());
Pkt.WriteVarInt32(1); // 1 passenger Pkt.WriteVarInt32(1); // 1 passenger
Pkt.WriteVarInt32(a_Entity.GetUniqueID()); Pkt.WriteVarInt32(a_Entity.GetUniqueID());
@ -1224,7 +1224,7 @@ void cProtocol_1_12::SendAttachEntity(const cEntity & a_Entity, const cEntity &
void cProtocol_1_12::SendDetachEntity(const cEntity & a_Entity, const cEntity & a_PreviousVehicle) void cProtocol_1_12::SendDetachEntity(const cEntity & a_Entity, const cEntity & a_PreviousVehicle)
{ {
ASSERT(m_State == 3); // In game mode? ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x42); // Set passangers packet cPacketizer Pkt(*this, 0x42); // Set Passengers packet
Pkt.WriteVarInt32(a_PreviousVehicle.GetUniqueID()); Pkt.WriteVarInt32(a_PreviousVehicle.GetUniqueID());
Pkt.WriteVarInt32(0); // No passangers Pkt.WriteVarInt32(0); // No passangers
} }
@ -1600,3 +1600,756 @@ bool cProtocol_1_12::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketTyp
m_Client->PacketUnknown(a_PacketType); m_Client->PacketUnknown(a_PacketType);
return false; return false;
} }
cProtocol_1_12_1::cProtocol_1_12_1(cClientHandle * a_Client, const AString & a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State) :
super(a_Client, a_ServerAddress, a_ServerPort, a_State)
{
}
void cProtocol_1_12_1::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer)
{
cServer * Server = cRoot::Get()->GetServer();
AString ServerDescription = Server->GetDescription();
auto NumPlayers = static_cast<signed>(Server->GetNumPlayers());
auto MaxPlayers = static_cast<signed>(Server->GetMaxPlayers());
AString Favicon = Server->GetFaviconData();
cRoot::Get()->GetPluginManager()->CallHookServerPing(*m_Client, ServerDescription, NumPlayers, MaxPlayers, Favicon);
// Version:
Json::Value Version;
Version["name"] = "Cuberite 1.12.1";
Version["protocol"] = cProtocolRecognizer::PROTO_VERSION_1_12_1;
// Players:
Json::Value Players;
Players["online"] = NumPlayers;
Players["max"] = MaxPlayers;
// TODO: Add "sample"
// Description:
Json::Value Description;
Description["text"] = ServerDescription.c_str();
// Create the response:
Json::Value ResponseValue;
ResponseValue["version"] = Version;
ResponseValue["players"] = Players;
ResponseValue["description"] = Description;
if (!Favicon.empty())
{
ResponseValue["favicon"] = Printf("data:image/png;base64,%s", Favicon.c_str());
}
// Serialize the response into a packet:
Json::FastWriter Writer;
cPacketizer Pkt(*this, 0x00); // Response packet
Pkt.WriteString(Writer.write(ResponseValue));
}
void cProtocol_1_12_1::SendRespawn(eDimension a_Dimension)
{
cPacketizer Pkt(*this, 0x35); // Respawn packet
cPlayer * Player = m_Client->GetPlayer();
Pkt.WriteBEInt32(static_cast<Int32>(a_Dimension));
Pkt.WriteBEUInt8(2); // TODO: Difficulty (set to Normal)
Pkt.WriteBEUInt8(static_cast<Byte>(Player->GetEffectiveGameMode()));
Pkt.WriteString("default");
}
void cProtocol_1_12_1::SendPlayerListAddPlayer(const cPlayer & a_Player)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x2e); // Player List Item packet
Pkt.WriteVarInt32(0);
Pkt.WriteVarInt32(1);
Pkt.WriteUUID(a_Player.GetUUID());
Pkt.WriteString(a_Player.GetPlayerListName());
const Json::Value & Properties = a_Player.GetClientHandle()->GetProperties();
Pkt.WriteVarInt32(Properties.size());
for (auto & Node : Properties)
{
Pkt.WriteString(Node.get("name", "").asString());
Pkt.WriteString(Node.get("value", "").asString());
AString Signature = Node.get("signature", "").asString();
if (Signature.empty())
{
Pkt.WriteBool(false);
}
else
{
Pkt.WriteBool(true);
Pkt.WriteString(Signature);
}
}
Pkt.WriteVarInt32(static_cast<UInt32>(a_Player.GetGameMode()));
Pkt.WriteVarInt32(static_cast<UInt32>(a_Player.GetClientHandle()->GetPing()));
Pkt.WriteBool(false);
}
void cProtocol_1_12_1::SendPlayerListRemovePlayer(const cPlayer & a_Player)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x2e); // Player List Item packet
Pkt.WriteVarInt32(4);
Pkt.WriteVarInt32(1);
Pkt.WriteUUID(a_Player.GetUUID());
}
void cProtocol_1_12_1::SendPlayerListUpdateGameMode(const cPlayer & a_Player)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x2e); // Player List Item packet
Pkt.WriteVarInt32(1);
Pkt.WriteVarInt32(1);
Pkt.WriteUUID(a_Player.GetUUID());
Pkt.WriteVarInt32(static_cast<UInt32>(a_Player.GetGameMode()));
}
void cProtocol_1_12_1::SendPlayerListUpdatePing(const cPlayer & a_Player)
{
ASSERT(m_State == 3); // In game mode?
auto ClientHandle = a_Player.GetClientHandlePtr();
if (ClientHandle != nullptr)
{
cPacketizer Pkt(*this, 0x2e); // Player List Item packet
Pkt.WriteVarInt32(2);
Pkt.WriteVarInt32(1);
Pkt.WriteUUID(a_Player.GetUUID());
Pkt.WriteVarInt32(static_cast<UInt32>(ClientHandle->GetPing()));
}
}
void cProtocol_1_12_1::SendPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_CustomName)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x2e); // Player List Item packet
Pkt.WriteVarInt32(3);
Pkt.WriteVarInt32(1);
Pkt.WriteUUID(a_Player.GetUUID());
if (a_CustomName.empty())
{
Pkt.WriteBool(false);
}
else
{
Pkt.WriteBool(true);
Pkt.WriteString(Printf("{\"text\":\"%s\"}", a_CustomName.c_str()));
}
}
void cProtocol_1_12_1::SendPlayerAbilities(void)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x2c); // Player Abilities packet
Byte Flags = 0;
cPlayer * Player = m_Client->GetPlayer();
if (Player->IsGameModeCreative())
{
Flags |= 0x01;
Flags |= 0x08; // Godmode, used for creative
}
if (Player->IsFlying())
{
Flags |= 0x02;
}
if (Player->CanFly())
{
Flags |= 0x04;
}
Pkt.WriteBEUInt8(Flags);
Pkt.WriteBEFloat(static_cast<float>(0.05 * Player->GetFlyingMaxSpeed()));
Pkt.WriteBEFloat(static_cast<float>(0.1 * Player->GetNormalMaxSpeed()));
}
void cProtocol_1_12_1::SendPlayerMoveLook(void)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x2f); // Player Position And Look packet
cPlayer * Player = m_Client->GetPlayer();
Pkt.WriteBEDouble(Player->GetPosX());
Pkt.WriteBEDouble(Player->GetPosY());
Pkt.WriteBEDouble(Player->GetPosZ());
Pkt.WriteBEFloat(static_cast<float>(Player->GetYaw()));
Pkt.WriteBEFloat(static_cast<float>(Player->GetPitch()));
Pkt.WriteBEUInt8(0);
Pkt.WriteVarInt32(++m_OutstandingTeleportId);
// This teleport ID hasn't been confirmed yet
m_IsTeleportIdConfirmed = false;
}
void cProtocol_1_12_1::SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x30); // Use bed
Pkt.WriteVarInt32(a_Entity.GetUniqueID());
Pkt.WritePosition64(a_BlockX, a_BlockY, a_BlockZ);
}
void cProtocol_1_12_1::SendDestroyEntity(const cEntity & a_Entity)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x32); // Destroy Entities packet
Pkt.WriteVarInt32(1);
Pkt.WriteVarInt32(a_Entity.GetUniqueID());
}
void cProtocol_1_12_1::SendRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x33); // Remove entity effect packet
Pkt.WriteVarInt32(a_Entity.GetUniqueID());
Pkt.WriteBEUInt8(static_cast<UInt8>(a_EffectID));
}
void cProtocol_1_12_1::SendEntityHeadLook(const cEntity & a_Entity)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x36); // Entity Head Look packet
Pkt.WriteVarInt32(a_Entity.GetUniqueID());
Pkt.WriteByteAngle(a_Entity.GetHeadYaw());
}
void cProtocol_1_12_1::SendCameraSetTo(const cEntity & a_Entity)
{
cPacketizer Pkt(*this, 0x39); // Camera packet (Attach the camera of a player at another entity in spectator mode)
Pkt.WriteVarInt32(a_Entity.GetUniqueID());
}
void cProtocol_1_12_1::SendDisplayObjective(const AString & a_Objective, cScoreboard::eDisplaySlot a_Display)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x3b); // Display Scoreboard packet
Pkt.WriteBEUInt8(static_cast<UInt8>(a_Display));
Pkt.WriteString(a_Objective);
}
void cProtocol_1_12_1::SendEntityMetadata(const cEntity & a_Entity)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x3c); // Entity Metadata packet
Pkt.WriteVarInt32(a_Entity.GetUniqueID());
WriteEntityMetadata(Pkt, a_Entity);
Pkt.WriteBEUInt8(0xff); // The termination byte
}
void cProtocol_1_12_1::SendEntityVelocity(const cEntity & a_Entity)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x3e); // Entity Velocity packet
Pkt.WriteVarInt32(a_Entity.GetUniqueID());
// 400 = 8000 / 20 ... Conversion from our speed in m / s to 8000 m / tick
Pkt.WriteBEInt16(static_cast<Int16>(a_Entity.GetSpeedX() * 400));
Pkt.WriteBEInt16(static_cast<Int16>(a_Entity.GetSpeedY() * 400));
Pkt.WriteBEInt16(static_cast<Int16>(a_Entity.GetSpeedZ() * 400));
}
void cProtocol_1_12_1::SendEntityEquipment(const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x3f); // Entity Equipment packet
Pkt.WriteVarInt32(a_Entity.GetUniqueID());
// Needs to be adjusted due to the insertion of offhand at slot 1
if (a_SlotNum > 0)
{
a_SlotNum++;
}
Pkt.WriteVarInt32(static_cast<UInt32>(a_SlotNum));
WriteItem(Pkt, a_Item);
}
void cProtocol_1_12_1::SendExperience(void)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x40); // Set Experience packet
cPlayer * Player = m_Client->GetPlayer();
Pkt.WriteBEFloat(Player->GetXpPercentage());
Pkt.WriteVarInt32(static_cast<UInt32>(Player->GetXpLevel()));
Pkt.WriteVarInt32(static_cast<UInt32>(Player->GetCurrentXp()));
}
void cProtocol_1_12_1::SendHealth(void)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x41); // Update Health packet
cPlayer * Player = m_Client->GetPlayer();
Pkt.WriteBEFloat(static_cast<float>(Player->GetHealth()));
Pkt.WriteVarInt32(static_cast<UInt32>(Player->GetFoodLevel()));
Pkt.WriteBEFloat(static_cast<float>(Player->GetFoodSaturationLevel()));
}
void cProtocol_1_12_1::SendScoreboardObjective(const AString & a_Name, const AString & a_DisplayName, Byte a_Mode)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x42); // Scoreboard Objective packet
Pkt.WriteString(a_Name);
Pkt.WriteBEUInt8(a_Mode);
if ((a_Mode == 0) || (a_Mode == 2))
{
Pkt.WriteString(a_DisplayName);
Pkt.WriteString("integer");
}
}
void cProtocol_1_12_1::SendAttachEntity(const cEntity & a_Entity, const cEntity & a_Vehicle)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x43); // Set Passengers packet
Pkt.WriteVarInt32(a_Vehicle.GetUniqueID());
Pkt.WriteVarInt32(1); // 1 passenger
Pkt.WriteVarInt32(a_Entity.GetUniqueID());
}
void cProtocol_1_12_1::SendDetachEntity(const cEntity & a_Entity, const cEntity & a_PreviousVehicle)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x43); // Set Passengers packet
Pkt.WriteVarInt32(a_PreviousVehicle.GetUniqueID());
Pkt.WriteVarInt32(0); // No passangers
}
void cProtocol_1_12_1::SendScoreUpdate(const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x45); // Update Score packet
Pkt.WriteString(a_Player);
Pkt.WriteBEUInt8(a_Mode);
Pkt.WriteString(a_Objective);
if (a_Mode != 1)
{
Pkt.WriteVarInt32(static_cast<UInt32>(a_Score));
}
}
void cProtocol_1_12_1::SendLogin(const cPlayer & a_Player, const cWorld & a_World)
{
// Send the Join Game packet:
{
cServer * Server = cRoot::Get()->GetServer();
cPacketizer Pkt(*this, 0x23); // Join Game packet
Pkt.WriteBEUInt32(a_Player.GetUniqueID());
Pkt.WriteBEUInt8(static_cast<UInt8>(a_Player.GetEffectiveGameMode()) | (Server->IsHardcore() ? 0x08 : 0)); // Hardcore flag bit 4
Pkt.WriteBEInt32(static_cast<Int32>(a_World.GetDimension()));
Pkt.WriteBEUInt8(2); // TODO: Difficulty (set to Normal)
Pkt.WriteBEUInt8(static_cast<UInt8>(Clamp<size_t>(Server->GetMaxPlayers(), 0, 255)));
Pkt.WriteString("default"); // Level type - wtf?
Pkt.WriteBool(false); // Reduced Debug Info - wtf?
}
// Send the spawn position:
{
cPacketizer Pkt(*this, 0x46); // Spawn Position packet
Pkt.WritePosition64(FloorC(a_World.GetSpawnX()), FloorC(a_World.GetSpawnY()), FloorC(a_World.GetSpawnZ()));
}
// Send the server difficulty:
{
cPacketizer Pkt(*this, 0x0d); // Server difficulty packet
Pkt.WriteBEInt8(1);
}
// Send player abilities:
SendPlayerAbilities();
}
void cProtocol_1_12_1::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle)
{
ASSERT(m_State == 3); // In game mode?
if (!a_DoDaylightCycle)
{
// When writing a "-" before the number the client ignores it but it will stop the client-side time expiration.
a_TimeOfDay = std::min(-a_TimeOfDay, -1LL);
}
cPacketizer Pkt(*this, 0x47); // Time update packet
Pkt.WriteBEInt64(a_WorldAge);
Pkt.WriteBEInt64(a_TimeOfDay);
}
void cProtocol_1_12_1::SendSetRawTitle(const AString & a_Title)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x48); // Title packet
Pkt.WriteVarInt32(0); // Set title
Pkt.WriteString(a_Title);
}
void cProtocol_1_12_1::SendSetRawSubTitle(const AString & a_SubTitle)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x48); // Title packet
Pkt.WriteVarInt32(1); // Set subtitle
Pkt.WriteString(a_SubTitle);
}
void cProtocol_1_12_1::SendTitleTimes(int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x48); // Title packet
Pkt.WriteVarInt32(3); // Set title display times
Pkt.WriteBEInt32(a_FadeInTicks);
Pkt.WriteBEInt32(a_DisplayTicks);
Pkt.WriteBEInt32(a_FadeOutTicks);
}
void cProtocol_1_12_1::SendHideTitle(void)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x48); // Title packet
Pkt.WriteVarInt32(4); // Hide title
}
void cProtocol_1_12_1::SendResetTitle(void)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x48); // Title packet
Pkt.WriteVarInt32(5); // Reset title
}
void cProtocol_1_12_1::SendCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player, int a_Count)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x4b); // Collect Item packet
Pkt.WriteVarInt32(a_Entity.GetUniqueID());
Pkt.WriteVarInt32(a_Player.GetUniqueID());
Pkt.WriteVarInt32(static_cast<UInt32>(a_Count));
}
void cProtocol_1_12_1::SendTeleportEntity(const cEntity & a_Entity)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x4c); // Entity teleport packet
Pkt.WriteVarInt32(a_Entity.GetUniqueID());
Pkt.WriteBEDouble(a_Entity.GetPosX());
Pkt.WriteBEDouble(a_Entity.GetPosY());
Pkt.WriteBEDouble(a_Entity.GetPosZ());
Pkt.WriteByteAngle(a_Entity.GetYaw());
Pkt.WriteByteAngle(a_Entity.GetPitch());
Pkt.WriteBool(a_Entity.IsOnGround());
}
void cProtocol_1_12_1::SendEntityProperties(const cEntity & a_Entity)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x4e); // Entity Properties packet
Pkt.WriteVarInt32(a_Entity.GetUniqueID());
WriteEntityProperties(Pkt, a_Entity);
}
void cProtocol_1_12_1::SendEntityEffect(const cEntity & a_Entity, int a_EffectID, int a_Amplifier, short a_Duration)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x4f); // Entity Effect packet
Pkt.WriteVarInt32(a_Entity.GetUniqueID());
Pkt.WriteBEUInt8(static_cast<UInt8>(a_EffectID));
Pkt.WriteBEUInt8(static_cast<UInt8>(a_Amplifier));
Pkt.WriteVarInt32(static_cast<UInt32>(a_Duration));
Pkt.WriteBool(false); // Hide particles
}
void cProtocol_1_12_1::SendPlayerMaxSpeed(void)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x4e); // Entity Properties
cPlayer * Player = m_Client->GetPlayer();
Pkt.WriteVarInt32(Player->GetUniqueID());
Pkt.WriteBEInt32(1); // Count
Pkt.WriteString("generic.movementSpeed");
// The default game speed is 0.1, multiply that value by the relative speed:
Pkt.WriteBEDouble(0.1 * Player->GetNormalMaxSpeed());
if (Player->IsSprinting())
{
Pkt.WriteVarInt32(1); // Modifier count
Pkt.WriteBEUInt64(0x662a6b8dda3e4c1c);
Pkt.WriteBEUInt64(0x881396ea6097278d); // UUID of the modifier
Pkt.WriteBEDouble(Player->GetSprintingMaxSpeed() - Player->GetNormalMaxSpeed());
Pkt.WriteBEUInt8(2);
}
else
{
Pkt.WriteVarInt32(0); // Modifier count
}
}
bool cProtocol_1_12_1::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType)
{
switch (m_State)
{
case 1:
{
// Status
switch (a_PacketType)
{
case 0x00: HandlePacketStatusRequest(a_ByteBuffer); return true;
case 0x01: HandlePacketStatusPing(a_ByteBuffer); return true;
}
break;
}
case 2:
{
// Login
switch (a_PacketType)
{
case 0x00: HandlePacketLoginStart(a_ByteBuffer); return true;
case 0x01: HandlePacketLoginEncryptionResponse(a_ByteBuffer); return true;
}
break;
}
case 3:
{
// Game
switch (a_PacketType)
{
case 0x00: HandleConfirmTeleport(a_ByteBuffer); return true;
case 0x01: HandlePacketTabComplete(a_ByteBuffer); return true;
case 0x02: HandlePacketChatMessage(a_ByteBuffer); return true;
case 0x03: HandlePacketClientStatus(a_ByteBuffer); return true;
case 0x04: HandlePacketClientSettings(a_ByteBuffer); return true;
case 0x05: break; // Confirm transaction - not used in Cuberite
case 0x06: HandlePacketEnchantItem(a_ByteBuffer); return true;
case 0x07: HandlePacketWindowClick(a_ByteBuffer); return true;
case 0x08: HandlePacketWindowClose(a_ByteBuffer); return true;
case 0x09: HandlePacketPluginMessage(a_ByteBuffer); return true;
case 0x0a: HandlePacketUseEntity(a_ByteBuffer); return true;
case 0x0b: HandlePacketKeepAlive(a_ByteBuffer); return true;
case 0x0c: HandlePacketPlayer(a_ByteBuffer); return true;
case 0x0d: HandlePacketPlayerPos(a_ByteBuffer); return true;
case 0x0e: HandlePacketPlayerPosLook(a_ByteBuffer); return true;
case 0x0f: HandlePacketPlayerLook(a_ByteBuffer); return true;
case 0x10: HandlePacketVehicleMove(a_ByteBuffer); return true;
case 0x11: HandlePacketBoatSteer(a_ByteBuffer); return true;
case 0x12: break; // Craft Recipe Request - not yet implemented
case 0x13: HandlePacketPlayerAbilities(a_ByteBuffer); return true;
case 0x14: HandlePacketBlockDig(a_ByteBuffer); return true;
case 0x15: HandlePacketEntityAction(a_ByteBuffer); return true;
case 0x16: HandlePacketSteerVehicle(a_ByteBuffer); return true;
case 0x17: HandlePacketCraftingBookData(a_ByteBuffer); return true;
case 0x18: break; // Resource pack status - not yet implemented
case 0x19: HandlePacketAdvancementTab(a_ByteBuffer); return true;
case 0x1a: HandlePacketSlotSelect(a_ByteBuffer); return true;
case 0x1b: HandlePacketCreativeInventoryAction(a_ByteBuffer); return true;
case 0x1c: HandlePacketUpdateSign(a_ByteBuffer); return true;
case 0x1d: HandlePacketAnimation(a_ByteBuffer); return true;
case 0x1e: HandlePacketSpectate(a_ByteBuffer); return true;
case 0x1f: HandlePacketBlockPlace(a_ByteBuffer); return true;
case 0x20: HandlePacketUseItem(a_ByteBuffer); return true;
}
break;
}
default:
{
// Received a packet in an unknown state, report:
LOGWARNING("Received a packet in an unknown protocol state %d. Ignoring further packets.", m_State);
// Cannot kick the client - we don't know this state and thus the packet number for the kick packet
// Switch to a state when all further packets are silently ignored:
m_State = 255;
return false;
}
case 255:
{
// This is the state used for "not processing packets anymore" when we receive a bad packet from a client.
// Do not output anything (the caller will do that for us), just return failure
return false;
}
} // switch (m_State)
// Unknown packet type, report to the ClientHandle:
m_Client->PacketUnknown(a_PacketType);
return false;
}

View File

@ -5,6 +5,8 @@
Declares the 1.12 protocol classes: Declares the 1.12 protocol classes:
- cProtocol_1_12 - cProtocol_1_12
- release 1.12 protocol (#335) - release 1.12 protocol (#335)
- cProtocol_1_12_1
- release 1.12.1 protocol (#338)
(others may be added later in the future for the 1.12 release series) (others may be added later in the future for the 1.12 release series)
*/ */
@ -69,3 +71,60 @@ protected:
virtual void WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a_Entity) override; virtual void WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a_Entity) override;
virtual void WriteMobMetadata(cPacketizer & a_Pkt, const cMonster & a_Mob) override; virtual void WriteMobMetadata(cPacketizer & a_Pkt, const cMonster & a_Mob) override;
}; };
class cProtocol_1_12_1 :
public cProtocol_1_12
{
typedef cProtocol_1_12 super;
public:
cProtocol_1_12_1(cClientHandle * a_Client, const AString &a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State);
virtual void SendRespawn(eDimension a_Dimension) override;
virtual void SendPlayerListAddPlayer(const cPlayer & a_Player) override;
virtual void SendPlayerListRemovePlayer(const cPlayer & a_Player) override;
virtual void SendPlayerListUpdateGameMode(const cPlayer & a_Player) override;
virtual void SendPlayerListUpdatePing(const cPlayer & a_Player) override;
virtual void SendPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_CustomName) override;
virtual void SendPlayerAbilities(void) override;
virtual void SendPlayerMoveLook(void) override;
virtual void SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ) override;
virtual void SendDestroyEntity(const cEntity & a_Entity) override;
virtual void SendRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID) override;
virtual void SendEntityHeadLook(const cEntity & a_Entity) override;
virtual void SendCameraSetTo(const cEntity & a_Entity) override;
virtual void SendDisplayObjective(const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) override;
virtual void SendEntityMetadata(const cEntity & a_Entity) override;
virtual void SendEntityVelocity(const cEntity & a_Entity) override;
virtual void SendEntityEquipment(const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) override;
virtual void SendExperience(void) override;
virtual void SendHealth(void) override;
virtual void SendScoreboardObjective(const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override;
virtual void SendAttachEntity(const cEntity & a_Entity, const cEntity & a_Vehicle) override;
virtual void SendDetachEntity(const cEntity & a_Entity, const cEntity & a_PreviousVehicle) override;
virtual void SendScoreUpdate(const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) override;
virtual void SendLogin(const cPlayer & a_Player, const cWorld & a_World) override;
virtual void SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) override;
virtual void SendHideTitle(void) override;
virtual void SendResetTitle(void) override;
virtual void SendSetRawSubTitle(const AString & a_SubTitle) override;
virtual void SendSetRawTitle(const AString & a_Title) override;
virtual void SendTitleTimes(int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks) override;
virtual void SendCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player, int a_Count) override;
virtual void SendTeleportEntity(const cEntity & a_Entity) override;
virtual void SendEntityProperties(const cEntity & a_Entity) override;
virtual void SendEntityEffect(const cEntity & a_Entity, int a_EffectID, int a_Amplifier, short a_Duration) override;
virtual void SendPlayerMaxSpeed(void) override;
protected:
virtual bool HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType) override;
virtual void HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer) override;
};