News:

Do you need help?
Simutrans Wiki Manual can help you to play and extend Simutrans. In 9 languages.

Wanted: Network mode

Started by prissi, November 19, 2008, 10:46:17 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Spike

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.

RodrigoSoracco

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...

prissi

There is already a field for passwords in the current player structure. They are not enforced yet.

vilvoh

One curious thing. I was digging along the archive when I found these interesting posts from Simutrans is multiplayer 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...

Escala Real...a blog about Simutrans in Spanish...

RodrigoSoracco

Well, that's what I tryng to say on Portuguese Forum.  Just graphical front ends to clients and the server doing all the hard work, sending and receiving requests...

prissi

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 ...

RodrigoSoracco

I will take a look. Liked the public server index there.

z9999+

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;'

prissi

GCC have issues with printf("%lli"), and thus it is not working at the moment.

Dwachs

Parsley, sage, rosemary, and maggikraut.

prissi

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 ...

z9999+

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.

Dwachs

#47
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 :)
Parsley, sage, rosemary, and maggikraut.

z9999+

I couldn't do any construction but at least I could receive savegame from server. :)

RodrigoSoracco

Sorry about a stupid question. But... How I apply the patch on Linux client? I need to compile everything?

Dwachs

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.
Parsley, sage, rosemary, and maggikraut.

z9999+

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

Dwachs

The data looks ok to me, but most probably the client_id stuff is not working :(
Parsley, sage, rosemary, and maggikraut.

Dwachs

#53
Here is another try on the client-ids. Could you please test whether it works? It works for me on Windows and Linux.
Parsley, sage, rosemary, and maggikraut.

prissi

It works for me too. Not tried on BeOS though, only on 127.0.0.1 so far.

z9999+

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.

Dwachs

#56
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.
Parsley, sage, rosemary, and maggikraut.

prissi

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.

jamespetts

Presumably, this can be set easily by the person running the server to allow for variation?
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

prissi

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.

viktorht

Can i help, Im starting on c++.

Dwachs

Try to get the source code and compile it as a first step. Look here:

http://forum.simutrans.com/index.php?topic=3228.0
Parsley, sage, rosemary, and maggikraut.

viktorht

#62
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 .........................


jamespetts

Viktorht,

I think that they're already well into developing network code for Simutrans based on the OpenTTD code...
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

prissi

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.

Fabio

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... :::)

prissi

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.