Badly wanted: Somebody who make simutrans TCPIP compatible, i.e. can use sockets to transfer the game over the net. Further discussion can be done also in this thread.
What is the behavior intended? If it is only the technical problem of creating the socket and transfer some information, it shouldn't be difficult since SDL includes a net subsystem. I can help there.
Or is the topic to put the basis of generating a sort of real-time multiplayer over the net?
It must use Posix sockets, and for the first step the problem ist to extend loadsave.cc in such a way, that games can be saved and loaded over the net. A routine to send and recieve data blocks over the net would be helpful too as a starting point.
SDL is not useful, since it does not compile on BeOS and cannot suuport Unicode 2Byte characters properly. Any network code should work on all machines (Posix) ...
Now I understand better... So, the goal is to, let's say, click on an "Open game from network" button, specify an IP address and port and get a list of available saved games, click on one and then load the game as usual. Is that so?
If that's the case, the game repository is managed by another application or by another copy of simutrans running there? That's important since simutrans can be a client only or a client and a server.
I've had a look to the
loadsave.cc file and noticed that
FILE * are used for file transfer. In UNIX, there is a very nice function
fdopen, which gives a
FILE * from a file descriptor. The procedure for a load could then be:
- Creating a socket (this will give a file descriptor)
- Opening a connection to the server
- Getting a FILE * from the file descriptor of the socket
- Use the methods in loadsave.cc directly
The method should be compatible with existing formats: text, binary and gzipped.
I've had a look at msdn and seems that that function, although deprecated, is also available in Windows.
I would prefer to write directly to the sockets to avoid buffering. This is especially important during the game when commands are transferred through the connection. But if this filke from sockets works under windows, you can give it a try.
But the idea is to have a cooperative game, i.e. a simutrans version acting as a server and the same exes connecting to it. The server than sends the savegame to one client together with a lease (and to other without a lease). THis could be time in game years or real time. THe game must be checked in before the lease expires and can then be modified by someone else.
Flushing the FILE * with fflush can do the trick.
But then there is one question left: if the simutrans exe will be the server and the client we must create a new thread to wait for and serve connections. Again, SDL has threads, but is there another portable alternative?
Posix threads are there since computer stone age (more or less).
Sure. From "silicon" age, I dare say. ;) But they are not directly portable to Win32:
http://blogs.msdn.com/hpctrekker/archive/2008/07/03/a-unix-to-windows-porting-topic-threads-and-processes.aspx (http://blogs.msdn.com/hpctrekker/archive/2008/07/03/a-unix-to-windows-porting-topic-threads-and-processes.aspx)
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnucmg/html/UCMGch09.asp (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnucmg/html/UCMGch09.asp)
Either we use system-dependent code or an external library like the one pointed by the first link (which includes more external dependencies). Can pthreads be directly used for other targets: macs, BeOs,...? It is a pity that SDL doesn't work with BeOs since it gives the proper platform-independence needed.
I will try some test code with an external server first, and God will provide pthreads or whatever...
Here is some preliminary work. The server is simserver.c. You have to start it with the name of a file containing a saved game. It will listen to port 12121 and wait until anything connects there. It then gives the file, with no further protocol, and closes connection with no farewell whatsoever.
The second part is a patch for simutrans so that when loading a file, you can enter something like:
net:IP_address:PORT (e.g. net:127.0.0.1:12121), at the input box of the load game window.
If so, it will try to connect to the IP address and port and get the saved file from there.
I've tested both progs in Linux with localhost address (127.0.0.1) and it worked. I don't have any Windows installation to test them at hand. Sorry. I guess it will require some headers to be changed... :(
By the way, fdopen is not really needed since there is a pretty function in zlib that does the job: gzdopen. Some other things had to be changed since, with no protocol defined, you cannot "rewind" the opened connection to, for instance, reopen the file without the compression layer if the file is not compressed.
And one last thing, while debugging, gdb protested against this line in vehikel_besch.h:190:
return prev_veh = 0;
Should it be == instead of =?
I have a VISTA laptop and a XP machine, im also installing linux ubuntu, without succes so far. So if you need any help please say so :). I cant help with coding though, im only familiar with Actionscript 3(flash) and a tad bit of C# C++.
Als usual lately, my comments in erverse order:
Thank for the prev_veh bug.
That you cannot rewind is not a problem, since I doubt I will send uncompressed games over the net ...
inet_anon windows does not know. Also some other include files are needed and the network needs to be initialized at least one. No big deal, will look into it.
EDIT: code is running, but zlib does not allow calls with a socket as file descriptor under non Unix systems. :(
EDIT2: working version; the server must be run as admin due to the firewall. Since zlib does not work on sockets, any networkgame is first saved as temp-network.sve in the savegamefolder. Any savegame with this name is of course lost.
To compile simserver.c under windows, either use "gcc simserver.c -lwsock32" oder in MSVC you need to add wsock32.lib to the linker tab.
Quote from: the almighty snark on November 23, 2008, 09:35:16 AM
I have a VISTA laptop and a XP machine, im also installing linux ubuntu, without succes so far. [...]
Thanks for the offer. About linux, sometimes it is harder to install on new laptops. If the laptop is old and the problem is the hard disk, try Dapper. The new libata drivers for PATA devices are very buggy.
Quote from: prissi on November 23, 2008, 07:43:41 PM
Thank for the prev_veh bug.
Here's another warning. It doesn't make any sense to me, but perhaps lines 81 and 82 of
depot_frame.cc can be swapped to make gcc happy:
gui/depot_frame.h: In constructor 'depot_frame_t::depot_frame_t(depot_t*)':
gui/depot_frame.h:111: warning: 'depot_frame_t::scrolly_electrics' will be initialized after
gui/depot_frame.h:110: warning: 'gui_scrollpane_t depot_frame_t::scrolly_pas'
gui/depot_frame.cc:65: warning: when initialized here
Quote from: prissi on November 23, 2008, 07:43:41 PM
EDIT: code is running, but zlib does not allow calls with a socket as file descriptor under non Unix systems. :(
That's really a pity. I will try to investigate if there is a workaround.
Quote from: prissi on November 23, 2008, 07:43:41 PM
To compile simserver.c under windows, either use "gcc simserver.c -lwsock32" oder in MSVC you need to add wsock32.lib to the linker tab.
gcc doesn't recognize
SOCKET and
closesocket in my installation. In the attachment, I've changed that. The same problem happens with the code in the patch. An easy workaround is to add this at
loadsave.cc:
#include <zlib.h>
#ifndef WIN32
typedef int SOCKET;
#define INVALID_SOCKET -1
#endif
loadsave_t::mode_t loadsave_t::save_mode = binary; // default to use for saving
There was also a typo in the patch in
simmain.cc: an extra dot in
#include "network/network.h"
Sorry for the long post, but one last thing: once the server is integrated in the main exe, what file should it serve? The current one? Should it offer all possibilities in the
save folder? Should the player be interrupted and be asked?
EDIT: Three ideas to make
gzdopen work. If they don't work, I give up:
- Simple one: fp = (FILE *)gzdopen((int)sock,"rb");
- More elaborate one (#include <Mswsock.h>), instead of connect:
if(!ConnectEx(sock,(struct sockaddr *)&server_name,sizeof(server_name),NULL,0,NULL,NULL)) {
//TODO: some feedback for errors
dbg->error("loadsave_t::rd_open()","Cannot connect to %s",cp);
return false;
}
fp = (FILE *)gzdopen((int)sock,"rb"); - Still more elaborate one (#include <Mswsock.h>,<fcntl.h>), instead of connect:
if(!ConnectEx(sock,(struct sockaddr *)&server_name,sizeof(server_name),NULL,0,NULL,NULL)) {
//TODO: some feedback for errors
dbg->error("loadsave_t::rd_open()","Cannot connect to %s",cp);
return false;
}
fp = (FILE *)gzdopen(_open_osfhandle(sock,_O_RDONLY),"rb");
I cannot check, though...
As far a google told me, FileWrite fails on a socket in Windows. Thus zlib will fail too. But I will check.
EDIT: it fails. But this is not a problem, since every client must save and reload its local game anyway to keep them in sync, because during load time too many things are changed.
What a pity. What about this question:
Quote from: isidoro on November 24, 2008, 05:14:07 AM
[...] once the server is integrated in the main exe, what file should it serve? The current one? Should it offer all possibilities in the save folder? Should the player be interrupted and be asked?
I have a question, how will the different companies be integrated? For i presume players will play with there own company? So how would they take control of there lines when loading the game back with more or fewer players?
The player system is under overhaul anyway. I think there will be passwords for each company, and to change to a player you need either be public player or know the password.
Interesting way of making it MP! I hope it will turn out well!.
Quote from: prissi on November 27, 2008, 09:33:21 PM
The player system is under overhaul anyway. I think there will be passwords for each company, and to change to a player you need either be public player or know the password.
password = ip-adress ?
a problem is private ip-adress, you can doubled
private ip ( 192.168.1.12 ) - router - internet ip 1 / internet ip 2 - router - private ip ( 192.168.1.12 )
or a player hash as password
And a lot of ISP's provide a dynamic IP, so that would confuse the game too.
Now all game relevant settings are in einstellungen_t, a big step forward to consistent synchronized playing.
There is a preliminary version under patches, that knows a server mode and a client mode. The server transfers a game, when a cleint join its. Enter "net:IP-Nummer:Port" as the file to load. (Works on commandline and 127.0.0.1 too.)
Server ist started by -server portnr. That is all. It will send the current game.
I register as a test player, please, please! :)
Or if I get a recipe, I can run the hostserver.
Or I can create a 3rd domain (something like simutransonline.akrangard.cz) on my domain and run hostsserver ...
YOu can only download games, Nothing more, no commands are transferred yet, no synchronisation, nothing. Be patient.
Who is working on this project, this time?
Me, the relevant patches are changing from time to time. Sending command is 95% prepared.
Fine. You are the rock in the sea. :D
But many people would have a network mode. Where are they gone?
Quote from: sojo on January 25, 2009, 08:36:17 PM
But many people would have a network mode. Where are they gone?
sojo, you know: people who
want something are not necessarily people who also
do something. ;)
and the programming of network code is not easy ... ;o)
Can I just ask - why are you using sockets for this and not a higher level protocol?
As I understand it, you have savegame being transferred between players every time slice (or at least some kind of diff of the savegame). That means you can't be too worried about latency over the network.
Why not use a standard protocol such as REST (or just HTTP)? libcurl is cross-platform IIRC.
That would let you make the server far easier - for example I don't see why the server has to be integrated into the main game, or even written in the same programming language. C++ is a great choice for the graphics required for simutrans, but using a standard web server like language like Python or PHP you could get the server written much faster IMO.
I could be mis-understanding though - if you want real-time networking then obviously you do need access to the sockets (although TCP would probably be ok)
As for user passwords for networking, why not generate a random key the first time the game is loaded, save it in the player's directory, and then use that? if you use sufficient entropy to generate the key then collisions should be highly unlikely, and could be checked for by the server.
Using sockets is not that difficult and for realtime needed and has bee already resolved (see patches directory in SVN). The server must run simutrans too (without display) to get the same results than the connected clients.
Hi, Prissi and simufriends. Are you already working on this project? I'm learning C++ to help something. Actually, I developed a front-end on Delphi that sync and lock a game into a svn server. Works like an RPG. Each player makes changes and return the game to the server. It's not a practical idea to public distribute, because I have to register users on subversion server. But we are testing it on a closed group to verify each role (company owners, public manager) and how we interact. Unfortunatelly we still haven't passwords on users, then we have to trust each one. I will posts results here. Perhaps helps to adjust some features to the final network mode.
The network mode is working, but some commands (like creating and starting a convoi) are not yet trnsmitted via network. And the thing is a little instable on joining and exiting ...
How can i start a network server with the code of the svn?
Do I have to compile ST new? With which settings?
Or something else?
There is an #if in simmain.cc just before the string "-server". Change this to #if 1 and change the savegameversion to 103.0. The you start the server with "simutrans -server"
The client you start normally, but load a game for net:127.0.0.1 on the same computer or the IP number (or DNS name) of the server. Default port is 13353.
But convois do not start synchronized, and neither schedules are synchronzied, so this is not working. The AIs will start synchronized though ...
Any way to have per-player passwords?
Be patient. This is now maybe 50% done, and passwords are not needed until it's in a playable state. Let Prissi complete the basics first. I'm sure he has security problems in mind and will not forget about them.
Thanks Hajo. As I writed few posts ago, I'm playing same map with other players. This feature don't necessary need to be related with network mode. Just to help me or others that play in same way, until Prissi ends this job. I understand it. Just asking...
There is already a field for passwords in the current player structure. They are not enforced yet.
One curious thing. I was digging along the archive when I found these interesting posts from
Simutrans is multiplayer (http://archive.forum.simutrans.com/topic/03864.0/index.html) thread.
This is from Prissi:
QuoteMy opinion is, that simutrans uses a pseudo-random geneator, passenger generator is in sync as long as every machine does the same number of simloops per second. So only the simloops have to be synchronized, then the passenger generation and production is synchronized. Since the simloops are not neccessairly connected with the display, missing simloops would not immediately affect the display.
..and this is dschoene's reply:
QuoteYou could avoid most of those problems by going strictly client/server. The server does effectively the same as the game engine does now. It simulates. The clients have the GUI and they do nothing but to send the players UI input to the server and receiving output on what to draw where Basically this would mean that per cycle the server gets (unknown) bytes from each client, does the cycle, and sends 2(mapwidth*mapheight)+(amount_of_client_data_changes) bytes back to each client. This would mean there's not a cat's chance in hell to play it over a dialup line, but even a 64K ISDN line would suffice. As an added bonus you could have bigger maps, if the server is some machine with some serious juice under the bonnet, while the client machines may well be of the moderately powerfull breed.
What for single player games then? Well you can of course install both client and server on the same machine with minimum performance loss over the current monolithic implementation as loopback network traffic is lightning fast.
There's some more bonus. People could program AI clients, which connect to the server, so you might have some seriously smart AI opponents.
Have you consider this approach, Prissi? leaving aside the complexity, it sounds tempting...
Well, that's what I tryng to say on Portuguese Forum (http://forum.simutrans.com/index.php?topic=3355.0). Just graphical front ends to clients and the server doing all the hard work, sending and receiving requests...
Giving the complexity of an average savegame, doing everything only on the server would require sevreal MB/minute. No the easiest way is to keep them running synchronized. The OpenTTD guys choose the same approach, btw ...
I will take a look. Liked the public server index there.
Sorry one question.
Network mode is still working with the latest r2926 version ?
It worked in older versions but in r2926, client can't receive savegame from server.
If I start client with debug option, client starts downloading savegame but that binary data is shown in console window and client can't start game.
Quote
Warning: network_connect: send :ask:game;
Warning: network_check_activity(): recieved 'do:game 488,0;'
Warning: network_connect: received: id=488 len=0
Message: network_recieve_file: Game size 0
Message: gui_textarea_t::recalc_size(): reset size to 100,33
Warning: void release_focus(): Focus was already released
Warning: network_check_activity(): recieved '・'
Message: karte_t::interactive_event(): Keyboard event with code 13 '?'
Warning: network_check_activity(): recieved '@7喬ケx迭キkw燃ソO匀樰Vォ鉀マo7ゥoP#オヲセhココワm・・ァrHキゥッ粥s/・^}[w;'
GCC have issues with printf("%lli"), and thus it is not working at the moment.
would something like this
http://www.opengroup.org/onlinepubs/9699919799/basedefs/inttypes.h.html
help? Ie include <inttypes.h>
Not there on BeOS. In priciple it should help; but I am not sure it actually does. Nevertheless such huge cleint number are probably just bloating network traffic. It would still rather reduced them to an unit8 ...
Quote from: prissi on December 07, 2009, 10:29:06 AM
GCC have issues with printf("%lli"), and thus it is not working at the moment.
I see. Thank you for explaining it.
here is a patch, at least it worked for me on Linux / Kubuntu / g++ 4.4
I fixed all the warnings regarding format specifier "x" expects data typ "y" but argument n is of type "z"
And one change, which fixed a segfault for me in network_check_activity.
Could you please test whether it works on other platforms / compilers? Cannot test at the moment, my windows pc is occupied by my mife :P
Edit: my wife now operates a simutrans server on her laptop .. on windows, the client runs on linux :)
I couldn't do any construction but at least I could receive savegame from server. :)
Sorry about a stupid question. But... How I apply the patch on Linux client? I need to compile everything?
Quote from: Rodrigo Soracco on December 08, 2009, 08:32:03 AM
Sorry about a stupid question. But... How I apply the patch on Linux client? I need to compile everything?
yes.
Quote from: z9999+ on December 08, 2009, 06:52:16 AM
I couldn't do any construction but at least I could receive savegame from server. :)
Could you provide some debug output, where one can see the network commands for both client and server? I had no problems with construction on server or client.
When I click a construction tool, construction tool doesn't activate. It is both server and client.
And when I click oil tank tool on client, server quit without any error dialogue.
An example log of when I click sand_rail tool.
server
Quote
Warning: network_check_activity(): recieved 'ask:init 1475,4200672015,512,4110,0,4,113,-1,sand_track;'
Warning: append command_queue: next: 1508 new: 1508 steps: 1507 init 1508,1502654551,512,4110,0,4,113,-1,sand_track;
Warning: network_send_all(): do:init 1508,1502654551,512,4110,0,4,113,-1,sand_track;
Warning: command_queue: next: 1508 cmd: 1508 steps: 1508 init 1508,1502654551,512,4110,0,4,113,-1,sand_track;
Warning: command: 14:1:簡易線用線路, 35$ (4.00$), 55km/h
Warning: two_click_werkzeug_t::init:
Warning: network_check_activity(): recieved 'ask:check 1476,1332764889'
client
Quote
Warning: network_send_server(): ask:check 1508,3045420671
Warning: command_queue: next: 1508 cmd: 1508 steps: 1508 init 1508,1502654551,512,4110,0,4,113,-1,sand_track;
Warning: command: init 1508,1502654551,512,4110,0,4,113,-1,sand_track;
Warning: command: 14:1:簡易線用線路, 35$ (4.00$), 55km/h
Warning: two_click_werkzeug_t::init:
Warning: network_send_server(): ask:check 1509,3045420671
The data looks ok to me, but most probably the client_id stuff is not working :(
Here is another try on the client-ids. Could you please test whether it works? It works for me on Windows and Linux.
It works for me too. Not tried on BeOS though, only on 127.0.0.1 so far.
It worked, thank you.
But unfortunately, it doesn't work smoothly on my poor PC anymore.
So, I won't try to test network mode any more.
Quote from: z9999+ on December 13, 2009, 11:56:21 AM
But unfortunately, it doesn't work smoothly on my poor PC anymore.
So, I won't try to test network mode any more.
What of this patch eats that much resources?
The patch is now included in trunk. Nevertheless, I can change this part again, if there is another error.
The frame rate of networking game should be fixed at 10 fps or so, since there cannot be a synchronous and asynchronous step anymore. This means, that the slowest PC sets the limit on complexity. Thus a server needs to run at 10 fps at max. to allow nearly all PCs on decent maps to join.
With 10 fps, even my two most complex pak64 games could be handled by by the first 600MHz centrino ASUS netbook throttled down.
Presumably, this can be set easily by the person running the server to allow for variation?
Only before starting the game (although not enorced yet, we need a server GUI panel tooo ... ), since otherwise already connected clients would loose sync. Currently setting only fps from commandline or option via simuconf.tab ensures that.
Can i help, Im starting on c++.
Try to get the source code and compile it as a first step. Look here:
http://forum.simutrans.com/index.php?topic=3228.0
Quote from: viktorht on December 31, 2009, 02:19:36 AM
Can i help, Im starting on c++.
I found this:
/* basic network functionality, borrowed from OpenTTD */
#ifdef _MSC_VER
#include <direct.h>
#else
#include <unistd.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "network.h"
#ifdef __BEOS__
#include <net/netdb.h>
#endif
// Haiku has select in an additional header
#ifndef FD_SET
#include <sys/select.h>
#endif
#include "../simconst.h"
#include "../simdebug.h"
#include "../simgraph.h"
#include "../dataobj/translator.h"
#include "../dataobj/umgebung.h"
#include "../utils/simstring.h"
#include "../tpl/vector_tpl.h"
#ifdef WIN32
#define socklen_t int
#endif
static bool network_active = false;
// local server cocket
static SOCKET my_socket = INVALID_SOCKET;
// local client socket
static SOCKET my_client_socket = INVALID_SOCKET;
static char pending[4096];
// to query all open sockets, we maintain this list
static vector_tpl<SOCKET> clients;
static uint32 our_client_id;
static uint32 active_clients;
// global client id
static uint32 client_id;
uint32 network_get_client_id()
{
return client_id;
}
/**
* Initializes the network core (as that is needed for some platforms
* @return true if the core has been initialized, false otherwise
*/
bool network_initialize()
{
if(!network_active) {
#ifdef WIN32
/* Let's load the network in windows */
WSADATA wsa;
if(WSAStartup(MAKEWORD(2, 0), &wsa) != 0) {
dbg->error("NetworkInitialize()","failed loading windows socket library");
return false;
}
#endif /* WIN32 */
}
network_active = true;
return true;
}
// open a socket or give a decent error message
const char *network_open_address( const char *cp)
{
// Network load. Address format e.g.: "net:128.0.0.1:13353"
char address[32];
static char err_str[256];
uint16 port = 13353;
const char *cp2 = strrchr(cp,':');
if(cp2!=NULL) {
port=atoi(cp2+1);
// Copy the address part
tstrncpy(address,cp,cp2-cp>31?31:cp2-cp+1);
cp = address;
}
struct sockaddr_in server_name;
#ifdef WIN32
server_name.sin_addr.s_addr = inet_addr(cp);
if((int)server_name.sin_addr.s_addr==-1) {// Bad address
#else
#if defined(__BEOS__)
struct hostent *theHost;
theHost = gethostbyname( cp );
if(theHost) {
server_name.sin_addr.s_addr = *(ulong *)theHost->h_addr_list[0];
}
else {// Bad address
#else
if(inet_aton(cp,&server_name.sin_addr)==0) { // Bad address
#endif
#endif
sprintf( err_str, "Bad address %s", cp );
return err_str;
}
server_name.sin_port=htons(port);
server_name.sin_family=AF_INET;
// now activate network
if( !network_initialize() ) {
return "Cannot init network!";
}
my_client_socket = socket(PF_INET,SOCK_STREAM,0);
if(my_client_socket==INVALID_SOCKET) {
return "Cannot create socket";
}
if(connect(my_client_socket,(struct sockaddr *)&server_name,sizeof(server_name))==-1) {
sprintf( err_str, "Cannot connect to %s", cp );
return err_str;
}
pending[0] = 0;
active_clients = 0;
return NULL;
}
// connect to address (cp), receive game, save to (filename)
const char *network_connect(const char *cp, const char *filename)
{
// open from network
const char *err = network_open_address( cp );
if( err==NULL ) {
int len;
dbg->warning( "network_connect", "send :" NET_TO_SERVER NET_GAME NET_END_CMD );
len = send( my_client_socket, NET_TO_SERVER NET_GAME NET_END_CMD, 9, 0 );
len = 64;
char buf[64];
network_add_client( my_client_socket );
if( network_check_activity( 60000, buf, len )!=INVALID_SOCKET ) {
// wait for sync message to finish
if( memcmp( NET_FROM_SERVER NET_GAME, buf, 7 )!=0 ) {
err = "Protocoll error (expecting " NET_GAME ")";
}
else {
int len = 0;
client_id = 0;
sscanf(buf+7, " %lu,%li" NET_END_CMD, &client_id, &len);
dbg->warning( "network_connect", "received: id=%li len=%li", client_id, len);
err = network_recieve_file( my_client_socket, filename, len );
}
}
else {
err = "Server did not respond!";
}
}
if(err) {
network_close_socket( my_client_socket );
}
return err;
}
// if sucessful, starts a server on this port
bool network_init_server( int port )
{
struct sockaddr_in name;
network_initialize();
my_socket = socket(PF_INET, SOCK_STREAM, 0);
if( my_socket==INVALID_SOCKET ) {
dbg->fatal("init_server()", "Fail to open
........................ and more .........................
Viktorht,
I think that they're already well into developing network code for Simutrans based on the OpenTTD code...
The basic functionality is almost finished, lacking is stuff like avoid desyncs, finetuning of timing (a client may run 1ms per minute hahead, which my be fatal in a 4h session ... ), player management/password. All of them worked partly on at the moment.
Quote from: prissi on December 31, 2009, 09:32:35 PM
finetuning of timing (a client may run 1ms per minute hahead, which my be fatal in a 4h session ... ), player management/password.
just a stupid and sudden idea: every, say, 15 min the clients should look at an internet time service (e.g. time.nist.gov or others) and synchronise... :::)
Does not help much, and means I need to implement the timing protocoll in simutrans, since there is absolutely now way to have this protable. No I rather use a much more simple approach, like checking the time when the last command arrived to the time it should be executed and then get estimates if the next frames should be 1ms longer or shorter.