It would be an assumption to say "Internet is now pretty fast and reliable" as @Ordous pointed out, and a dangerous one too.
The reason why UDP+custom protocol for delivery-critical packets does magic on most games is that, there are times when it could be "okay" if you lose some packet (just for. e.g. secondary non-critical events to complete game play), there are also times where its "not at all okay" to lose some data for e.g cursor movement etc. (I don't do game development for a living so pardon my vague-ish examples)
UDP doesn't waste time in pushing them again and again, by default.
And, many games incidentally seem to have the "okay to lose sometimes" packets more than "always need to deliver without fail" packets. Hence making a natural fit for this task.
All that was needed on UDP was to use a custom protocol that just helps deliver the "always need to deliver without fail" packets properly, leaving the rest of game data to the mercy of the network connection.
Now deciding on what kind of traffic makes up most of YOUR data to be transmitted across will help you decide better.
The point against TCP would be that time spent on retries could rather be spent on sending packets that matter NOW.
There is also a chance that if there is any issue during transmission, TCP could cascade to a more broken down game-play scenario for the user, spoiling their experience compared to UDP+Custom Stack (This last part is just hunch. I will leave this to other experts here to comment on this. Would love to learn about possibilities of this scenario).
internet is now pretty fast and reliable
No, it's not. The bandwidth has dramatically increased, yes, but latency is still quite high. With pure TCP you need the server tick time to be more than the max affordable latency, unless you do packet squishing - which is best done at the client via UDP. The problem is that some info in a game needs to be reliable, while some other needs to be fast. Custom protocols on top of UDP allow for that, as well as a bunch of proprietary ones that give you everything you need in a nice package.t0
that is never received, then you send the new world state at timet1
, you don't have to wait until the client actually receive the first package, which is already obsolete.