We decided not to use TCP because I have heard there is a lot of overhead and it is slower/less efficient. UDP with custom error/loss checking will be much more efficient.
The main point is that the high level multiplayer code to transfer commands and execute them at exactly the same time works almost perfectly. On each PC everything appears identical.
Hmm, per se this is not always correct. The "large" overhead comes into play on establishing a connection between two computers. For that case, some packets have to be sent and received. But if you use keepalive, this has to be done only once - when entering the game. The connection can be kept open, so practically no more overhead is needed except the keepalive packets which should not interfere with your network load.
When the connection is established, the difference in header length is only 12 bytes (TCP/IP over Ethernet: 54 bytes minimum, UDP/IP over Ethernet: 42 bytes minimum; each depending on network configuration, not counting gaps).
The payload for each packet is slightly lower than 1460 bytes. But if you need the correct order of incoming packets (if you transfer the commands), then you will need to send at least two int numbers (probably 4 bytes each), thus reducing the overhead size advantage of UDP once more.
On the backside, you have to implement an error correction algorithm for catching the arriving problem, which may be very buggy. So why not use the well-tested TCP-stack of your OS in the first place?
The reason why most (Ego-Shooter) games use UDP is, because they send the current status update of the player rather than the commands. The whole status usually cannot be sent each time because this probably is too large, so only the updates are sent and the whole status is synchronized only once a while. If one packet is not acknowledged to have arrived, the next UDP-packet sends the current status update plus the not-arrived status update, which means larger packets. With TCP you don't have to write this kind of algorithms.
In the real world, TCP with high-latency and/or bad connetions could cause anything from slight to heavy lags because TCP will try to resend each lost packet until the arrival is acknowleged.
With UDP you won't see this as an effect of packet loss, but it's completely up to your skill of writing error catching algorithms. If you have a good idea on this, UDP may be the best choice. If a command packet is lost and the client has to wait until the synchronizing packets arrived, a huge lag could appear and completely alter the game status.
If you really send the commands only, I would consider picking TCP.
If you have fun in the challenge of developing a good error catching, then go with UDP
