<?xml version="1.0" encoding="utf-8" ?>
<dedicated>
<authorization_levels>
<level>
<name>SuperAdmin</name> <!-- use for xmlrpc to login -->
<password>SuperAdmin</password> <!-- xmlrpc password -->
</level>
<level>
<name>Admin</name>
<password>Admin</password>
</level>
<level>
<name>User</name>
<password>User</password>
</level>
</authorization_levels>
<masterserver_account>
<login>my_server_login</login> <!-- your server login from https://players.trackmania.com -->
<password><![CDATA[put_your_password_here]]></password>
</masterserver_account>
<server_options>
<name></name> <!-- server name, used for local network browser, othervice club room name is used -->
<comment></comment>
<hide_server>0</hide_server> <!-- value is 0 (always shown), 1 (always hidden), 2 (hidden from nations) -->
<max_players>32</max_players> <!-- max players amount -->
<password></password> <!-- empty for public, othervice password required to join server -->
<max_spectators>32</max_spectators> <!-- max spectator amount -->
<password_spectator></password_spectator> <!-- empty for public, othervice password required to join server as spectator -->
<keep_player_slots>False</keep_player_slots> <!-- when a player changes to spectator, hould the server keep if player slots/scores etc.. or not. -->
<ladder_mode>forced</ladder_mode> <!-- accepts values: 'inactive', 'forced' (or '0', '1') -->
<enable_p2p_upload>False</enable_p2p_upload>
<enable_p2p_download>False</enable_p2p_download>
<callvote_timeout>60000</callvote_timeout> <!-- how long voting lasts, in milliseconds = 60 seconds atm)
<callvote_ratio>0.5</callvote_ratio> <!-- default ratio. value in [0..1], or -1 to forbid. -->
<callvote_ratios>
<voteratio command="Ban" ratio="-1"/>
<!-- commands can be "Ban", "Kick", "RestartMap", "NextMap", "SetModeScriptSettingsAndCommands"... -->
</callvote_ratios>
<allow_map_download>True</allow_map_download>
<autosave_replays>False</autosave_replays>
<autosave_validation_replays>False</autosave_validation_replays>
<referee_password></referee_password>
<referee_validation_mode>0</referee_validation_mode> <!-- value is 0 (only validate top3 players), 1 (validate all players) -->
<use_changing_validation_seed>False</use_changing_validation_seed>
<disable_horns>False</disable_horns>
<clientinputs_maxlatency>200</clientinputs_maxlatency> <!-- players with c2s-latency greater than this value will experience difficulties playing, but a lower value reduce overall clients CPU usage (max 540ms) -->
</server_options>
<system_config>
<connection_uploadrate>102400</connection_uploadrate> <!-- Kbits per second -->
<connection_downloadrate>102400</connection_downloadrate> <!-- Kbits per second -->
<workerthreadcount>2</workerthreadcount>
<packetassembly_multithread>True</packetassembly_multithread>
<packetassembly_packetsperframe>60</packetassembly_packetsperframe> <!-- Number of reduced SIMU-packets sent each frame (=10ms) -->
<packetassembly_fullpacketsperframe>30</packetassembly_fullpacketsperframe> <!-- Number of full SIMU-packets sent each frame (=10ms) -->
<delayedvisuals_s2c_sendingrate>32</delayedvisuals_s2c_sendingrate> <!-- proportion of frames when the server sends DELAYEDVISUAL-packets to everyone. 255 means every frame, 128 means every other frame, 64 means every fourth frame... -->
<trustclientsimu_c2s_sendingrate>64</trustclientsimu_c2s_sendingrate> <!-- proportion of frames when the clients send TRUSTCLIENTSIMU-packets to the server. 255 means every frame, 128 means every other frame, 64 means every fourth frame... -->
<allow_spectator_relays>False</allow_spectator_relays>
<p2p_cache_size>600</p2p_cache_size>
<force_ip_address></force_ip_address>
<server_port>2350</server_port>
<client_port>0</client_port>
<bind_ip_address></bind_ip_address>
<use_nat_upnp></use_nat_upnp>
<gsp_name></gsp_name> <!-- Game Server Provider name and info url -->
<gsp_url></gsp_url> <!-- If you're a server hoster, you can use this to advertise your services -->
<xmlrpc_port>5000</xmlrpc_port>
<xmlrpc_allowremote>False</xmlrpc_allowremote> <!-- If you specify an ip adress here, it'll be the only accepted adress. this will improve security. -->
<blacklist_url></blacklist_url>
<guestlist_filename></guestlist_filename>
<blacklist_filename></blacklist_filename>
<minimum_client_build></minimum_client_build> <!-- Only accept updated client to a specific version. ex: 2011-10-06 -->
<disable_coherence_checks>False</disable_coherence_checks> <!-- disable internal checks to detect issues/cheats, and reject race times -->
<disable_replay_recording>False</disable_replay_recording> <!-- disable replay recording in memory during the game to lower memory usage. -->
<save_all_individual_runs>False</save_all_individual_runs> <!-- Save all the ghosts from the match replay to individual ghost.gbx files, in folder {servername}/Autosaves/Runs_{mapname}/ -->
<use_proxy>False</use_proxy>
<proxy_url></proxy_url>
</system_config>
</dedicated>
<clientinputs_maxlatency>120</clientinputs_maxlatency>
<connection_uploadrate>250000</connection_uploadrate>
<connection_downloadrate>250000</connection_downloadrate>
<workerthreadcount>3</workerthreadcount>
<packetassembly_multithread>True</packetassembly_multithread>
<packetassembly_packetsperframe>0</packetassembly_packetsperframe>
<packetassembly_fullpacketsperframe>10</packetassembly_fullpacketsperframe>
<delayedvisuals_delay>300</delayedvisuals_delay>
<trustclietnsimu_c2s_sendingrate>64</trustclietnsimu_c2s_sendingrate>
<delayedvisuals_s2c_sendingrate>64</delayedvisuals_s2c_sendingrate>
<disable_replay_recording>True</disable_replay_recording>
In order to understand the network-related parameters, one must first understand that the netcode can operate in different ways:
Delegating physics calulations to clients
In gameplay, physics calculation happens every 10ms (so 100 times a second).
In order to lighten the load on the server, a game mode can choose to trust the clients, and opt for a client-side physics calculation.
This can be modified per game client, as there can be game modes where this could get useful (for example in a streamer vs viewer situation).
True
, a player could theoretically cheat (giving themselves more speed etc.) cause the server does not validate the physics, and you would only see it when validating the replay.False
, the server calculates the players' physics, and the client can't modify them for the race.Be careful : This only affects the physics of the car (because that is the most costly thing to calculate). Other things like the game mode will always be simulated server-side.
Please note:
It's better or even mandatory to disable this setting in case that interactions between players are needed, because it's always the server who has the most recent information about all the players.
For example, if Bob and Alice are on a server, Bob's computer only has delayed information about Alice's position and speed (because it needed to travel to the server and THEN to Bob).
If Bob would now need to calculate their physics based off that information, the result could go anywhere.
And it's the same the other way round for Alice!
For example, let's take a collision between 2 cars: In the best case, it will just give unnatural bounces, in the worst case we can imagine cars sticking together like GTA Online's "Demon Drag" (Alice thinks Bob is left of them, Bob thinks Alice is left of them, both cars push right), and other examples...
But as long as each player only drives their own race and doesn't need interaction with others, and you don't need that form of anticheat in real time (you can always detect it by validating the replay), trusting the clients reduces a lot the CPU used by the server.
Continuing opponents' simulation trajectory based on their last state and making them more accurate by adding a delay
When we display other players on Alice's PC, we (phsyically) can't have all their precise positions in the same moment.
For example when Bob lives on the moon (= a lot of ping), Alice can physically never instantly know about this because this information needs the ping time to travel from Bob to the server to Alice's client.
There are 3 approaches to handling this situation:
UseCrudeExtrapolation
to False
.But when it is too expensive to do this, you should set UseCrudeExtrapolation
to True
(In the code, this option is also referenced to as delayedvisuals
). In this case:
TrustClientSimu
), and we display it, but "delayed".CrudeExtrapolation_AllowDelay
to True
.CrudeExtrapolation_AllowDelay
to False
.Like trusting the client, this is an option separate for every player, for similar reasons:
For a "follow the VIP" mode, everyone wants to see an extrapolated VIP position (so followers can see without delay if they are really close or not).
But since no one needs to see the followers in real time, we can use the delay on them to display this nicer.
To give an example from Nadeo's gamemodes, TrustClientSimu
and UseCrudeExtrapolation
are enabled everywhere, and CrudeExtrapolation_AllowDelay
is enabled for TimeAttack-based modes (where not everyone needs to race with a synchronized start) but not for Rounds-based modes because in a synchronized race like that, the delay would most likely be less wanted.
The server calculates the physics of frame T when it has received inputs from all the players it has to simulate, and the physics of all the players that are "trusted" with TrustClientSimu
respectively.
But if this takes too long (because of lag etc), it never waits longer than the clientinputs_maxlatency
setting. Too bad for the players who didn't send their inputs/physics in time..
If we didn't receive a player's inputs in time and we have to calculate their physics for them, we assume that their input just didnt change. If we trust that player, we just don't change their position.
In practice, this pretty much means that if a player has a higher ping than this value, they won't be able to play. If they just have a ping peak at some point, it will recover but potentially their run is screwed up.
Now what is a “rate” for a setting's function?
To limit the bandwidth and CPU usage, the following happens in the code:
rate+1
to this numberSo, if the rate is 0, the function is called every 256 frames (= 2.5s = never), and if the rate is 255 the function is executed every frame.
Adressing problems with ping
Whether it's network related ping, or "virtual ping" related to sporadic packet sending (or a combination of therein), we try to mitigate issues by doing the following:
For example: Bob and Alice receive a packet from the server every 10ms. But Bob receives packets with 50ms delay and Alice with 100ms. So Alice's PC has to effectively make 2x the calculation efforts to "catch up" all this delay, integrating the queue of past frames received from the server being 2 times as long.
c2s = “client to server”
When the server delegates the physics to a client, the client sends the result of their simulation "from time to time" (a few tens of ms) with their inputs - that rate is managed by this setting.
If the clients have a good upload and CPU, this rate can be increased. Keep in mind though that the CPU is used quite a bit when writing packets, because they have to be well compressed.
However, there quickly is a point of diminishing returns: between 10ms and 20ms of difference (rate = 255 or rate = 128), the bandwidth linked to the trustclientsimu is multiplied by 2, but the gain in quality only corresponds to 10ms of "virtual ping".
But not only think about the client's CPU, also think about the servers' bandwidth to receive and read all this input.
s2c = “server to client” (delayedvisuals = UseCrudeExtrapolation)
If CrudeExtrapolation
is enabled, the server also sends the positions of everyone "from time to time" (a few tens of ms) - that rate is managed by this setting now.
Again, if there are few things hindering you, you can increase this rate, but like the other sending rate, beware of diminishing returns.
The gain of this is only for the visual display of the opponents, so if you have to lower a rate for performance or other reasons, you proabably want to start with this one.
The dedicated server must, in addition to the CrudeExtrapolation, also send a lot of other information to the client (the game mode options, the CP times of the opponents, etc).
So for each frame, the server will prepare a number of packets to send. This operation is quite costly, because it is necessary to look at everything that has changed since the last packet, which information concerns which player, etc...
For example, if the server prepares and sends 10 packets for each frame, and there are 50 players connected, we will send packets for players 1 to 10 during the first frame, then 11 to 20, etc... cause only 10 packets are allowed each frame.
If this setting gets too low, it also adds “virtual ping” (artificial delay) since clients only can be sent a packet after some time.
Since assembling the “fullpacket” from the previous setting is quite expensive for the server, there is also the possibility to send a smaller heartbeat more often.
This packet contains only essential network information and inputs from other players, which we use when we are in the mode of UseCrudeExtrapolation = False
.
On the one hand, it doesn't cost much to send it often. But at the same time, you don't gain much either.
This is the kind of value where it's better to test a bit per-situation to see how it affects your playing performance.
Nadeo uses the default value of this for their servers.
As the package preparation is very expensive, this process can be multithreaded.
Assuming that package preparation takes about 3/4 of the server's time (the rest is mainly the game mode script), there is not much of a point in having more than 4 or 5 threads per server.
If you have a very performant gamemode, you might want to reconsider this value though.
As data for these can get quite large, these things are handled in a separate way without being able to be configured in the server settings.
Thanks to Nadeo for sharing this information - this is derived from a translation of a french post.