I’m thinking TCP for chat and UDP for tracking movements but do they need to be on separate servers?
No, they don't need to be on separate servers. Although separate servers has its own advantages. By the way, when I say server, I mean the process, not the machine. Servers could be on the same machine, or different machines.
Do I have to redo it all in python on the server side for scaling in the future? Or for cross platform?
Design an application protocol on top of UDP, TCP, both, whatever… As long you implement that protocol, the language you use matters little. In fact, the server and the client could be implemented in different languages. With that said, I would encourage to use a languages and platform with good threading support. There are plenty of option, even cross platform options.
Furthermore, client and server might not be monolithic. For example, you can write them as applications in one language, and use libraries written in another language. And for the library anything that can expose a C interface is fair game.
Perhaps your initial instinct is to have your application in your preferred language, and then the network code will be a library it calls. However, let me tell you, it can be the other way around. Have the main application do the networking and call into a library in your preferred language that handles the rest (UI et.al. on the client, and game logic on the server). In fact, the client can be one way and the server the other.
The network is a big scary thing in the middle of your architecture. And deciding how to deal with that can shift your entire architecture. Reason why it is common advice to decide early if you will have networking in your game/engine.
I usually suggest to start with TCP (or some other protocol or solution that guarantees reliability), and to start with a chat-like proof of concept. If you can send strings, you can send anything (to be clear, I'm not suggesting to have a human readable string encoding for everything).
However, move to UDP (or similar), so you can have control over the reliability model (either because you roll your own, or by using a third party solution).
As per networking framework, avoid those that:
- Do not give you reliability options.
- Do not support threading.
Now, let us say you want to take your existing code and somehow shoehorn networking into it. Start by figuring out what parts need to be on the server, and what parts on the client.
As, you know, the server should not be doing the game UI (if the server has some UI at all, it is to control the server). Thus, the code to draw the map, characters, and so on does not need to exist on the server. But there will be a logic representation of those in the memory of the server.
For the architecture of the client, in preparation of moving to a networking solution, you want to isolate anything that should run on the server. You will likely want the server to run physics, for example. That isolated component should not depend on implementation details of the rest of the client to work. And you want to put it behind some form of asynchronous interface.
Then, move that code to a library. Use the library in the server. As long as the server can call into that library, it does not matter if the library and the rest of the server are written in different languages. You would only be forced to recreate that code in a different language for the server, if you cannot create such library.
Once the server has that code, replace the code in the client to connect to the server instead of using the library.
Note: The client can call into the library. But should not be able to get a result synchronously. Furthermore, the library cannot call code on the rest of the client, because that requires knowledge of it. Instead, have a function that the client can call to get any results since the last time it was called. Make calling that part of your game loop equivalent. Once it is not calling into the library, but into the network, that same function will return any network messages since the last time it was called. It might be possible to build a callback dispatch solution, but it does not always make sense.