1. The MSG_Read[Big]String transforms '%' to '.', the MSG_Write[Big]String does not. The write functions should be fixed.
2. (Let's call the '%' and extended ASCII characters non-net chars.)
Com_HashKey is a common function that hashes a string. The client scrambles all usercmds with the Com_HashKey() value of the last received/acknowledged server-to-client reliable command (I think to verify that it DID receive that command in case it says that it received it), and the server unscrambles them with it.
The problem is that on the server Com_HashKey() is used BEFORE/WITHOUT non-net to '.' conversions take place. That is, the server version of the server-to-client reliable commands are raw, but they are changed when transmitted to the client (through the MSG functions). The result is that if the server tries to send a command with non-net chars to a client, the server and client Com_HashKey() value will differ, and usercmd misinterpretation will occur (aka, bug 2719).
This behaviour was not noticed because when the clients send chat or other commands, they will have been MSG-processed by the time the server tries to do something with them, like broadcast it to everyone. And seemingly the server game has never sent non-net chars on its own.
Com_HashKey should be ditched and a new NET_HashKey or MSG_HashKey should be used instead, which differs from the original one only in that it behaves as if the given strings are MSG-processed, that is, it should use '.' for every non-net char.
PS: I believe we can cross-compatibly change the net code to use non-net chars across ioquake3 clients: on ioq3 servers, non-ioquake3 clients will see '.', but will suffer no other side effects, and ioq3 clients will be able to use non-ioq3 servers as well. But nontheless, I think the above should be fixed for now.
Created attachment 2056 [details] bug reproduction and fix testcase
Created attachment 2057 [details] process '%' in write functions; new cross-compatible string hasher Still needs to be tested.