This method doesn't require port-forwarding to be used, and works for
most common NAT routers in home setups. But, for sure it doesn't work
for all setups, and not everyone will be able to use this.
spanish (mexican): 4 changes by absay
english (us): 13 changes by 2TallTyler
korean: 5 changes by telk5093
german: 13 changes by Wuzzy2
portuguese: 4 changes by azulcosta
hindi: 6 changes by ritwikraghav14
Now you can use things like `set server_game_type public` instead of having to
guess the number, which would not be written into the configuration file nor
would it be shown when doing `set server_game_type`.
Every outgoing connection, either TCP or UDP, triggered
NetworkInitialize(), which triggered NetworkUDPInitialize() which
first closes all connections.
Now the problem was that "Search LAN games" found a server, added
it to the list, after which (over TCP) it queries the server. This
closes all UDP sockets (as that makes sense, I guess?), while the
UDP was still reading from it.
Solve this by simply stop initializing UDP every time we make an
outgoing TCP connection; instead only do it on start-up.
In this mode you do register to the Game Coordinator, but your
server will not show up in the public server listing. You can give
your friends the invite code of the server with which they can
join.
This removes the need to know a server IP to join it. Invite codes
are small (~7 characters) indentifiers for servers, which can be
exchanged with other players to join the servers.
Normally TCPConnecter will do a DNS resolving of the connection_string
and connect to it. But for SERVER_ADDRESS_INVITE_CODE this is different:
the Game Coordinator does the "resolving".
This means we need to allow TCPConnecter to not setup a connection
and allow it to be told when a connection has been setup by an external
(to TCPConnecter) part of the code. We do this by telling the (active)
socket for the connection.
This means the rest of the code doesn't need to know the TCPConnecter
is not doing a simple resolve+connect. The rest of the code only
cares the connection is established; not how it was established.
This statement was removed by accident, as it felt it could be removed.
But it is used to know if the NewGRF is from the baseset folder or
from the NewGRF folder.
OTTD_COORDINATOR_CS for the game coordinator defaults to coordinator.openttd.org:3976
OTTD_CONTENT_SERVER_CS for the content server defaults to content.openttd.org:3978
OTTD_CONTENT_MIRROR_CS for the content mirror server defaults to binaries.openttd.org:80
The C++ std::getenv is guaranteed thread-safe by the C++11 specification,
whereas the POSIX/C getenv might not be thread-safe by the C11 specification.
The outer if statement checks for 'aa' being false, so within the inner
statements anything checking aa will have a known result and the other
branch from there will be dead code.
This reduced the load on compilers, as currently for example MacOS
doesn't like the huge settings-tables.
Additionally, nobody can find settings, as the list is massive and
unordered. By splitting it, it becomes a little bit more sensible.
LoadCheck makes it sound like something is really broken while
loading savegames, while it really is perfectly normal, as most
chunks do not implement LoadCheck.
num_liveries indirectly contained the same information, but this
makes reading these things pretty difficult. So use IsSavegameVersionBefore()
like everywhere else instead.
IsSavegameVersionUntil() did a [0, N] check, not [0, N) as the
name suggests.
Until can be a confusing word, where people consider it to be
including the upperbound. Dictionary states it means "before",
excluding the upperbound. There are long debates about who is right.
So, simply remove away from this ambiguity, and call it "before"
and "before or at". This makes the world easier for everyone.
We no longer need them. If you want to remove a field .. just
remove it! Because of the headers in the savegame, on loading,
it will do the right thing and skip the field.
Do remember to bump the savegame version, as otherwise older
clients can still load the game, but will reset the field you
have removed .. that might be unintentially.
We won't be able to make it fully self-descriptive (looking at you
MAP-chunks), but anything else can. With this framework, we can
add headers for each chunk explaining how each chunk looks like
in detail.
They also will all be tables, making it a lot easier to read in
external tooling, and opening the way to consider a database
(like SQLite) to use as savegame format.
Lastly, with the headers in the savegame, you can freely add
fields without needing a savegame version bump; older versions
of OpenTTD will simply ignore the new field. This also means
we can remove all the SLE_CONDNULL, as they are irrelevant.
The next few commits will start using this framework.
We often ask people for their openttd.cfg, which now includes their
passwords, usernames, etc. It is easy for people to overlook this,
unwillingly sharing information they shouldn't.
By splitting this information over either private.cfg or secrets.cfg,
we make it more obvious they shouldn't be sharing those files, and
hint to what is inside them.
Instead of creating the object on heap and use a pointer, create
the object on stack and use a guaranteed-not-null pointer.
The size of IniFile doesn't warrent the forcing to heap.
Additionally, use a subclass instead of a function to do some
initial bookkeeping on an IniFile meant to read a configuration.
Unless invoked with -w, --warning ("print a warning for any untranslated strings") or -t, --todo ("replace any untranslated strings with '<TODO>'").
Eints normally fixes the warnings after a Pull Request, so it is not really useful information for the developer to see as a warning.
With std::variant all memory can be figured out at compile time, so the compiler needs to keep track of fewer elements. It also saves out a unique_ptr and its memory management, over a slight impact for resolving a setting.
One UpdateServiceInterval has two parameters to update the service interval for a vehicle type, the other for all vehicle types at once. Rename the latter to help with function resolution for the introduction of variants.
Rename the zero-parameter NetworkValidateClientName to NetworkValidateOurClientName to make it clearer it is performed on our client name, and to make it a non-overloaded function to aid with the variant being added a few commits later
ThreadSanitizer rightfully notices that the game-thread could
update the palette while the draw-thread is copying it for local
use. The odds of this are very small, but nevertheless, it does
carry a very good point.
It wouldn't hurt the application in any way, but it might cause
visual glitches on the screen.
The enum values still have the exact same numerical values, but the 10.12
SDK introduced more explicit names (e.g. like NSEventTypeApplicationDefined
instead of NSApplicationDefined) for several enum constants.
Use them when available.
When the game-loop is very slow, it was easily possible to start
the loop with _shift_pressed being false, but end with
_shift_pressed being true. This doesn't hurt the game as such,
but for the user this can be very weird: I pressed "Buy Vehicle",
pressed shift a bit later, and I still get a cost indication.
Creating a thread was not thread-safe. The irony.
The video-driver has a function GameLoopPause() which first checks
if the thread is the game-thread or not. For this it needs access
to this->game_thread. This variable is set in StartNewThread().
However, due to timing, it is well possible GameLoopPause() is
called from the thread well before this->game_thread is assigned.
And so we have a race-condition!
Simply solve this by preventing a thread to start till we are
done with our bookkeeping.
This makes it easier to spot chunks that have a save_proc that
is a nullptr, but also prevents confusion, where it looks like
the CH_ type of a chunk has influence on how it is being read.
It is not, it is only used for saving.
Basically it is very similar to Vehicles, where there first is
a type field, followed by data of that type. So this commit makes
it looks like how Vehicles solved that.
This removes a lot of custom "keeping track of length" stuff.
This adds two byte extra to those chunks, and might feel a bit
silly at first. But in later changes we will prefix CH_ARRAY with
a table header, and then this change shines.
Without this, we could still add headers to these chunks, but any
external reader wouldn't know if the CH_RIFF has them or not. This
way is much more practical, as they are now more like any other
chunk.
This means that during loading we can validate that what is saved
is also that what is expected. Additionally, this makes all list
types similar to how they are stored on disk:
First a gamma to indicate length, followed by the data.
The size still depends on the type.
In the end, the code was already doing the right thing, but a few
functions deep, and not really obvious. When validating what objects
can handle SLE_VAR_NULL, it is nicer to just have this obvious.
Using SL_ARR for this gives us a bit of trouble later on, where we
add a length-field to SL_ARR. This of course is not the intention
of SLE_CONDNULL. So better seperate it.
The current SaveLoad is a bit inconsistent how long a length field
is. Sometimes it is a 32bit, sometimes a gamma. Make it consistent
across the board by making them all gammas.
This helps external tooling to understand if a SL_STRUCT should
be skipped when reading. Basically, this transforms an SL_STRUCT
into a SL_STRUCTLIST with either 0 or 1 length.
This wasn't consistently done, and often variables were used that
were read by an earlier blob. By moving it next to the struct
itself, the code becomes a bit more self-contained and easier to
read.
Additionally, this allows for external tooling to know how many
structs to expect, instead of having to know where to find the
length-field or a hard-coded value that can change at any moment.
There was a lot of code duplication for no real reason. Now with
SLEG_STRUCT support, we can just re-use the code, hopefully making
it easier for future-us to make changes to this, without breaking
everything for old games.
With the new SLEG_STRUCT it is much easier to embed a struct
in a struct, where the sub-struct has limitations on when it is
being used.
This makes both the code easier to read (less magic) and avoids
the SaveLoad needing to know all these things about Stations
and Vehicles.
The commits following this will use this new functionality.
Currently, a few places do this manually. This has as drawback that
the Save() and Load() code need to be in sync, and that any change
can result in (old) savegames no longer loading. In general, it is
annoying code to maintain.
By putting everything in a description table, and use that for
both Save() and Load(), it becomes easier to see what is going on,
and hopefully less likely for people to make mistakes.
Both did not support format parameters, so in many places IConsolePrint(CC_ERROR, "message") was used with a style different from what IConsoleError would do.
If a command cannot be executed for whatever reason, it makes no sense to call it a warning. Something has been done wrong.
Also make writing of these error message consistent while changing their "type".
This may change behaviour when multiple loading/loaded stages are provided, as the various copies checked in different orders, however only one result is expected in these cases anyway.
This is extreme useful for automated testing. Without this, OpenTTD
will always look in your personal-dir (like ~/.local/share/openttd
or %USER%\Documents\OpenTTD). For most users this is exactly what
we want, that there is a shared place for all their files.
However, for automated testing this is rather annoying, as your
local development files influence the automated test. As such,
'-X' counters this, and only gives the local folders. This is
especially useful in combination with '-x' and '-c'.
You can easily mistake SlList / SL_LST to be a list of SL_VAR, but
it is a list of SL_REF. With this rename, it hopefully saves a few
people from "wtf?" moments.
Prepare the full description and send it to SlObject. This does
require some code to be able to read to a SLE_VAR_NULL, like strings
etc, as there is no way to know their length beforehand.
It was rather confusing which one was for what, especially as some
SaveLoad flags were settings-only. Clean up this mess a bit by
having only Setting flags.
It is a lovely organicly grown enum, where it started off with
GUI-only flags, and after that a few flags got added that can be
considered GUI-only (the GUI disables/enables based on them), to
only have flags added that has nothing to do with the GUI.
So be less confusing, and rename them to what they do.
Additionally, I took this opportunity to rename 0ISDISABLED to
reflect what it really does.
Basically, this changes "SaveLoad *" to either:
1) "SaveLoadTable" if a list of SaveLoads was meant
2) "SaveLoad &" if a single entry was meant
As added bonus, this removes SL_END / SLE_END / SLEG_END. This
also adds core/span.hpp, a "std::span"-lite.
This is mostly done as there are now constraints on settings.ini you might not
expected. For example, conditional settings always have to come last, as otherwise
they would influence the index.
YAPF could end up in a situation where it sets the best intermediate node
to a node whose construction is never finalized (i.e. it is never added to
the open list). The content of the node would be overwritten in the next
round, potentially sending the vehicle to an unwanted location.
When you buy-out a company, you got your shares back. This is
based on company-value, which includes values for the vehicles etc.
In other words, you not only got the vehicles, but you also got
paid to get them back.
Additionally, you also got the loan of the company, but not the
money for the loan (as that is subtracted from the company-value).
Solve this by changing the rules of a buy-out: don't sell your
shares, get the loan AND the balance and get the infrastructure.
The comments for SettingDescType; it is a byte, so not 4 bytes and since it is not a flag there are about 250 other possibilities left instead of 9.
SettingGuiFlag is uint16 so has 2 bytes allocated.
SettingDescGlobVarList and related comments imply that global vars cannot be used elsewhere, but they are used for settings just fine. Even then the type is not used anywhere else but the definition of the table.
This to prevent the default copy-assignment getting used when during the assignment also some other memory needs to be allocated as that would otherwise be freed.
Division by resize_y is already yielding an unsigned number, so when clicking in the WD_FRAMERECT_TOP you would already get a huge value, so sel would never be negative. So, leave sel an unsigned number and remove the <= check.
Due to 47a99bb the order of elements in the garbage collection chain has
changed causing the class to be finalised before the instances of that class.
Since the instance's array of member values depends on the size of the values
in the class, the class finalisation resetting that size to 0 causes not all
finalisations to run, which subsequently causes a heap use after free. So,
just set the SQObjectPtrs to 'null' during the finalisation of the SQClass
so the SQInstance can release all instance variables during its finalisation.
Practically the length of the handlers not being equal to the number of
features is the problem as it means something was forgotten when adding
a new feature, so static assert to that and let the existing check on
the feature number take care of invalid data from the NewGRFs.
Functions like localtime, gmtime and asctime are not thread safe as they (might) reuse the same buffer. So use the safer _s/_r variant for localtime and gmtime, and use strftime in favour of asctime.
This ensures that default vehicles can transport any NewGRF defined cargos, albeit with weird graphics and vehicle names.
This also changes the refittability of default vehicles with default industries.
Default vehicles now behave as if they had a cargo translation table. This fixes default vehicles carrying seemingly random cargos, if NewGRF industry sets are present.
This behavior is disabled, when a NewGRF touches any of the cargo-type or refitting properties. In that case it's up to the NewGRF to define its own cargo translation table.
* Codechange: [Network] split CloseSocket and CloseConnection more clearly
- CloseSocket now closes the actual OS socket.
- CloseConnection frees up the resources to just before CloseSocket.
- dtors call CloseSocket / CloseConnection where needed.
Susz is masculine, not neuter, so it should result in "Susz Mazowiecki",
"Susz Morski", and not "Susz Mazowieckie" or "Susz Morskie". However,
because order of the names whould not be changed, it was replaced with
Leszno, which is neuter.
In the destructors of many of the network related classes Close() is called, just like the
top class in that hierarchy. However, due to virtual functions getting resolved statically
in the destructor it would always call the empty Close() of the top class.
Document the other cases where a virtual call is resolved statically.
This as during construction the sub class has not been initialized yet, and
during destruction the sub class has already been destroyed, so the overriding
virtual function would be accessing uninitialized data.
This also changes ScriptEventVehicleAutoReplaced when replacing wagons:
The event is now only spawned, if the head engine changes, so only if the VehicleID of the consist changes.
Previously replacing wagons spawned an event with OldVehicleID==NewVehicleID.
This means that random tree generation density is higher on small maps and lower on large maps. This difference is enough to make the Lumber Mill impractical to use on large maps.
This change skips ticks on maps smaller than 256x256 and increases iterations or shortens the interval on maps larger than 256x256.
It now follows very simple rules:
0 - Fatal, user should know about this
1 - Error, but we are recovering
2 - Warning, wrong but okay if you don't know
3 - Info, information you might care about
4 -
5 - Debug #1 - High level debug messages
6 - Debug #2 - Low level debug messages
7 - Trace information
The code mixed up "client has quit but we already told everyone"
with "client lost connection, handle this".
Split up those two signals:
- CLIENT_QUIT means we told everyone and the connection is now dead
- CONNECTION_LIST means we should tell everyone we lost a client
The function fluid_player_join in the library is broken beyond compare for the
usecases it was used for (see their #872). It does not wait until it is safe
to delete the player, so it is up to the end user to ensure that.
For OpenTTD we acquire a lock before fluid_synth_write_s16 and we acquire the
same lock in the stop function. So, only one of the functions can be doing its
thing, meaning we do not need to wait for the player to be stopped as it
cannot be doing anything as we prevent that by the lock.
Since pixel dimensions in SetPadding() are scaled by GUI size, padding for inset viewports was excessive.
Instead, automatically apply padding for WWT_INSET at widget level. This applies to all widgets inside a WWT_INSET, which in all instances is a NWID_VIEWPORT.
This meant that on opening the Multiplayer window, if you had more
than one server configured, it would one by one cancel all pending
queries and send a new. Result: only the last server was updated.
The most common case never needs access to it anymore. Make the
one exception to this explicit. This means the fact that we
store it is now an implementation detail.
If the highscore/news window panel size, which is now scaled by GUI zoom, is larger than the screen size, a loop will be entered where the window is repeatedly resized.
This is resolved by removing the minimal size from the panel, as the window is always resized to cover the screen anyway. This means the screen size can never be too small.
Hostnames like "content.openttd.org" resolve into multiple IPv4 and IPv6.
It is possible that either of the IPs is not working, either due to
a poorly configured OS (having IPv6 but no valid route), broken network
paths, or a service that is temporary unavailable.
Instead of trying the IPs one by one, waiting for a 3s timeout between
each, be a bit more like browsers, and stack attempts on top of each
other with slight delays. This is called Happy Eyebells.
Initially, try the first IPv6 address. If within 250ms there is no
connection yet, try the first IPv4 address. 250ms later, try the
second IPv6 address, etc, till all addresses are tried.
If any connection is created, abort all the other (pending) connections
and use the one that is created. If all fail 3s after the last connect(),
trigger a timeout for all.
We now resolve the connection_string to a NetworkAddress in a much
later state. This means there are fewer places constructing a NetworkAddress.
The main benefit of this is in later PRs that introduce different types
of NetworkAddresses. Storing this in things like NetworkGameList is
rather complex, especially as NetworkAddress has to be mutable at all
times.
Additionally, the NetworkAddress is a complex object to store simple
information: how to connect to this server.
Split the updating in a "static" version that only needs to be called when a new map is loaded or some settings are changed, and a "dynamic" version that updates everything that changes regularly such as the current game date or the number of spectators.
english (us): 1 change by 2TallTyler
estonian: 49 changes by siimsoni
korean: 1 change by telk5093
hungarian: 45 changes by baliball
finnish: 12 changes by hpiirai
spanish: 1 change by JohnBoyFan
In FluidSynth 2.2.0 an extra state was added to denote stopping. To transition
from this state to a stopped state the rendering needs to be running. Since
04ce1f07 locking was added that skipped the rendering when something else held
a lock, so the state would never get to stopped and join would never return.