10 #include "../ByteBuffer.h"
11 #include "../Bindings/PluginManager.h"
12 #include "../ClientHandle.h"
59 LOGD(
"Forge handshake error: %s", message.c_str());
77 LOGD(
"Received server ping from version: %d", ProtocolVersion);
80 Modinfo[
"type"] =
"FML";
82 Json::Value
ModList(Json::arrayValue);
83 for (
auto & item: Mods)
86 Mod[
"modid"] = item.first;
87 Mod[
"version"] = item.second;
92 a_ResponseValue[
"modinfo"] = Modinfo;
103 static const std::array<std::string_view, 5> Channels{{
"FML|HS",
"FML",
"FML|MP",
"FML",
"FORGE" }};
105 for (
auto & Channel: Channels)
107 ChannelsString.append({
reinterpret_cast<const std::byte *
>(Channel.data()), Channel.size() });
108 ChannelsString.push_back(std::byte(0));
143 if (a_Data.size() < 4)
145 SetError(fmt::format(FMT_STRING(
"ParseModList invalid packet, missing length (size = {})"), a_Data.size()));
150 Buf.
Write(a_Data.data(), a_Data.size());
154 SetError(
"ParseModList failed to read mod count");
158 for (
UInt32 i = 0; i < NumMods; ++i)
163 SetError(fmt::format(FMT_STRING(
"ParseModList failed to read mod name at i = {}"), i));
168 SetError(fmt::format(FMT_STRING(
"ParseModList failed to read mod version at i = {}"), i));
171 Mods.insert({Name, Version});
183 if (a_Data.size() == 2)
185 const auto FmlProtocolVersion =
static_cast<Int8>(a_Data[1]);
186 LOGD(
"Received ClientHello with FML protocol version %d", FmlProtocolVersion);
187 if (FmlProtocolVersion != 2)
189 SetError(fmt::format(FMT_STRING(
"Unsupported FML client protocol version received in ClientHello: {}"), FmlProtocolVersion));
194 SetError(fmt::format(FMT_STRING(
"Received unexpected length of ClientHello: {}"), a_Data.size()));
204 LOGD(
"Received ModList");
208 for (
auto & item: ClientMods)
210 ClientModsString.append(fmt::format(FMT_STRING(
"{}@{}, "), item.first, item.second));
213 LOG(
"Client connected with %zu mods: %s", ClientMods.size(), ClientModsString);
218 if (
cRoot::Get()->GetPluginManager()->CallHookLoginForge(a_Client, ClientMods))
220 SetError(
"Modded client refused by plugin");
229 const auto ModCount = ServerMods.size();
235 for (
const auto & item: ServerMods)
253 if (a_Data.size() != 2)
255 SetError(fmt::format(FMT_STRING(
"Unexpected HandshakeAck packet length: {}"), a_Data.size()));
259 const auto Phase =
static_cast<Int8>(a_Data[1]);
260 LOGD(
"Received client HandshakeAck with phase = %d", Phase);
270 bool HasMore =
false;
271 AString RegistryName =
"potions";
273 UInt32 NumSubstitutions = 0;
290 LOGD(
"Client finished receiving registry data; acknowledging");
301 LOGD(
"Client is pending completion; sending complete ack");
320 SetError(fmt::format(
"Received unknown phase in Forge handshake acknowledgement: {}", Phase));
334 SetError(fmt::format(FMT_STRING(
"Received unexpected Forge data from non-Forge client ({} bytes)"), a_Data.size()));
339 LOGD(
"Received unexpected Forge data when in errored state, ignored");
343 if (a_Data.size() <= 1)
345 SetError(fmt::format(FMT_STRING(
"Received unexpectedly short Forge data ({} bytes)"), a_Data.size()));
std::basic_string_view< std::byte > ContiguousByteBufferView
std::basic_string< std::byte > ContiguousByteBuffer
void LOG(std::string_view a_Format, const Args &... args)
std::map< AString, AString > AStringMap
A string dictionary, used for key-value pairs.
Discriminator byte values prefixing the FML|HS packets to determine their type.
static const Int8 ServerHello
static const Int8 ModList
static const Int8 ClientHello
static const Int8 HandshakeAck
static const Int8 RegistryData
Client handshake state phases.
static const Int8 PENDINGCOMPLETE
static const Int8 WAITINGSERVERCOMPLETE
static const Int8 WAITINGSERVERDATA
static const Int8 COMPLETE
Server handshake state phases.
static const auto COMPLETE
static const auto WAITINGCACK
An object that can store incoming bytes and lets its clients read the bytes sequentially The bytes ar...
void ReadAll(ContiguousByteBuffer &a_Data)
Reads all available data into a_Data.
bool WriteBEInt32(Int32 a_Value)
bool ReadVarInt32(UInt32 &a_Value)
bool WriteBool(bool a_Value)
bool WriteVarUTF8String(const AString &a_Value)
bool WriteBEInt8(Int8 a_Value)
bool WriteVarInt32(UInt32 a_Value)
bool ReadVarUTF8String(AString &a_Value)
bool Write(const void *a_Bytes, size_t a_Count)
Writes the bytes specified to the ringbuffer.
void FinishAuthenticate()
Finish logging the user in after authenticating.
const AStringMap & GetForgeMods(void) const
Returns the Forge mods installed on the client.
void SendPluginMessage(const AString &a_Channel, std::string_view a_Message)
AStringMap m_ForgeMods
Forge mods and versions installed on this client.
UInt32 GetProtocolVersion(void) const
Returns the protocol version number of the protocol that the client is talking.
bool m_Errored
True if the Forge handshake is in an errored state.
void AugmentServerListPing(cClientHandle &a_Client, Json::Value &ResponseValue)
Add the registered Forge mods to the server ping list packet.
void HandleClientHello(cClientHandle &a_Client, ContiguousByteBufferView a_Data)
void SendServerHello(cClientHandle &a_Client)
Send the ServerHello packet in the Forge handshake.
AStringMap ParseModList(ContiguousByteBufferView a_Data)
Parse the client ModList packet of installed Forge mods and versions.
void SetError(const AString &message)
Set errored state to prevent further handshake message processing.
void BeginForgeHandshake(cClientHandle &a_Client)
Begin the Forge Modloader Handshake (FML|HS) sequence.
void HandleModList(cClientHandle &a_Client, ContiguousByteBufferView a_Data)
bool IsForgeClient
True if the client advertised itself as a Forge client.
void HandleHandshakeAck(cClientHandle &a_Client, ContiguousByteBufferView a_Data)
void DataReceived(cClientHandle &a_Client, ContiguousByteBufferView a_Data)
Process received data from the client advancing the Forge handshake.
cServer * GetServer(void)
const AStringMap & GetRegisteredForgeMods(const UInt32 a_Protocol)
Get the Forge mods (map of ModName -> ModVersionString) registered for a given protocol.