-
Notifications
You must be signed in to change notification settings - Fork 45
Mod support
Minecraft mods can use dedicated channels in the protocol to send and receive data. For more information about that, you can check this post from Dinnerbone, or the wiki.vg page.
As it is not possible to know in advance which mods will be present, protocolCraft can't parse these data and only exposes them as raw byte arrays, leaving your Botcraft based program the task to serialize/deserialize them. This page aims to explain how you can do that.
There are two different methods, depending on what you want to achieve. In both cases, you will have to implement some serialization/deserialization code, but the handling of incoming data is different.
- if you only need to read values from messages AND you are fine getting a json representation of the messages --> you can use the "simpler" plugin approach
- if you also need to send data OR your packet structures are not adapted for json representation --> you need to implement the reading in your application code
ProtocolCraft has a plugin system that lets you define some custom packet structures that are loaded at runtime. It means you do not need to recompile protocolCraft, botcraft or your app everytime you want to make a change to the packet structure, speeding up the development process. The downside is that the interface to the packets is very limited, and you can only get a json representation of the incoming data. This is the approach that is used in Sniffcraft for example.
To use this method you need to:
- create a protocolCraft plugin with your packet read/write methods
- copy it to a
protocolcraft_plugins
folder next to your executable - mod packets with the plugin defined identifier will now be deserialized. You can access them in your botcraft client Handle function:
void ManagersClient::Handle(ProtocolCraft::ClientboundCustomPayloadPacket& msg)
{
if (msg.GetParsedData() == nullptr)
{
LOG_INFO("No loaded plugin for " << msg.GetIdentifier());
return;
}
if (msg.GetIdentifier() == "namespace:my_mod")
{
ProtocolCraft::Json::Value json = ProtocolCraft::Json::Parse(msg.GetParsedData()->Serialize());
// To get an int value:
json["my_field"].get<int>();
// To get a string:
json["my_string"].get<std::string>();
}
}
If the plugin approach does not fit your usecase, it's still possible to use a more manual solution. In this case, you can either implement the parsing manually (using protocolCraft atomic ReadData function) or define a packet structure directly in your application code instead of a plugin, inheriting ProtocolCraft::NetworkType. You can check how a type is defined in protocolCraft.
Once done, you can read data like that:
void ManagersClient::Handle(ProtocolCraft::ClientboundCustomPayloadPacket& msg)
{
if (msg.GetIdentifier() == "namespace:my_mod")
{
ProtocolCraft::ReadIterator iter = msg.GetRawData().cbegin();
size_t length = msg.GetRawData().size();
MyType t;
t.Read(iter, length);
// Do something with t
}
}
And to write data:
// Assuming you have a MyType t defined above
std::vector<unsigned char> serialized;
t.Write(serialized);
std::shared_ptr<ProtocolCraft::ServerboundCustomPayloadPacket> packet = std::make_shared<ProtocolCraft::ServerboundCustomPayloadPacket>();
packet->SetIdentifier("namespace:my_mod");
packet->SetRawData(serialized);
// GetNetworkManager is a botcraft client function
GetNetworkManager()->Send(packet);