ProtocolLib

3M Downloads

How to set content in ClientboundSystemChatPacket?

kangarko opened this issue · 5 comments

commented

Make sure you're doing the following

  • You're using the latest build for your server version
  • This isn't an issue caused by another plugin
  • You've checked for duplicate issues
  • You didn't use /reload

Do ProtocolLib provide wrapper for setting content of the chat message in the ClientboundSystemChatPacket? I spent countless time trying to figure out to no avail, looks really complex since they introduced their Adventure library. Thanks for the help.

KyoriPowered/adventure#902

commented

Hello @kangarko did you find a solution? I have the exactly same problem and I am stuck with no options

commented

Got more information about this at a Paper issue. Do you know how to replace the chat packet? We have a large consumer base using packet integration with the chat packet to replace system chat messages, I'd appreciate your help in this!

#2330

commented

Yes and no, I tried just sending a new packet and cancelling the old one but it seemed to cause a race condition and we need further investigation: kangarko/Foundation@8374209

commented

For plain Spigot, the correct way to modify the content would be the following which just replaces the JSON encoded chat component that is stored in a String

Reading:

WrappedChatComponent message = WrappedChatComponent.fromJson(packetContainer().getStrings().read(0));

Writing:

packetContainer().getStrings().write(0, WrappedChatComponent.fromText("Test").getJson());

However, if you are using Paper, this could potentially break as they introduced another field that takes an Advanture Chat Component as a content. If this field is non-null, the JSON encoded message mentioned above will be completely ignored.

The way for accessing the Advanture component would be container.getSpecificModifier(net.kyori.adventure.text.Component.class).read(0) resp. container.getSpecificModifier(net.kyori.adventure.text.Component.class).write(1). However, this requires that you have Adventure in your Classpath and you are using Paper. I'd suggest doing something like this for the best compatability:

@Override
public void onPacketSending(PacketEvent event) {
    PacketContainer container = event.getPacket();

    WrappedChatComponent component = null;
    try {
        StructureModifier<Object> adventureModifier = container.getModifier().withType(AdventureComponentConverter.getComponentClass());
        if(!adventureModifier.getFields().isEmpty()) { // Only true on Paper
            net.kyori.adventure.text.Component comp = (net.kyori.adventure.text.Component) adventureModifier.read(0);
            if(comp != null) {
                component = AdventureComponentConverter.fromComponent(comp);
                adventureModifier.write(0, null); // Reset to null - the JSON message will be set instead
            }
        }
    } catch (Throwable ignored) {} // Ignore if paper is unavailable

    if(component == null) {
        component = WrappedChatComponent.fromJson(container.getStrings().read(0));
    }

    // Modify component here
    container.getStrings().write(0, component.getJson());
}

Please not that this code is untested

commented

@lukalt love it, thanks! Got it working WITHOUT importing Adventure at all, if anyone needs the code here it is: kangarko/Foundation@9ed1a29