Page 1 of 5

Modifying chat with sayfilter but SayCommand doesnt "register"

Posted: Tue Mar 29, 2016 12:49 am
by decompile
Hey,

I talked already to Ayuto about my problem but maybe you can help me out there.

So I'm modifying my chat currently with the SayFilter & coloring it and sending it modified out with SayText2, but my problem is when you CommandReturn.BLOCK the sayfilter (so the old message wont get shown) the SayCommand doesnt register anymore, so right now I need to write a decorator with player_say and hook every function with it, kinda stupid when you can use the awesome SayCommand's

Posted: Tue Mar 29, 2016 2:49 am
by satoon101
You can find out if a command is registered by SP using the command generator:
http://forums.sourcepython.com/showthread.php?191&p=6241&viewfull=1#post6241

So, my suggestion would be to not change the text in the say filter if the command is in SayCommandGenerator().

Posted: Tue Mar 29, 2016 11:44 am
by decompile
That will work, but Isnt there another way so I can modify the chat with colors even when the player writes a command?

Posted: Tue Mar 29, 2016 12:30 pm
by satoon101
The only other way that I can think of would be to hook the user message itself instead of using a say filter.
http://forums.sourcepython.com/showthread.php?980

We still do not have a built-in way to do this, though it is still planned.

Posted: Tue Mar 29, 2016 1:46 pm
by iPlayer
Is there a way to dispatch a command to CSayCommandManager from python though? If there were, it would be possible to block the string, but if the string is present in the command generator, we would dispatch it to the command manager so that it will call its callbacks.

Posted: Tue Mar 29, 2016 2:03 pm
by satoon101
We could add that in, but it would only help in the case where commands were registered by SP. Meaning that if a server also uses SourceMod, it would still block any commands registered with SM. The cleanest way would be to hook SayText2, get the msg_name, and override it if the message is a normal chat message. That would also help to keep the same RecipientFilter on say_team as well as dead/spec player chat.

Posted: Tue Mar 29, 2016 2:07 pm
by iPlayer
No, please don't add that in, that's not what should be accessible from python plugins. At least there're no other reasons for it, and for current case registering usermessage hook is better. Espsecially since there're plans for built-in support for it.

Posted: Tue Mar 29, 2016 4:15 pm
by decompile
satoon101 wrote:The cleanest way would be to hook SayText2, get the msg_name, and override it if the message is a normal chat message. That would also help to keep the same RecipientFilter on say_team as well as dead/spec player chat.


Im not realy understanding the way how to override it, the example in the link shows how to get it but afterwards to block the old msg and send the new (or however that works)

Posted: Tue Mar 29, 2016 4:26 pm
by iPlayer
No, I assume the example in the links shows how to get ProtobufMessage object of the sent message, then you can alter it, for example,

Syntax: Select all

buffer.set_string('msg_name', "My message")

However, I'm not sure if that works if the game uses bitbuf messages

Posted: Tue Mar 29, 2016 4:55 pm
by Ayuto
iPlayer wrote:No, I assume the example in the links shows how to get ProtobufMessage object of the sent message, then you can alter it, for example,
[PYTHON]buffer.set_string('msg_name', "My message")[/PYTHON]

Exactly! Though, I should mention that the code in the other thread isn't working anymore, because I have changed the internal structure some months ago. But getting a ProtobufMessage is now much easier. You just need to use memory.make_object(ProtobufMessage, args[3]). I can update the code if anyone needs it.

Posted: Thu Mar 31, 2016 11:00 pm
by decompile
Can someone post a snippet and comment it? Hard to understand for me

Posted: Tue Apr 05, 2016 11:22 pm
by decompile
Wouldn't it be possible to make a check before the CommandReturn.BLOCK, if its a command it gets fired (as usual) but still get blocked, thats how I Thought it could be possible

Posted: Wed Apr 06, 2016 5:06 am
by iPlayer
That's basically what I proposed, but it won't work with SM commands. No, hooking is surely better.

Posted: Wed Apr 06, 2016 7:53 pm
by iPlayer
decompile, try this (props to Ayuto for original code)

Syntax: Select all

from commands.say import SayCommand
from memory import Convention, DataType, get_object_pointer, make_object
from memory.hooks import PreHook
from messages import SayText2
from engines.server import engine_server
from messages import UserMessage
from _messages import ProtobufMessage


saytext2_index = UserMessage(RecipientFilter(), 'SayText2').message_index

# virtual void SendUserMessage( IRecipientFilter &filter, int message, const google::protobuf::Message &msg ) = 0;
send_user_message = get_object_pointer(engine_server).make_virtual_function(
45,
Convention.THISCALL,
[DataType.POINTER, DataType.POINTER, DataType.INT, DataType.POINTER],
DataType.VOID
)


@PreHook(send_user_message)
def pre_send_user_message(args):
message_index = args[2]
if message_index != saytext2_index:
return

buffer = make_object(ProtobufMessage, args[3])

player_name = buffer.get_repeated_string('params', 0)
message = buffer.get_repeated_string('params', 1)
buffer.set_string('msg_name', "\x02{} \x01says: \x10{}".format(player_name, message))


@SayCommand("!test")
def say_test(command, index, team_only):
print("Issued !test by (index={})".format(index))


Everything works. Note how I used params to get the initial name and message and then msg_name to create a new one. Initial msg_name only contains string like Cstrike_Chat_AllDead

Posted: Wed Apr 06, 2016 8:25 pm
by satoon101
Correct me if I am wrong, but I am fairly certain you can still use the original msg_name and just modify the first parameter. This will help to keep the full original message intact, including the *DEAD* and *SPEC* tags, which will still be shown in the clients language.

*Edit: same goes for the player's team and location in team chat messages.

Posted: Wed Apr 06, 2016 8:27 pm
by iPlayer
Yeah, I thought of it, but what if you want, you know, change the formatting? Like in my example, it shows something like
iPlayer says !test

While the game would have printed
iPlayer: !test


The good thing is that SayCommand still fires when the whole message is included in msg_name.

EDIT: What is more, when inserted in, say, params #0, colors don't seems to work as they usually do, I only get team color and white.

Posted: Wed Apr 06, 2016 10:35 pm
by decompile
Is it possible to make it possible that alive players can see dead messages and spectator messages?

EDIT:

Thank you for the start!

Posted: Wed Apr 06, 2016 10:42 pm
by iPlayer
Try this

Syntax: Select all

from filters.recipients import RecipientFilter

# ...


@PreHook(send_user_message)
def pre_send_user_message(args):
args[1] = RecipientFilter() # If we don't pass any filters, this RecipientFilter will target all existing players

# ...

Posted: Thu Apr 07, 2016 6:40 am
by Ayuto
Better just call make_object(RecipientFilter, args[1]).add_all_players(). But I think there is a ConVar as well. Just can't remember its name.

Posted: Thu Apr 07, 2016 4:33 pm
by decompile
When im trying to load it, Ill get

Syntax: Select all

from _messages import ProtobufMessage

ImportError: cannot import name 'ProtobufMessage'


Current Source.Python version: 304