SpongeAPI icon indicating copy to clipboard operation
SpongeAPI copied to clipboard

A new chat event for messages that should not be treated as normal chat

Open Katrix opened this issue 8 years ago • 8 comments

It would be nice to have a separate chat event for messages that gets sent as chat, but should not get the normal chat formatting. This could for example be used to replace or remove word from commands that also function as chat, but should not get the normal chat formatting.

This is currently possible by using a MessageChannelEvent, but that one can't be cancelled, so it's more of a dirty hack.

Katrix avatar Jul 09 '16 20:07 Katrix

E.G.

We currently have MessageChannel.Chat

Private messages should be counted as chat, but not formatted as chat, as should /say and /me commands.

This idea means having some sort of a MessageChannel.Chat.Global which would be the standard chat formatting, leaving plugins to be able to implement MessageChannel.Chat.PM

Plugins wishing to do text replacements could listen to .Chat and cover all usecases of chat, without stepping on "primary formatting" plugins responsible for how the global chat should look.

ryantheleach avatar Jul 09 '16 23:07 ryantheleach

Well, from what I know, your best bet is to insert a named cause (perhaps "type", "pm" or "type", "global") into the message channel cause and then use message channels to format it as you want. For example, say you want to ignore any messages that are not private messages. You would insert the "type" "pm" named cause into the event when you call it, then in a listener, set the message channel to something like this: MessageChannel#combined(new PMChannel(), event.getChannel().get()) Of course, this relies on the event having a channel to begin with, but if it is to be sent to anyone this is a safe call. You can then specify in the PMChannel#transform(Object sender, MessageReceiver recipient, Text original, ChatType type) method how the pm should be formatted. The original text message in the message channel will be what other plugins modify the message to be (for instance, a swear word removed from it), and then you can format it as you please.

From what I can tell, this is what would work best as ryantheleach has explained it. Because the MessageChannel#combined() method does transforming in order of channels supplied to it, you can decide what channels format the message in order. This could allow for a ChatMessageChannel to format first, then a PMMessageChannel or GlobalMessageChannel to do their formatting afterwards. You can then edit words or whatever in the ChatMessageChannel object and then format messages in the others. The only caveat is that this relies on other plugins not submitting their own formatting message channels after yours, however there isn't really anything you can do about that until ways for plugins to communicate are provided.

I hope this helped!

Wundero avatar Jul 31 '16 00:07 Wundero

The problem I see with that approach is twofold.

First of you loose basically all the advantages of doing chat formating in the event itself if you instead use channels for it as you can no longer differentiate between the header, body and footer of the message.

The bigger problem however is that it is an completely opt in system. Yeah sure, more freedom is good, but if you actually look around, none of the big Chat plugins use the header, body footer, system, and instead just use toPlain() or similar, which interferes quite a bit with plugins that do use that part of the API. To have a type parameter in the cause, and format based on that could allow more freedom (as long as people actually followed it), but I don't feel it is quite as good a solution as having different events.

Katrix avatar Jul 31 '16 01:07 Katrix

Having a cause could work well, but SpongeAPI would need to provide a number of inbuilt causes for it to be useful.

ryantheleach avatar Jul 31 '16 04:07 ryantheleach

I have a problem with the way ryan suggested the events be added, however.

As far as I can tell, there are only a few possible ways of solving the problem:

Adding new events (as you have stated):

  • This is a good option as far as separating from currently active chat plugins goes
    • This is only because the way to get the raw message is with MessageChannelEvent.Chat and not with the raw event
  • This is a bad option in that the type of message is not customizable
    • This means that, if you were to have MessageChannelEvent.PM, .Chat, .Global, etc., they would have to be a fixed list of events; this eliminates the ability to have different types of messages for different plugins. For example, if I had an internal message type TEAM_MESSAGE that applied to minigame teams, the way these events are handled would not support it
  • Part of the reason for these separate events is to determine who receives the chat message, but that is determined by the channel so that eliminates the reason to specify additional events as far as target goes

Allowing formatters to combine:

  • This is a good option to try to incorporate multiple plugins editing a message at once
  • However, this would not eliminate the opt-in problem you presented, as plugins will probably still choose to edit it manually with disregard to the formatter

Having a MessageType object stored in the event:

  • This would allow specification for message types and how they should be handled
  • Again, this is opt-in (I can't think of a way to force people to run checks on the type, even if setMessage has MessageType as a parameter)
  • This would solve the customization issue of the events, but not the opt-in issue

Using MessageChannels:

  • This allows multiple plugins to format and removes opt-in worries as this is the last word in how a message looks
  • The problem with this is that there are, as you mentioned, no ways to differentiate the message. The way I've dealt with this is by solely using the raw message of the event and completely handling formatting my way, but this eliminates the usefulness of the formatters altogether.

You could, of course, try to create a pull request that gives MessageChannels the ability to view header, body and footer as separate objects (perhaps pass the event's TextFormatter or a TextFormatter generated with the send method instead of the original text, and then return said formatter), however for the time being there are no real solutions that cover what you want. Events are probably the closest, however they stifle the ability for plugins to handle separate events as separate messages through internal means.

I've tried to list the pro's and con's of each method, hopefully this can help people with this for now.

Wundero avatar Aug 01 '16 02:08 Wundero

From Discord: " SquidDev - Today at 1:11 AM Hello! I've recently had an weird cross-mod interaction which, while no mod is really at fault, probably counts as a bug. Just thought I'd chuck it here to see if anyone had any thoughts. Nucleus has a "staff chat" system, which forwards chat messages to a separate MessageChannel. However, posting messages will also fire Forge's ServerChatEvent - this will then be picked up by Computronics' chat boxes, allowing any user to read staff chat. This is obviously undesirable, but I can't see any solution to this which isn't going to cause more problems than it solves. "

ryantheleach avatar Jul 29 '18 17:07 ryantheleach

Given causes, would it be worth firing the chat event intertwined with another event, with the OG event as the cause?

This would let people filter chat events for death etc to do death formatting.

This would have the added advantage of the chat event being able to be cancelled as well.

ryantheleach avatar Jul 29 '18 17:07 ryantheleach

We could definitely do with a way to mark message channels as "for chat-related modification" and "for chat-related global readability".

pie-flavor avatar Jul 29 '18 17:07 pie-flavor