summaryrefslogtreecommitdiffstats
path: root/src/Protocol
diff options
context:
space:
mode:
Diffstat (limited to 'src/Protocol')
-rw-r--r--src/Protocol/CMakeLists.txt2
-rw-r--r--src/Protocol/Packetizer.cpp5
-rw-r--r--src/Protocol/Protocol.h3
-rw-r--r--src/Protocol/ProtocolRecognizer.cpp21
-rw-r--r--src/Protocol/ProtocolRecognizer.h2
-rw-r--r--src/Protocol/Protocol_1_12.cpp76
-rw-r--r--src/Protocol/Protocol_1_12.h9
-rw-r--r--src/Protocol/Protocol_1_13.cpp1
-rw-r--r--src/Protocol/Protocol_1_8.cpp20
-rw-r--r--src/Protocol/Protocol_1_8.h2
-rw-r--r--src/Protocol/Protocol_1_9.cpp6
-rw-r--r--src/Protocol/RecipeMapper.cpp128
-rw-r--r--src/Protocol/RecipeMapper.h35
13 files changed, 299 insertions, 11 deletions
diff --git a/src/Protocol/CMakeLists.txt b/src/Protocol/CMakeLists.txt
index e197853cb..40eecde07 100644
--- a/src/Protocol/CMakeLists.txt
+++ b/src/Protocol/CMakeLists.txt
@@ -14,6 +14,7 @@ target_sources(
Protocol_1_13.cpp
ProtocolPalettes.cpp
ProtocolRecognizer.cpp
+ RecipeMapper.cpp
Authenticator.h
ChunkDataSerializer.h
@@ -29,4 +30,5 @@ target_sources(
Protocol_1_13.h
ProtocolPalettes.h
ProtocolRecognizer.h
+ RecipeMapper.h
)
diff --git a/src/Protocol/Packetizer.cpp b/src/Protocol/Packetizer.cpp
index 6afea8a36..12bfcc0dd 100644
--- a/src/Protocol/Packetizer.cpp
+++ b/src/Protocol/Packetizer.cpp
@@ -121,6 +121,7 @@ AString cPacketizer::PacketTypeToStr(cProtocol::ePacketType a_PacketType)
case cProtocol::pktTimeUpdate: return "pktTimeUpdate";
case cProtocol::pktTitle: return "pktTitle";
case cProtocol::pktUnloadChunk: return "pktUnloadChunk";
+ case cProtocol::pktUnlockRecipe: return "pktUnlockRecipe";
case cProtocol::pktUpdateBlockEntity: return "pktUpdateBlockEntity";
case cProtocol::pktUpdateHealth: return "pktUpdateHealth";
case cProtocol::pktUpdateScore: return "pktUpdateScore";
@@ -134,7 +135,3 @@ AString cPacketizer::PacketTypeToStr(cProtocol::ePacketType a_PacketType)
}
return Printf("Unknown packet type: 0x%02x", a_PacketType);
}
-
-
-
-
diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h
index 12382b954..e1d901321 100644
--- a/src/Protocol/Protocol.h
+++ b/src/Protocol/Protocol.h
@@ -132,6 +132,7 @@ public:
pktTimeUpdate,
pktTitle,
pktUnloadChunk,
+ pktUnlockRecipe,
pktUpdateBlockEntity,
pktUpdateHealth,
pktUpdateScore,
@@ -225,6 +226,8 @@ public:
virtual void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity) = 0;
virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) = 0;
virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ) = 0;
+ virtual void SendUnlockRecipe (UInt32 a_RecipeID) = 0;
+ virtual void SendInitRecipes (UInt32 a_RecipeID) = 0;
virtual void SendWeather (eWeather a_Weather) = 0;
virtual void SendWholeInventory (const cWindow & a_Window) = 0;
virtual void SendWindowClose (const cWindow & a_Window) = 0;
diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp
index 73f8e0ff1..3f3982c90 100644
--- a/src/Protocol/ProtocolRecognizer.cpp
+++ b/src/Protocol/ProtocolRecognizer.cpp
@@ -51,6 +51,7 @@ AString cProtocolRecognizer::GetVersionTextFromInt(int a_ProtocolVersion)
case PROTO_VERSION_1_11_1: return "1.11.1";
case PROTO_VERSION_1_12: return "1.12";
case PROTO_VERSION_1_12_1: return "1.12.1";
+ case PROTO_VERSION_1_12_2: return "1.12.2";
case PROTO_VERSION_1_13: return "1.13";
}
ASSERT(!"Unknown protocol version");
@@ -921,6 +922,26 @@ void cProtocolRecognizer::SendUseBed(const cEntity & a_Entity, int a_BlockX, int
+void cProtocolRecognizer::SendUnlockRecipe(UInt32 a_RecipeID)
+{
+ ASSERT(m_Protocol != nullptr);
+ m_Protocol->SendUnlockRecipe(a_RecipeID);
+}
+
+
+
+
+
+void cProtocolRecognizer::SendInitRecipes(UInt32 a_RecipeID)
+{
+ ASSERT(m_Protocol != nullptr);
+ m_Protocol->SendInitRecipes(a_RecipeID);
+}
+
+
+
+
+
void cProtocolRecognizer::SendWeather(eWeather a_Weather)
{
ASSERT(m_Protocol != nullptr);
diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h
index f82dab08a..c5d180b44 100644
--- a/src/Protocol/ProtocolRecognizer.h
+++ b/src/Protocol/ProtocolRecognizer.h
@@ -127,6 +127,8 @@ public:
virtual void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity) override;
virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) override;
virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ) override;
+ virtual void SendUnlockRecipe (UInt32 a_RecipeID) override;
+ virtual void SendInitRecipes (UInt32 a_RecipeID) override;
virtual void SendWeather (eWeather a_Weather) override;
virtual void SendWholeInventory (const cWindow & a_Window) override;
virtual void SendWindowClose (const cWindow & a_Window) override;
diff --git a/src/Protocol/Protocol_1_12.cpp b/src/Protocol/Protocol_1_12.cpp
index dba85435b..6998f73bf 100644
--- a/src/Protocol/Protocol_1_12.cpp
+++ b/src/Protocol/Protocol_1_12.cpp
@@ -25,6 +25,7 @@ Implements the 1.12 protocol classes:
#include "../Root.h"
#include "../Server.h"
#include "../ClientHandle.h"
+#include "../CraftingRecipes.h"
#include "../Bindings/PluginManager.h"
#include "../JsonUtils.h"
@@ -1007,6 +1008,7 @@ UInt32 cProtocol_1_12::GetPacketID(cProtocol::ePacketType a_Packet)
case pktTeleportEntity: return 0x4b;
case pktTimeUpdate: return 0x46;
case pktTitle: return 0x47;
+ case pktUnlockRecipe: return 0x30;
case pktUpdateBlockEntity: return 0x09;
case pktUpdateHealth: return 0x40;
case pktUpdateScore: return 0x44;
@@ -1019,10 +1021,27 @@ UInt32 cProtocol_1_12::GetPacketID(cProtocol::ePacketType a_Packet)
+void cProtocol_1_12::HandleCraftRecipe(cByteBuffer & a_ByteBuffer)
+{
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, WindowID);
+ HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, RecipeID);
+ HANDLE_READ(a_ByteBuffer, ReadBool, bool, MakeAll);
+ auto CuberiteRecipeId = cRoot::Get()->GetRecipeMapper()->GetCuberiteRecipeId(RecipeID, m_Client->GetProtocolVersion());
+ if (CuberiteRecipeId.has_value())
+ {
+ m_Client->HandleCraftRecipe(CuberiteRecipeId.value());
+ }
+}
+
+
+
+
+
void cProtocol_1_12::HandlePacketCraftingBookData(cByteBuffer & a_ByteBuffer)
{
+ // TODO not yet used, not sure if it is needed
+ // https://wiki.vg/index.php?title=Protocol&oldid=14204#Crafting_Book_Data
a_ByteBuffer.SkipRead(a_ByteBuffer.GetReadableSpace() - 1);
- m_Client->GetPlayer()->SendMessageInfo("The green crafting book feature is not implemented yet.");
}
@@ -1170,6 +1189,7 @@ UInt32 cProtocol_1_12_1::GetPacketID(ePacketType a_Packet)
case pktRespawn: return 0x35;
case pktScoreboardObjective: return 0x42;
case pktSpawnPosition: return 0x46;
+ case pktUnlockRecipe: return 0x31;
case pktUpdateHealth: return 0x41;
case pktUpdateScore: return 0x45;
case pktUseBed: return 0x30;
@@ -1277,7 +1297,7 @@ bool cProtocol_1_12_1::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketT
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 0x12: HandleCraftRecipe(a_ByteBuffer); return true;
case 0x13: HandlePacketPlayerAbilities(a_ByteBuffer); return true;
case 0x14: HandlePacketBlockDig(a_ByteBuffer); return true;
case 0x15: HandlePacketEntityAction(a_ByteBuffer); return true;
@@ -1397,3 +1417,55 @@ void cProtocol_1_12_2::SendKeepAlive(UInt32 a_PingID)
cPacketizer Pkt(*this, pktKeepAlive);
Pkt.WriteBEInt64(a_PingID);
}
+
+
+
+
+
+void cProtocol_1_12_2::SendUnlockRecipe(UInt32 a_RecipeID)
+{
+ ASSERT(m_State == 3); // In game mode?
+
+ auto ProtocolRecipeId = cRoot::Get()->GetRecipeMapper()->GetProtocolRecipeId(a_RecipeID, m_Client->GetProtocolVersion());
+ if (ProtocolRecipeId.has_value())
+ {
+ cPacketizer Pkt(*this, pktUnlockRecipe);
+ Pkt.WriteVarInt32(1);
+ Pkt.WriteBool(true);
+ Pkt.WriteBool(false);
+ Pkt.WriteVarInt32(1);
+ Pkt.WriteVarInt32(ProtocolRecipeId.value());
+ }
+}
+
+
+
+
+
+void cProtocol_1_12_2::SendInitRecipes(UInt32 a_RecipeID)
+{
+ ASSERT(m_State == 3); // In game mode?
+
+ auto ProtocolRecipeId = cRoot::Get()->GetRecipeMapper()->GetProtocolRecipeId(a_RecipeID, m_Client->GetProtocolVersion());
+ if (!ProtocolRecipeId.has_value())
+ {
+ return;
+ }
+
+ cPacketizer Pkt(*this, pktUnlockRecipe);
+ Pkt.WriteVarInt32(0);
+ Pkt.WriteBool(true);
+ Pkt.WriteBool(false);
+ if (a_RecipeID == 0)
+ {
+ Pkt.WriteVarInt32(0);
+ Pkt.WriteVarInt32(0);
+ }
+ else
+ {
+ Pkt.WriteVarInt32(1);
+ Pkt.WriteVarInt32(ProtocolRecipeId.value());
+ Pkt.WriteVarInt32(1);
+ Pkt.WriteVarInt32(ProtocolRecipeId.value());
+ }
+}
diff --git a/src/Protocol/Protocol_1_12.h b/src/Protocol/Protocol_1_12.h
index 38c025e9e..c1b81955a 100644
--- a/src/Protocol/Protocol_1_12.h
+++ b/src/Protocol/Protocol_1_12.h
@@ -20,7 +20,7 @@ Declares the 1.12 protocol classes:
#include "Protocol_1_11.h"
-
+#include "RecipeMapper.h"
@@ -36,6 +36,7 @@ public:
protected:
virtual bool HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType) override;
virtual void HandlePacketAdvancementTab(cByteBuffer & a_ByteBuffer);
+ virtual void HandleCraftRecipe(cByteBuffer & a_ByteBuffer);
virtual void HandlePacketCraftingBookData(cByteBuffer & a_ByteBuffer);
virtual void HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer) override;
virtual void WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a_Entity) override;
@@ -86,8 +87,6 @@ protected:
virtual void HandlePacketKeepAlive(cByteBuffer & a_ByteBuffer) override;
virtual void HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer) override;
virtual void SendKeepAlive(UInt32 a_PingID) override;
+ virtual void SendUnlockRecipe(UInt32 a_RecipeID) override;
+ virtual void SendInitRecipes(UInt32 a_RecipeID) override;
};
-
-
-
-
diff --git a/src/Protocol/Protocol_1_13.cpp b/src/Protocol/Protocol_1_13.cpp
index fc048fe70..1dcecaa4b 100644
--- a/src/Protocol/Protocol_1_13.cpp
+++ b/src/Protocol/Protocol_1_13.cpp
@@ -140,6 +140,7 @@ UInt32 cProtocol_1_13::GetPacketID(ePacketType a_PacketType)
case pktTimeUpdate: return 0x4a;
case pktTitle: return 0x4b;
case pktUnloadChunk: return 0x1f;
+ case pktUnlockRecipe: return 0x32;
case pktUpdateHealth: return 0x44;
case pktUpdateScore: return 0x48;
case pktUpdateSign: return GetPacketID(pktUpdateBlockEntity);
diff --git a/src/Protocol/Protocol_1_8.cpp b/src/Protocol/Protocol_1_8.cpp
index b5d78e457..469f01c39 100644
--- a/src/Protocol/Protocol_1_8.cpp
+++ b/src/Protocol/Protocol_1_8.cpp
@@ -1587,6 +1587,26 @@ void cProtocol_1_8_0::SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_B
+void cProtocol_1_8_0::SendUnlockRecipe(UInt32 a_RecipeID)
+{
+ // Client doesn't support this feature
+ return;
+}
+
+
+
+
+
+void cProtocol_1_8_0::SendInitRecipes(UInt32 a_RecipeID)
+{
+ // Client doesn't support this feature
+ return;
+}
+
+
+
+
+
void cProtocol_1_8_0::SendWeather(eWeather a_Weather)
{
ASSERT(m_State == 3); // In game mode?
diff --git a/src/Protocol/Protocol_1_8.h b/src/Protocol/Protocol_1_8.h
index 42903a921..a8232104b 100644
--- a/src/Protocol/Protocol_1_8.h
+++ b/src/Protocol/Protocol_1_8.h
@@ -114,6 +114,8 @@ public:
virtual void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity) override;
virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) override;
virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ) override;
+ virtual void SendUnlockRecipe (UInt32 a_RecipeID) override;
+ virtual void SendInitRecipes (UInt32 a_RecipeID) override;
virtual void SendWeather (eWeather a_Weather) override;
virtual void SendWholeInventory (const cWindow & a_Window) override;
virtual void SendWindowClose (const cWindow & a_Window) override;
diff --git a/src/Protocol/Protocol_1_9.cpp b/src/Protocol/Protocol_1_9.cpp
index 8327eaf40..784c26f34 100644
--- a/src/Protocol/Protocol_1_9.cpp
+++ b/src/Protocol/Protocol_1_9.cpp
@@ -567,6 +567,12 @@ UInt32 cProtocol_1_9_0::GetPacketID(cProtocol::ePacketType a_Packet)
case pktWindowItems: return 0x14;
case pktWindowOpen: return 0x13;
case pktWindowProperty: return 0x15;
+
+ // Unsupported packets
+ case pktUnlockRecipe:
+ {
+ break;
+ }
}
UNREACHABLE("Unsupported outgoing packet type");
}
diff --git a/src/Protocol/RecipeMapper.cpp b/src/Protocol/RecipeMapper.cpp
new file mode 100644
index 000000000..2757fdfd6
--- /dev/null
+++ b/src/Protocol/RecipeMapper.cpp
@@ -0,0 +1,128 @@
+#include "Globals.h"
+#include "RecipeMapper.h"
+#include "../Root.h"
+
+cRecipeMapper::cRecipeMapper(void)
+{
+ AString path = "Protocol";
+ auto contents = cFile::GetFolderContents(path);
+ for (const auto & content: contents)
+ {
+ auto fullName = path + cFile::PathSeparator() + content;
+ if (cFile::IsFolder(fullName))
+ {
+ loadRecipes(content);
+ }
+ }
+}
+
+
+
+
+
+void cRecipeMapper::loadRecipes(const AString & a_ProtocolVersion)
+{
+ cFile f;
+ if (!f.Open("Protocol/" + a_ProtocolVersion + "/base.recipes.txt", cFile::fmRead))
+ {
+ LOGWARNING("Cannot open file \"Protocol/%s/base.recipes.txt\", no recipe book recipes will be available!", a_ProtocolVersion);
+ return;
+ }
+ AString Everything;
+ if (!f.ReadRestOfFile(Everything))
+ {
+ LOGWARNING("Cannot read file \"Protocol/%s/base.recipes.txt\", no recipe book recipes will be available!", a_ProtocolVersion);
+ return;
+ }
+ f.Close();
+
+ // Split it into lines, then process each line as a single recipe:
+ AStringVector Split = StringSplit(Everything, "\n");
+ m_ProtocolVersionMap[a_ProtocolVersion] = {};
+ const auto & RecipeNameMap = cRoot::Get()->GetCraftingRecipes()->GetRecipeNameMap();
+
+ int LineNum = 1;
+ for (AStringVector::const_iterator itr = Split.begin(); itr != Split.end(); ++itr, ++LineNum)
+ {
+ // Remove anything after a '#' sign and trim away the whitespace:
+ AString Recipe = TrimString(itr->substr(0, itr->find('#')));
+ if (Recipe.empty())
+ {
+ // Empty recipe
+ continue;
+ }
+ AddRecipeLine(a_ProtocolVersion, LineNum, Recipe, RecipeNameMap);
+ }
+ LOG("Loaded %s %zu recipe book", a_ProtocolVersion, m_ProtocolVersionMap[a_ProtocolVersion].size());
+}
+
+
+
+
+
+cRecipeMapper::~cRecipeMapper()
+{
+}
+
+
+
+
+
+void cRecipeMapper::AddRecipeLine(const AString & a_ProtocolVersion, int a_LineNum, const AString & a_RecipeLine, const std::map<AString, UInt32> & a_RecipeNameMap)
+{
+ AStringVector Sides = StringSplit(a_RecipeLine, " ");
+ UInt32 Id;
+ if (Sides.size() != 2)
+ {
+ LOGINFO("Recipe incompletely configured %s", a_RecipeLine);
+ return;
+ }
+ StringToInteger<UInt32>(Sides[0], Id);
+
+ auto RecipeIndex = a_RecipeNameMap.find(Sides[1]);
+ if (RecipeIndex == a_RecipeNameMap.end())
+ {
+ return;
+ }
+ m_ProtocolVersionMap[a_ProtocolVersion].emplace(Id, RecipeIndex->second);
+}
+
+
+
+
+
+std::optional<UInt32> cRecipeMapper::GetProtocolRecipeId(UInt32 a_RecipeId, UInt32 a_ProtocolVersion)
+{
+ auto ProtocolMap = m_ProtocolVersionMap.find(cRoot::Get()->GetProtocolVersionTextFromInt(static_cast<int>(a_ProtocolVersion)));
+ if (ProtocolMap == m_ProtocolVersionMap.end())
+ {
+ return {};
+ }
+ for (const auto & item: ProtocolMap->second)
+ {
+ if (item.second == a_RecipeId)
+ {
+ return item.first;
+ }
+ }
+ return {};
+}
+
+
+
+
+
+std::optional<UInt32> cRecipeMapper::GetCuberiteRecipeId(UInt32 a_ProtocolRecipeId, UInt32 a_ProtocolVersion)
+{
+ auto ProtocolMap = m_ProtocolVersionMap.find(cRoot::Get()->GetProtocolVersionTextFromInt(static_cast<int>(a_ProtocolVersion)));
+ if (ProtocolMap == m_ProtocolVersionMap.end())
+ {
+ return {};
+ }
+ auto Element = ProtocolMap->second.find(a_ProtocolRecipeId);
+ if (Element != ProtocolMap->second.end())
+ {
+ return Element->second;
+ }
+ return {};
+}
diff --git a/src/Protocol/RecipeMapper.h b/src/Protocol/RecipeMapper.h
new file mode 100644
index 000000000..1cac62f92
--- /dev/null
+++ b/src/Protocol/RecipeMapper.h
@@ -0,0 +1,35 @@
+#pragma once
+
+#include "../CraftingRecipes.h"
+#include <optional>
+
+/**
+The RecipeMapper handles the translation of crafting recipes into protocol
+specific recipe Ids.
+The crafting recipes are identified by the RecipeId.
+The actual configuration is stored in the protocol specific configuration
+directory, e.g. `Server/Protocol/1.12.2/base.recipes.txt`
+*/
+class cRecipeMapper
+{
+public:
+ cRecipeMapper(void);
+ ~cRecipeMapper();
+
+ /** Translates the cuberite RecipeId to the protocol specific RecipeId */
+ std::optional<UInt32> GetProtocolRecipeId(UInt32 a_RecipeId, UInt32 a_ProtocolVersion);
+
+ /** Translates the protocol specific RecipeId to the cuberite RecipeId */
+ std::optional<UInt32> GetCuberiteRecipeId(UInt32 a_ProtocolRecipeId, UInt32 a_ProtocolVersion);
+
+private:
+ /** A mapping for each protocol from the protocol specific RecipeId and the cuberite RecipeId */
+ std::map<AString, std::map<UInt32, UInt32>> m_ProtocolVersionMap;
+
+ /** Load Recipes from the protocol specific mapping file */
+ void loadRecipes(const AString & a_ProtocolVersion);
+
+ /** Handles a single line of the protocol specific mapping file */
+ void AddRecipeLine(const AString & a_ProtocolVersion, int a_LineNum, const AString & a_RecipeLine, const std::map<AString, UInt32> & a_RecipeNameMap);
+
+};