Merge branch 'jgrpp' into jgrpp-nrt
# Conflicts: # .ottdrev-vc # README.md # jgrpp-changelog.md # src/ship_cmd.cpp
This commit is contained in:
@@ -246,6 +246,8 @@ See [jgrpp-changelog.md](jgrpp-changelog.md) for changelog.
|
|||||||
* Add news/advice setting to warn if no depot order in vehicle schedule. (added in v0.31.1).
|
* Add news/advice setting to warn if no depot order in vehicle schedule. (added in v0.31.1).
|
||||||
* Enable vehicle list buttons in station window when the list would be non-empty. (added in v0.31.1).
|
* Enable vehicle list buttons in station window when the list would be non-empty. (added in v0.31.1).
|
||||||
* Enable vehicle group management actions on other companies' stations. (added in v0.31.1).
|
* Enable vehicle group management actions on other companies' stations. (added in v0.31.1).
|
||||||
|
* Add a password mechanism to change network game settings from a network client. (added in v0.31.4).
|
||||||
|
* Change network protocol to send server/join and rcon passwords in hashed form instead of in clear text. (added in v0.31.4).
|
||||||
* Various minor fixes, see changelog.
|
* Various minor fixes, see changelog.
|
||||||
* [NewGRF specification additions](docs/newgrf-additions.html) ([online copy](https://htmlpreview.github.io/?https://github.com/JGRennison/OpenTTD-patches/blob/jgrpp/docs/newgrf-additions.html)).
|
* [NewGRF specification additions](docs/newgrf-additions.html) ([online copy](https://htmlpreview.github.io/?https://github.com/JGRennison/OpenTTD-patches/blob/jgrpp/docs/newgrf-additions.html)).
|
||||||
* [Low-level code/performance changes](docs/jgrpp-low-level-changes.md).
|
* [Low-level code/performance changes](docs/jgrpp-low-level-changes.md).
|
||||||
|
@@ -6,6 +6,15 @@
|
|||||||
* Include NotRoadTypes (NRT).
|
* Include NotRoadTypes (NRT).
|
||||||
* Bump trunk base from commit 21edf67f89c60351d5a0d84625455aa296b6b950 to commit a52bbb72a8a2cbcbefb0ff91b559f33c34094239.
|
* Bump trunk base from commit 21edf67f89c60351d5a0d84625455aa296b6b950 to commit a52bbb72a8a2cbcbefb0ff91b559f33c34094239.
|
||||||
|
|
||||||
|
### v0.31.4 (2019-08-24)
|
||||||
|
* Fix crash when removing signals from tunnel/bridge with trainless reservation.
|
||||||
|
* Fix various cases where reversing a train inside a signalled tunnel/bridge handled PBS reservations incorrectly.
|
||||||
|
* Fix error windows being closed when returning to the main menu.
|
||||||
|
* Add a password mechanism to change network game settings from a network client.
|
||||||
|
* Change station tile coverage highlight colour to light blue.
|
||||||
|
* Change network protocol to send server/join and rcon passwords in hashed form instead of in clear text.
|
||||||
|
* Fix various possible sources of non-determinism which could potentially cause multiplayer desyncs.
|
||||||
|
|
||||||
### v0.31.3 (2019-07-13)
|
### v0.31.3 (2019-07-13)
|
||||||
* Fix the target order number of conditional order jumps being loaded incorrectly from SpringPP savegames.
|
* Fix the target order number of conditional order jumps being loaded incorrectly from SpringPP savegames.
|
||||||
* Fix order backups not being restored when using buy and refit.
|
* Fix order backups not being restored when using buy and refit.
|
||||||
|
@@ -460,6 +460,7 @@ core/alloc_type.hpp
|
|||||||
core/backup_type.hpp
|
core/backup_type.hpp
|
||||||
core/bitmath_func.cpp
|
core/bitmath_func.cpp
|
||||||
core/bitmath_func.hpp
|
core/bitmath_func.hpp
|
||||||
|
core/checksum_func.hpp
|
||||||
core/container_func.hpp
|
core/container_func.hpp
|
||||||
core/dyn_arena_alloc.hpp
|
core/dyn_arena_alloc.hpp
|
||||||
core/endian_func.hpp
|
core/endian_func.hpp
|
||||||
|
@@ -40,6 +40,7 @@
|
|||||||
#include "disaster_vehicle.h"
|
#include "disaster_vehicle.h"
|
||||||
#include "newgrf_airporttiles.h"
|
#include "newgrf_airporttiles.h"
|
||||||
#include "framerate_type.h"
|
#include "framerate_type.h"
|
||||||
|
#include "core/checksum_func.hpp"
|
||||||
|
|
||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
|
|
||||||
@@ -2127,6 +2128,7 @@ static bool AircraftEventHandler(Aircraft *v, int loop)
|
|||||||
|
|
||||||
bool Aircraft::Tick()
|
bool Aircraft::Tick()
|
||||||
{
|
{
|
||||||
|
UpdateStateChecksum((((uint64) this->x_pos) << 32) | this->y_pos);
|
||||||
if (!this->IsNormalAircraft()) return true;
|
if (!this->IsNormalAircraft()) return true;
|
||||||
|
|
||||||
this->tick_counter++;
|
this->tick_counter++;
|
||||||
|
@@ -1082,9 +1082,6 @@ struct BuildVehicleWindow : Window {
|
|||||||
this->GetWidget<NWidgetStacked>(WID_BV_BUILD_SEL)->SetDisplayedPlane(SZSP_NONE);
|
this->GetWidget<NWidgetStacked>(WID_BV_BUILD_SEL)->SetDisplayedPlane(SZSP_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* disable renaming engines in network games if you are not the server */
|
|
||||||
this->SetWidgetDisabledState(WID_BV_RENAME, _networking && !_network_server);
|
|
||||||
|
|
||||||
NWidgetCore *widget = this->GetWidget<NWidgetCore>(WID_BV_LIST);
|
NWidgetCore *widget = this->GetWidget<NWidgetCore>(WID_BV_LIST);
|
||||||
widget->tool_tip = STR_BUY_VEHICLE_TRAIN_LIST_TOOLTIP + type;
|
widget->tool_tip = STR_BUY_VEHICLE_TRAIN_LIST_TOOLTIP + type;
|
||||||
|
|
||||||
@@ -1589,6 +1586,9 @@ struct BuildVehicleWindow : Window {
|
|||||||
|
|
||||||
this->SetWidgetsDisabledState(this->sel_engine == INVALID_ENGINE, WID_BV_SHOW_HIDE, WID_BV_BUILD, WID_BV_RENAME, WIDGET_LIST_END);
|
this->SetWidgetsDisabledState(this->sel_engine == INVALID_ENGINE, WID_BV_SHOW_HIDE, WID_BV_BUILD, WID_BV_RENAME, WIDGET_LIST_END);
|
||||||
|
|
||||||
|
/* disable renaming engines in network games if you are not the server */
|
||||||
|
this->SetWidgetDisabledState(WID_BV_RENAME, _networking && !(_network_server || _network_settings_access));
|
||||||
|
|
||||||
this->DrawWidgets();
|
this->DrawWidgets();
|
||||||
|
|
||||||
if (!this->IsShaded()) {
|
if (!this->IsShaded()) {
|
||||||
|
@@ -556,7 +556,7 @@ char *DumpCommandLog(char *buffer, const char *last)
|
|||||||
buffer += seprintf(buffer, last, "%c%c%c%c%c%c%c%c | ",
|
buffer += seprintf(buffer, last, "%c%c%c%c%c%c%c%c | ",
|
||||||
fc(CLEF_SCRIPT, 'a'), fc(CLEF_BINARY, 'b'), fc(CLEF_MY_CMD, 'm'), fc(CLEF_ONLY_SENDING, 's'),
|
fc(CLEF_SCRIPT, 'a'), fc(CLEF_BINARY, 'b'), fc(CLEF_MY_CMD, 'm'), fc(CLEF_ONLY_SENDING, 's'),
|
||||||
fc(CLEF_ESTIMATE_ONLY, 'e'), fc(CLEF_TEXT, 't'), fc(CLEF_GENERATING_WORLD, 'g'), fc(CLEF_CMD_FAILED, 'f'));
|
fc(CLEF_ESTIMATE_ONLY, 'e'), fc(CLEF_TEXT, 't'), fc(CLEF_GENERATING_WORLD, 'g'), fc(CLEF_CMD_FAILED, 'f'));
|
||||||
buffer += seprintf(buffer, last, " %7d x %7d, p1: 0x%08X, p2: 0x%08X, cc: %2u, lc: %2u, cmd: 0x%08X (%s)\n",
|
buffer += seprintf(buffer, last, " %7d x %7d, p1: 0x%08X, p2: 0x%08X, cc: %3u, lc: %3u, cmd: 0x%08X (%s)\n",
|
||||||
TileX(entry.tile), TileY(entry.tile), entry.p1, entry.p2, (uint) entry.current_company, (uint) entry.local_company, entry.cmd, GetCommandName(entry.cmd));
|
TileX(entry.tile), TileY(entry.tile), entry.p1, entry.p2, (uint) entry.current_company, (uint) entry.local_company, entry.cmd, GetCommandName(entry.cmd));
|
||||||
}
|
}
|
||||||
return buffer;
|
return buffer;
|
||||||
|
@@ -703,6 +703,21 @@ DEF_CONSOLE_CMD(ConRcon)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEF_CONSOLE_CMD(ConSettingsAccess)
|
||||||
|
{
|
||||||
|
if (argc == 0) {
|
||||||
|
IConsoleHelp("Enable changing game settings from this client. Usage: 'settings_access <password>'");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc < 2) return false;
|
||||||
|
|
||||||
|
if (!_network_server) {
|
||||||
|
NetworkClientSendSettingsPassword(argv[1]);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
DEF_CONSOLE_CMD(ConStatus)
|
DEF_CONSOLE_CMD(ConStatus)
|
||||||
{
|
{
|
||||||
if (argc == 0) {
|
if (argc == 0) {
|
||||||
@@ -2356,6 +2371,7 @@ void IConsoleStdLibRegister()
|
|||||||
IConsoleAliasRegister("info", "server_info");
|
IConsoleAliasRegister("info", "server_info");
|
||||||
IConsoleCmdRegister("reconnect", ConNetworkReconnect, ConHookClientOnly);
|
IConsoleCmdRegister("reconnect", ConNetworkReconnect, ConHookClientOnly);
|
||||||
IConsoleCmdRegister("rcon", ConRcon, ConHookNeedNetwork);
|
IConsoleCmdRegister("rcon", ConRcon, ConHookNeedNetwork);
|
||||||
|
IConsoleCmdRegister("settings_access", ConSettingsAccess, ConHookNeedNetwork);
|
||||||
|
|
||||||
IConsoleCmdRegister("join", ConJoinCompany, ConHookNeedNetwork);
|
IConsoleCmdRegister("join", ConJoinCompany, ConHookNeedNetwork);
|
||||||
IConsoleAliasRegister("spectate", "join 255");
|
IConsoleAliasRegister("spectate", "join 255");
|
||||||
@@ -2380,6 +2396,8 @@ void IConsoleStdLibRegister()
|
|||||||
IConsoleAliasRegister("server_password", "setting server_password %+");
|
IConsoleAliasRegister("server_password", "setting server_password %+");
|
||||||
IConsoleAliasRegister("rcon_pw", "setting rcon_password %+");
|
IConsoleAliasRegister("rcon_pw", "setting rcon_password %+");
|
||||||
IConsoleAliasRegister("rcon_password", "setting rcon_password %+");
|
IConsoleAliasRegister("rcon_password", "setting rcon_password %+");
|
||||||
|
IConsoleAliasRegister("settings_pw", "setting settings_password %+");
|
||||||
|
IConsoleAliasRegister("settings_password", "setting settings_password %+");
|
||||||
IConsoleAliasRegister("name", "setting client_name %+");
|
IConsoleAliasRegister("name", "setting client_name %+");
|
||||||
IConsoleAliasRegister("server_name", "setting server_name %+");
|
IConsoleAliasRegister("server_name", "setting server_name %+");
|
||||||
IConsoleAliasRegister("server_port", "setting server_port %+");
|
IConsoleAliasRegister("server_port", "setting server_port %+");
|
||||||
|
@@ -55,6 +55,13 @@ uint8 FindFirstBit(uint32 x)
|
|||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8 FindFirstBit64(uint64 x)
|
||||||
|
{
|
||||||
|
if (x == 0) return 0;
|
||||||
|
if ((x & 0x00000000ffffffffULL) != 0) return FindFirstBit(x);
|
||||||
|
return FindFirstBit(x >> 32) + 32;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -198,6 +198,13 @@ inline uint8 FindFirstBit(uint32 x)
|
|||||||
return __builtin_ctz(x);
|
return __builtin_ctz(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline uint8 FindFirstBit64(uint64 x)
|
||||||
|
{
|
||||||
|
if (x == 0) return 0;
|
||||||
|
|
||||||
|
return __builtin_ctzll(x);
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
/** Lookup table to check which bit is set in a 6 bit variable */
|
/** Lookup table to check which bit is set in a 6 bit variable */
|
||||||
@@ -216,6 +223,7 @@ extern const uint8 _ffb_64[64];
|
|||||||
#define FIND_FIRST_BIT(x) _ffb_64[(x)]
|
#define FIND_FIRST_BIT(x) _ffb_64[(x)]
|
||||||
|
|
||||||
uint8 FindFirstBit(uint32 x);
|
uint8 FindFirstBit(uint32 x);
|
||||||
|
uint8 FindFirstBit64(uint64 x);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -395,14 +403,14 @@ static inline T ROR(const T x, const uint8 n)
|
|||||||
* (since it will use hardware swapping if available).
|
* (since it will use hardware swapping if available).
|
||||||
* Even though they should return uint16 and uint32, we get
|
* Even though they should return uint16 and uint32, we get
|
||||||
* warnings if we don't cast those (why?) */
|
* warnings if we don't cast those (why?) */
|
||||||
#define BSWAP64(x) ((uint64)CFSwapInt64(x))
|
#define BSWAP64(x) ((uint64)CFSwapInt64((uint64)x))
|
||||||
#define BSWAP32(x) ((uint32)CFSwapInt32(x))
|
#define BSWAP32(x) ((uint32)CFSwapInt32((uint32)x))
|
||||||
#define BSWAP16(x) ((uint16)CFSwapInt16(x))
|
#define BSWAP16(x) ((uint16)CFSwapInt16((uint16)x))
|
||||||
#elif defined(_MSC_VER)
|
#elif defined(_MSC_VER)
|
||||||
/* MSVC has intrinsics for swapping, resulting in faster code */
|
/* MSVC has intrinsics for swapping, resulting in faster code */
|
||||||
#define BSWAP64(x) (_byteswap_uint64(x))
|
#define BSWAP64(x) ((uint64)_byteswap_uint64((uint64)x))
|
||||||
#define BSWAP32(x) (_byteswap_ulong(x))
|
#define BSWAP32(x) ((uint32)_byteswap_ulong((uint32)x))
|
||||||
#define BSWAP16(x) (_byteswap_ushort(x))
|
#define BSWAP16(x) ((uint16)_byteswap_ushort((uint16)x))
|
||||||
#else
|
#else
|
||||||
/**
|
/**
|
||||||
* Perform a 64 bits endianness bitswap on x.
|
* Perform a 64 bits endianness bitswap on x.
|
||||||
@@ -430,7 +438,7 @@ static inline T ROR(const T x, const uint8 n)
|
|||||||
{
|
{
|
||||||
#if !defined(__ICC) && (defined(__GNUC__) || defined(__clang__))
|
#if !defined(__ICC) && (defined(__GNUC__) || defined(__clang__))
|
||||||
/* GCC >= 4.3 provides a builtin, resulting in faster code */
|
/* GCC >= 4.3 provides a builtin, resulting in faster code */
|
||||||
return (uint32)__builtin_bswap32((int32)x);
|
return (uint32)__builtin_bswap32((uint32)x);
|
||||||
#else
|
#else
|
||||||
return ((x >> 24) & 0xFF) | ((x >> 8) & 0xFF00) | ((x << 8) & 0xFF0000) | ((x << 24) & 0xFF000000);
|
return ((x >> 24) & 0xFF) | ((x >> 8) & 0xFF00) | ((x << 8) & 0xFF0000) | ((x << 24) & 0xFF000000);
|
||||||
#endif /* __GNUC__ || __clang__ */
|
#endif /* __GNUC__ || __clang__ */
|
||||||
@@ -443,7 +451,12 @@ static inline T ROR(const T x, const uint8 n)
|
|||||||
*/
|
*/
|
||||||
static inline uint16 BSWAP16(uint16 x)
|
static inline uint16 BSWAP16(uint16 x)
|
||||||
{
|
{
|
||||||
|
#if !defined(__ICC) && (defined(__GNUC__) || defined(__clang__))
|
||||||
|
/* GCC >= 4.3 provides a builtin, resulting in faster code */
|
||||||
|
return (uint16)__builtin_bswap16((uint16)x);
|
||||||
|
#else
|
||||||
return (x >> 8) | (x << 8);
|
return (x >> 8) | (x << 8);
|
||||||
|
#endif /* __GNUC__ || __clang__ */
|
||||||
}
|
}
|
||||||
#endif /* __APPLE__ */
|
#endif /* __APPLE__ */
|
||||||
|
|
||||||
|
33
src/core/checksum_func.hpp
Normal file
33
src/core/checksum_func.hpp
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/* $Id$ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of OpenTTD.
|
||||||
|
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||||
|
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file checksum_func.hpp Checksum utility functions. */
|
||||||
|
|
||||||
|
#ifndef CHECKSUM_FUNC_HPP
|
||||||
|
#define CHECKSUM_FUNC_HPP
|
||||||
|
|
||||||
|
#include "bitmath_func.hpp"
|
||||||
|
|
||||||
|
struct SimpleChecksum64 {
|
||||||
|
uint64 state = 0;
|
||||||
|
|
||||||
|
void Update(uint64 input)
|
||||||
|
{
|
||||||
|
this->state = ROL(this->state, 1) ^ input ^ 0x123456789ABCDEF7ULL;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
extern SimpleChecksum64 _state_checksum;
|
||||||
|
|
||||||
|
inline void UpdateStateChecksum(uint64 input)
|
||||||
|
{
|
||||||
|
_state_checksum.Update(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CHECKSUM_FUNC_HPP */
|
@@ -12,6 +12,8 @@
|
|||||||
#ifndef RANDOM_FUNC_HPP
|
#ifndef RANDOM_FUNC_HPP
|
||||||
#define RANDOM_FUNC_HPP
|
#define RANDOM_FUNC_HPP
|
||||||
|
|
||||||
|
#include "bitmath_func.hpp"
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
/* Apple already has Random declared */
|
/* Apple already has Random declared */
|
||||||
#define Random OTTD_Random
|
#define Random OTTD_Random
|
||||||
|
@@ -179,6 +179,13 @@ char *CrashLog::LogOpenTTDVersion(char *buffer, const char *last) const
|
|||||||
*/
|
*/
|
||||||
char *CrashLog::LogConfiguration(char *buffer, const char *last) const
|
char *CrashLog::LogConfiguration(char *buffer, const char *last) const
|
||||||
{
|
{
|
||||||
|
auto pathfinder_name = [](uint8 pf) -> const char * {
|
||||||
|
switch (pf) {
|
||||||
|
case VPF_NPF: return "NPF";
|
||||||
|
case VPF_YAPF: return "YAPF";
|
||||||
|
default: return "-";
|
||||||
|
};
|
||||||
|
};
|
||||||
buffer += seprintf(buffer, last,
|
buffer += seprintf(buffer, last,
|
||||||
"Configuration:\n"
|
"Configuration:\n"
|
||||||
" Blitter: %s\n"
|
" Blitter: %s\n"
|
||||||
@@ -189,7 +196,8 @@ char *CrashLog::LogConfiguration(char *buffer, const char *last) const
|
|||||||
" Network: %s\n"
|
" Network: %s\n"
|
||||||
" Sound driver: %s\n"
|
" Sound driver: %s\n"
|
||||||
" Sound set: %s (%u)\n"
|
" Sound set: %s (%u)\n"
|
||||||
" Video driver: %s\n\n",
|
" Video driver: %s\n"
|
||||||
|
" Pathfinder: %s %s %s\n\n",
|
||||||
BlitterFactory::GetCurrentBlitter() == nullptr ? "none" : BlitterFactory::GetCurrentBlitter()->GetName(),
|
BlitterFactory::GetCurrentBlitter() == nullptr ? "none" : BlitterFactory::GetCurrentBlitter()->GetName(),
|
||||||
BaseGraphics::GetUsedSet() == nullptr ? "none" : BaseGraphics::GetUsedSet()->name,
|
BaseGraphics::GetUsedSet() == nullptr ? "none" : BaseGraphics::GetUsedSet()->name,
|
||||||
BaseGraphics::GetUsedSet() == nullptr ? UINT32_MAX : BaseGraphics::GetUsedSet()->version,
|
BaseGraphics::GetUsedSet() == nullptr ? UINT32_MAX : BaseGraphics::GetUsedSet()->version,
|
||||||
@@ -201,7 +209,8 @@ char *CrashLog::LogConfiguration(char *buffer, const char *last) const
|
|||||||
SoundDriver::GetInstance() == nullptr ? "none" : SoundDriver::GetInstance()->GetName(),
|
SoundDriver::GetInstance() == nullptr ? "none" : SoundDriver::GetInstance()->GetName(),
|
||||||
BaseSounds::GetUsedSet() == nullptr ? "none" : BaseSounds::GetUsedSet()->name,
|
BaseSounds::GetUsedSet() == nullptr ? "none" : BaseSounds::GetUsedSet()->name,
|
||||||
BaseSounds::GetUsedSet() == nullptr ? UINT32_MAX : BaseSounds::GetUsedSet()->version,
|
BaseSounds::GetUsedSet() == nullptr ? UINT32_MAX : BaseSounds::GetUsedSet()->version,
|
||||||
VideoDriver::GetInstance() == nullptr ? "none" : VideoDriver::GetInstance()->GetName()
|
VideoDriver::GetInstance() == nullptr ? "none" : VideoDriver::GetInstance()->GetName(),
|
||||||
|
pathfinder_name(_settings_game.pf.pathfinder_for_trains), pathfinder_name(_settings_game.pf.pathfinder_for_roadvehs), pathfinder_name(_settings_game.pf.pathfinder_for_ships)
|
||||||
);
|
);
|
||||||
|
|
||||||
buffer += seprintf(buffer, last,
|
buffer += seprintf(buffer, last,
|
||||||
@@ -396,7 +405,7 @@ char *CrashLog::FillCrashLog(char *buffer, const char *last) const
|
|||||||
|
|
||||||
YearMonthDay ymd;
|
YearMonthDay ymd;
|
||||||
ConvertDateToYMD(_date, &ymd);
|
ConvertDateToYMD(_date, &ymd);
|
||||||
buffer += seprintf(buffer, last, "In game date: %i-%02i-%02i (%i, %i)\n", _cur_date_ymd.year, _cur_date_ymd.month + 1, _cur_date_ymd.day, _date_fract, _tick_skip_counter);
|
buffer += seprintf(buffer, last, "In game date: %i-%02i-%02i (%i, %i) (DL: %u)\n", _cur_date_ymd.year, _cur_date_ymd.month + 1, _cur_date_ymd.day, _date_fract, _tick_skip_counter, _settings_game.economy.day_length_factor);
|
||||||
if (_game_load_time != 0) {
|
if (_game_load_time != 0) {
|
||||||
buffer += seprintf(buffer, last, "Game loaded at: %i-%02i-%02i (%i, %i), %s",
|
buffer += seprintf(buffer, last, "Game loaded at: %i-%02i-%02i (%i, %i), %s",
|
||||||
_game_load_cur_date_ymd.year, _game_load_cur_date_ymd.month + 1, _game_load_cur_date_ymd.day, _game_load_date_fract, _game_load_tick_skip_counter, asctime(gmtime(&_game_load_time)));
|
_game_load_cur_date_ymd.year, _game_load_cur_date_ymd.month + 1, _game_load_cur_date_ymd.day, _game_load_date_fract, _game_load_tick_skip_counter, asctime(gmtime(&_game_load_time)));
|
||||||
@@ -440,16 +449,26 @@ char *CrashLog::FillCrashLog(char *buffer, const char *last) const
|
|||||||
* @param last The last position in the buffer to write to.
|
* @param last The last position in the buffer to write to.
|
||||||
* @return the position of the \c '\0' character after the buffer.
|
* @return the position of the \c '\0' character after the buffer.
|
||||||
*/
|
*/
|
||||||
char *CrashLog::FillDesyncCrashLog(char *buffer, const char *last) const
|
char *CrashLog::FillDesyncCrashLog(char *buffer, const char *last, const DesyncExtraInfo &info) const
|
||||||
{
|
{
|
||||||
time_t cur_time = time(nullptr);
|
time_t cur_time = time(nullptr);
|
||||||
buffer += seprintf(buffer, last, "*** OpenTTD Multiplayer %s Desync Report ***\n\n", _network_server ? "Server" : "Client");
|
buffer += seprintf(buffer, last, "*** OpenTTD Multiplayer %s Desync Report ***\n\n", _network_server ? "Server" : "Client");
|
||||||
|
|
||||||
buffer += seprintf(buffer, last, "Desync at: %s", asctime(gmtime(&cur_time)));
|
buffer += seprintf(buffer, last, "Desync at: %s", asctime(gmtime(&cur_time)));
|
||||||
|
if (!_network_server && info.flags) {
|
||||||
|
auto flag_check = [&](DesyncExtraInfo::Flags flag, const char *str) {
|
||||||
|
return info.flags & flag ? str : "";
|
||||||
|
};
|
||||||
|
buffer += seprintf(buffer, last, "Flags: %s%s%s%s\n",
|
||||||
|
flag_check(DesyncExtraInfo::DEIF_RAND1, "R"),
|
||||||
|
flag_check(DesyncExtraInfo::DEIF_RAND2, "Z"),
|
||||||
|
flag_check(DesyncExtraInfo::DEIF_STATE, "S"),
|
||||||
|
flag_check(DesyncExtraInfo::DEIF_DBL_RAND, "D"));
|
||||||
|
}
|
||||||
|
|
||||||
YearMonthDay ymd;
|
YearMonthDay ymd;
|
||||||
ConvertDateToYMD(_date, &ymd);
|
ConvertDateToYMD(_date, &ymd);
|
||||||
buffer += seprintf(buffer, last, "In game date: %i-%02i-%02i (%i, %i)\n", _cur_date_ymd.year, _cur_date_ymd.month + 1, _cur_date_ymd.day, _date_fract, _tick_skip_counter);
|
buffer += seprintf(buffer, last, "In game date: %i-%02i-%02i (%i, %i) (DL: %u)\n", _cur_date_ymd.year, _cur_date_ymd.month + 1, _cur_date_ymd.day, _date_fract, _tick_skip_counter, _settings_game.economy.day_length_factor);
|
||||||
if (_game_load_time != 0) {
|
if (_game_load_time != 0) {
|
||||||
buffer += seprintf(buffer, last, "Game loaded at: %i-%02i-%02i (%i, %i), %s",
|
buffer += seprintf(buffer, last, "Game loaded at: %i-%02i-%02i (%i, %i), %s",
|
||||||
_game_load_cur_date_ymd.year, _game_load_cur_date_ymd.month + 1, _game_load_cur_date_ymd.day, _game_load_date_fract, _game_load_tick_skip_counter, asctime(gmtime(&_game_load_time)));
|
_game_load_cur_date_ymd.year, _game_load_cur_date_ymd.month + 1, _game_load_cur_date_ymd.day, _game_load_date_fract, _game_load_tick_skip_counter, asctime(gmtime(&_game_load_time)));
|
||||||
@@ -490,7 +509,7 @@ char *CrashLog::FillDesyncCrashLog(char *buffer, const char *last) const
|
|||||||
* @param filename_last The last position in the filename buffer.
|
* @param filename_last The last position in the filename buffer.
|
||||||
* @return true when the crash log was successfully written.
|
* @return true when the crash log was successfully written.
|
||||||
*/
|
*/
|
||||||
bool CrashLog::WriteCrashLog(const char *buffer, char *filename, const char *filename_last, const char *name) const
|
bool CrashLog::WriteCrashLog(const char *buffer, char *filename, const char *filename_last, const char *name, FILE **crashlog_file) const
|
||||||
{
|
{
|
||||||
seprintf(filename, filename_last, "%s%s.log", _personal_dir, name);
|
seprintf(filename, filename_last, "%s%s.log", _personal_dir, name);
|
||||||
|
|
||||||
@@ -500,7 +519,11 @@ bool CrashLog::WriteCrashLog(const char *buffer, char *filename, const char *fil
|
|||||||
size_t len = strlen(buffer);
|
size_t len = strlen(buffer);
|
||||||
size_t written = fwrite(buffer, 1, len, file);
|
size_t written = fwrite(buffer, 1, len, file);
|
||||||
|
|
||||||
|
if (crashlog_file) {
|
||||||
|
*crashlog_file = file;
|
||||||
|
} else {
|
||||||
FioFCloseFile(file);
|
FioFCloseFile(file);
|
||||||
|
}
|
||||||
return len == written;
|
return len == written;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -618,7 +641,7 @@ bool CrashLog::MakeCrashLog() const
|
|||||||
* information like paths to the console.
|
* information like paths to the console.
|
||||||
* @return true when everything is made successfully.
|
* @return true when everything is made successfully.
|
||||||
*/
|
*/
|
||||||
bool CrashLog::MakeDesyncCrashLog(const std::string *log_in, std::string *log_out) const
|
bool CrashLog::MakeDesyncCrashLog(const std::string *log_in, std::string *log_out, const DesyncExtraInfo &info) const
|
||||||
{
|
{
|
||||||
char filename[MAX_PATH];
|
char filename[MAX_PATH];
|
||||||
char buffer[65536 * 2];
|
char buffer[65536 * 2];
|
||||||
@@ -632,16 +655,16 @@ bool CrashLog::MakeDesyncCrashLog(const std::string *log_in, std::string *log_ou
|
|||||||
strftime(name_buffer_date, lastof(name_buffer) - name_buffer_date, "%Y%m%dT%H%M%SZ", gmtime(&cur_time));
|
strftime(name_buffer_date, lastof(name_buffer) - name_buffer_date, "%Y%m%dT%H%M%SZ", gmtime(&cur_time));
|
||||||
|
|
||||||
printf("Desync encountered (%s), generating desync log...\n", mode);
|
printf("Desync encountered (%s), generating desync log...\n", mode);
|
||||||
char *b = this->FillDesyncCrashLog(buffer, lastof(buffer));
|
char *b = this->FillDesyncCrashLog(buffer, lastof(buffer), info);
|
||||||
|
|
||||||
|
if (log_out) log_out->assign(buffer);
|
||||||
|
|
||||||
if (log_in && !log_in->empty()) {
|
if (log_in && !log_in->empty()) {
|
||||||
b = strecpy(b, "\n", lastof(buffer), true);
|
b = strecpy(b, "\n", lastof(buffer), true);
|
||||||
b = strecpy(b, log_in->c_str(), lastof(buffer), true);
|
b = strecpy(b, log_in->c_str(), lastof(buffer), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (log_out) log_out->assign(buffer);
|
bool bret = this->WriteCrashLog(buffer, filename, lastof(filename), name_buffer, info.log_file);
|
||||||
|
|
||||||
bool bret = this->WriteCrashLog(buffer, filename, lastof(filename), name_buffer);
|
|
||||||
if (bret) {
|
if (bret) {
|
||||||
printf("Desync log written to %s. Please add this file to any bug reports.\n\n", filename);
|
printf("Desync log written to %s. Please add this file to any bug reports.\n\n", filename);
|
||||||
} else {
|
} else {
|
||||||
|
@@ -12,8 +12,23 @@
|
|||||||
#ifndef CRASHLOG_H
|
#ifndef CRASHLOG_H
|
||||||
#define CRASHLOG_H
|
#define CRASHLOG_H
|
||||||
|
|
||||||
|
#include "core/enum_type.hpp"
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
struct DesyncExtraInfo {
|
||||||
|
enum Flags {
|
||||||
|
DEIF_NONE = 0, ///< no flags
|
||||||
|
DEIF_RAND1 = 1 << 0, ///< random 1 mismatch
|
||||||
|
DEIF_RAND2 = 1 << 1, ///< random 2 mismatch
|
||||||
|
DEIF_STATE = 1 << 2, ///< state mismatch
|
||||||
|
DEIF_DBL_RAND = 1 << 3, ///< double-seed sent
|
||||||
|
};
|
||||||
|
|
||||||
|
Flags flags = DEIF_NONE;
|
||||||
|
FILE **log_file = nullptr; ///< save unclosed log file handle here
|
||||||
|
};
|
||||||
|
DECLARE_ENUM_AS_BIT_SET(DesyncExtraInfo::Flags)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class for creating crash logs.
|
* Helper class for creating crash logs.
|
||||||
*/
|
*/
|
||||||
@@ -113,8 +128,8 @@ public:
|
|||||||
virtual ~CrashLog() {}
|
virtual ~CrashLog() {}
|
||||||
|
|
||||||
char *FillCrashLog(char *buffer, const char *last) const;
|
char *FillCrashLog(char *buffer, const char *last) const;
|
||||||
char *FillDesyncCrashLog(char *buffer, const char *last) const;
|
char *FillDesyncCrashLog(char *buffer, const char *last, const DesyncExtraInfo &info) const;
|
||||||
bool WriteCrashLog(const char *buffer, char *filename, const char *filename_last, const char *name = "crash") const;
|
bool WriteCrashLog(const char *buffer, char *filename, const char *filename_last, const char *name = "crash", FILE **crashlog_file = nullptr) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write the (crash) dump to a file.
|
* Write the (crash) dump to a file.
|
||||||
@@ -130,7 +145,7 @@ public:
|
|||||||
bool WriteScreenshot(char *filename, const char *filename_last, const char *name = "crash") const;
|
bool WriteScreenshot(char *filename, const char *filename_last, const char *name = "crash") const;
|
||||||
|
|
||||||
bool MakeCrashLog() const;
|
bool MakeCrashLog() const;
|
||||||
bool MakeDesyncCrashLog(const std::string *log_in, std::string *log_out) const;
|
bool MakeDesyncCrashLog(const std::string *log_in, std::string *log_out, const DesyncExtraInfo &info) const;
|
||||||
bool MakeCrashSavegameAndScreenshot() const;
|
bool MakeCrashSavegameAndScreenshot() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -140,7 +155,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
static void InitialiseCrashLog();
|
static void InitialiseCrashLog();
|
||||||
|
|
||||||
static void DesyncCrashLog(const std::string *log_in, std::string *log_out);
|
static void DesyncCrashLog(const std::string *log_in, std::string *log_out, const DesyncExtraInfo &info);
|
||||||
|
|
||||||
static void SetErrorMessage(const char *message);
|
static void SetErrorMessage(const char *message);
|
||||||
static void AfterCrashLogCleanup();
|
static void AfterCrashLogCleanup();
|
||||||
|
@@ -47,6 +47,7 @@
|
|||||||
#include "company_base.h"
|
#include "company_base.h"
|
||||||
#include "core/random_func.hpp"
|
#include "core/random_func.hpp"
|
||||||
#include "core/backup_type.hpp"
|
#include "core/backup_type.hpp"
|
||||||
|
#include "core/checksum_func.hpp"
|
||||||
|
|
||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
|
|
||||||
@@ -707,6 +708,7 @@ static DisasterVehicleTickProc * const _disastervehicle_tick_procs[] = {
|
|||||||
|
|
||||||
bool DisasterVehicle::Tick()
|
bool DisasterVehicle::Tick()
|
||||||
{
|
{
|
||||||
|
UpdateStateChecksum((((uint64) this->x_pos) << 32) | this->y_pos);
|
||||||
return _disastervehicle_tick_procs[this->subtype](this);
|
return _disastervehicle_tick_procs[this->subtype](this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -18,6 +18,7 @@
|
|||||||
#include "animated_tile_func.h"
|
#include "animated_tile_func.h"
|
||||||
#include "effectvehicle_func.h"
|
#include "effectvehicle_func.h"
|
||||||
#include "effectvehicle_base.h"
|
#include "effectvehicle_base.h"
|
||||||
|
#include "core/checksum_func.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
@@ -670,6 +671,7 @@ EffectVehicle *CreateEffectVehicleRel(const Vehicle *v, int x, int y, int z, Eff
|
|||||||
|
|
||||||
bool EffectVehicle::Tick()
|
bool EffectVehicle::Tick()
|
||||||
{
|
{
|
||||||
|
UpdateStateChecksum((((uint64) this->x_pos) << 32) | this->y_pos);
|
||||||
return _effect_tick_procs[this->subtype](this);
|
return _effect_tick_procs[this->subtype](this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -41,6 +41,8 @@ NetworkGameSocketHandler::NetworkGameSocketHandler(SOCKET s) : info(nullptr), cl
|
|||||||
*/
|
*/
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::CloseConnection(bool error)
|
NetworkRecvStatus NetworkGameSocketHandler::CloseConnection(bool error)
|
||||||
{
|
{
|
||||||
|
if (this->ignore_close) return NETWORK_RECV_STATUS_CONN_LOST;
|
||||||
|
|
||||||
/* Clients drop back to the main menu */
|
/* Clients drop back to the main menu */
|
||||||
if (!_network_server && _networking) {
|
if (!_network_server && _networking) {
|
||||||
extern void ClientNetworkEmergencySave(); // from network_client.cpp
|
extern void ClientNetworkEmergencySave(); // from network_client.cpp
|
||||||
@@ -79,6 +81,8 @@ NetworkRecvStatus NetworkGameSocketHandler::HandlePacket(Packet *p)
|
|||||||
case PACKET_SERVER_NEED_COMPANY_PASSWORD: return this->Receive_SERVER_NEED_COMPANY_PASSWORD(p);
|
case PACKET_SERVER_NEED_COMPANY_PASSWORD: return this->Receive_SERVER_NEED_COMPANY_PASSWORD(p);
|
||||||
case PACKET_CLIENT_GAME_PASSWORD: return this->Receive_CLIENT_GAME_PASSWORD(p);
|
case PACKET_CLIENT_GAME_PASSWORD: return this->Receive_CLIENT_GAME_PASSWORD(p);
|
||||||
case PACKET_CLIENT_COMPANY_PASSWORD: return this->Receive_CLIENT_COMPANY_PASSWORD(p);
|
case PACKET_CLIENT_COMPANY_PASSWORD: return this->Receive_CLIENT_COMPANY_PASSWORD(p);
|
||||||
|
case PACKET_CLIENT_SETTINGS_PASSWORD: return this->Receive_CLIENT_SETTINGS_PASSWORD(p);
|
||||||
|
case PACKET_SERVER_SETTINGS_ACCESS: return this->Receive_SERVER_SETTINGS_ACCESS(p);
|
||||||
case PACKET_SERVER_WELCOME: return this->Receive_SERVER_WELCOME(p);
|
case PACKET_SERVER_WELCOME: return this->Receive_SERVER_WELCOME(p);
|
||||||
case PACKET_CLIENT_GETMAP: return this->Receive_CLIENT_GETMAP(p);
|
case PACKET_CLIENT_GETMAP: return this->Receive_CLIENT_GETMAP(p);
|
||||||
case PACKET_SERVER_WAIT: return this->Receive_SERVER_WAIT(p);
|
case PACKET_SERVER_WAIT: return this->Receive_SERVER_WAIT(p);
|
||||||
@@ -100,6 +104,7 @@ NetworkRecvStatus NetworkGameSocketHandler::HandlePacket(Packet *p)
|
|||||||
case PACKET_CLIENT_QUIT: return this->Receive_CLIENT_QUIT(p);
|
case PACKET_CLIENT_QUIT: return this->Receive_CLIENT_QUIT(p);
|
||||||
case PACKET_CLIENT_ERROR: return this->Receive_CLIENT_ERROR(p);
|
case PACKET_CLIENT_ERROR: return this->Receive_CLIENT_ERROR(p);
|
||||||
case PACKET_CLIENT_DESYNC_LOG: return this->Receive_CLIENT_DESYNC_LOG(p);
|
case PACKET_CLIENT_DESYNC_LOG: return this->Receive_CLIENT_DESYNC_LOG(p);
|
||||||
|
case PACKET_SERVER_DESYNC_LOG: return this->Receive_SERVER_DESYNC_LOG(p);
|
||||||
case PACKET_SERVER_QUIT: return this->Receive_SERVER_QUIT(p);
|
case PACKET_SERVER_QUIT: return this->Receive_SERVER_QUIT(p);
|
||||||
case PACKET_SERVER_ERROR_QUIT: return this->Receive_SERVER_ERROR_QUIT(p);
|
case PACKET_SERVER_ERROR_QUIT: return this->Receive_SERVER_ERROR_QUIT(p);
|
||||||
case PACKET_SERVER_SHUTDOWN: return this->Receive_SERVER_SHUTDOWN(p);
|
case PACKET_SERVER_SHUTDOWN: return this->Receive_SERVER_SHUTDOWN(p);
|
||||||
@@ -166,6 +171,8 @@ NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_NEED_GAME_PASSWORD(Pa
|
|||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_NEED_COMPANY_PASSWORD(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_NEED_COMPANY_PASSWORD); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_NEED_COMPANY_PASSWORD(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_NEED_COMPANY_PASSWORD); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_GAME_PASSWORD(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_GAME_PASSWORD); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_GAME_PASSWORD(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_GAME_PASSWORD); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_COMPANY_PASSWORD(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_COMPANY_PASSWORD); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_COMPANY_PASSWORD(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_COMPANY_PASSWORD); }
|
||||||
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_SETTINGS_PASSWORD(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_SETTINGS_PASSWORD); }
|
||||||
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_SETTINGS_ACCESS(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_SETTINGS_ACCESS); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_WELCOME(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_WELCOME); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_WELCOME(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_WELCOME); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_GETMAP(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_GETMAP); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_GETMAP(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_GETMAP); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_WAIT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_WAIT); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_WAIT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_WAIT); }
|
||||||
@@ -187,6 +194,7 @@ NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_SET_NAME(Packet *p) {
|
|||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_QUIT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_QUIT); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_QUIT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_QUIT); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_ERROR(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_ERROR); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_ERROR(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_ERROR); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_DESYNC_LOG(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_DESYNC_LOG); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_DESYNC_LOG(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_DESYNC_LOG); }
|
||||||
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_DESYNC_LOG(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_DESYNC_LOG); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_QUIT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_QUIT); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_QUIT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_QUIT); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_ERROR_QUIT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_ERROR_QUIT); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_ERROR_QUIT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_ERROR_QUIT); }
|
||||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_SHUTDOWN(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_SHUTDOWN); }
|
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_SHUTDOWN(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_SHUTDOWN); }
|
||||||
|
@@ -63,6 +63,8 @@ enum PacketGameType {
|
|||||||
PACKET_CLIENT_GAME_PASSWORD, ///< Clients sends the (hashed) game password.
|
PACKET_CLIENT_GAME_PASSWORD, ///< Clients sends the (hashed) game password.
|
||||||
PACKET_SERVER_NEED_COMPANY_PASSWORD, ///< Server requests the (hashed) company password.
|
PACKET_SERVER_NEED_COMPANY_PASSWORD, ///< Server requests the (hashed) company password.
|
||||||
PACKET_CLIENT_COMPANY_PASSWORD, ///< Client sends the (hashed) company password.
|
PACKET_CLIENT_COMPANY_PASSWORD, ///< Client sends the (hashed) company password.
|
||||||
|
PACKET_CLIENT_SETTINGS_PASSWORD, ///< Client sends the (hashed) settings password.
|
||||||
|
PACKET_SERVER_SETTINGS_ACCESS, ///< Server sends the settings access state.
|
||||||
|
|
||||||
/* The server welcomes the authenticated client and sends information of other clients. */
|
/* The server welcomes the authenticated client and sends information of other clients. */
|
||||||
PACKET_SERVER_WELCOME, ///< Server welcomes you and gives you your #ClientID.
|
PACKET_SERVER_WELCOME, ///< Server welcomes you and gives you your #ClientID.
|
||||||
@@ -122,6 +124,7 @@ enum PacketGameType {
|
|||||||
PACKET_CLIENT_ERROR, ///< A client reports an error to the server.
|
PACKET_CLIENT_ERROR, ///< A client reports an error to the server.
|
||||||
PACKET_SERVER_ERROR_QUIT, ///< A server tells that a client has hit an error and did quit.
|
PACKET_SERVER_ERROR_QUIT, ///< A server tells that a client has hit an error and did quit.
|
||||||
PACKET_CLIENT_DESYNC_LOG, ///< A client reports a desync log
|
PACKET_CLIENT_DESYNC_LOG, ///< A client reports a desync log
|
||||||
|
PACKET_SERVER_DESYNC_LOG, ///< A server reports a desync log
|
||||||
|
|
||||||
PACKET_END, ///< Must ALWAYS be on the end of this list!! (period)
|
PACKET_END, ///< Must ALWAYS be on the end of this list!! (period)
|
||||||
};
|
};
|
||||||
@@ -158,6 +161,7 @@ private:
|
|||||||
NetworkClientInfo *info; ///< Client info related to this socket
|
NetworkClientInfo *info; ///< Client info related to this socket
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
bool ignore_close = false;
|
||||||
NetworkRecvStatus ReceiveInvalidPacket(PacketGameType type);
|
NetworkRecvStatus ReceiveInvalidPacket(PacketGameType type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -262,6 +266,21 @@ protected:
|
|||||||
*/
|
*/
|
||||||
virtual NetworkRecvStatus Receive_CLIENT_COMPANY_PASSWORD(Packet *p);
|
virtual NetworkRecvStatus Receive_CLIENT_COMPANY_PASSWORD(Packet *p);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a password to the server to authorize
|
||||||
|
* uint8 Password type (see NetworkPasswordType).
|
||||||
|
* string The password.
|
||||||
|
* @param p The packet that was just received.
|
||||||
|
*/
|
||||||
|
virtual NetworkRecvStatus Receive_CLIENT_SETTINGS_PASSWORD(Packet *p);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indication to the client that the setting access state has changed
|
||||||
|
* bool setting access state
|
||||||
|
* @param p The packet that was just received.
|
||||||
|
*/
|
||||||
|
virtual NetworkRecvStatus Receive_SERVER_SETTINGS_ACCESS(Packet *p);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The client is joined and ready to receive his map:
|
* The client is joined and ready to receive his map:
|
||||||
* uint32 Own client ID.
|
* uint32 Own client ID.
|
||||||
@@ -428,6 +447,7 @@ protected:
|
|||||||
*/
|
*/
|
||||||
virtual NetworkRecvStatus Receive_CLIENT_ERROR(Packet *p);
|
virtual NetworkRecvStatus Receive_CLIENT_ERROR(Packet *p);
|
||||||
virtual NetworkRecvStatus Receive_CLIENT_DESYNC_LOG(Packet *p);
|
virtual NetworkRecvStatus Receive_CLIENT_DESYNC_LOG(Packet *p);
|
||||||
|
virtual NetworkRecvStatus Receive_SERVER_DESYNC_LOG(Packet *p);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notification that a client left the game:
|
* Notification that a client left the game:
|
||||||
|
@@ -35,6 +35,7 @@
|
|||||||
#include "../core/pool_func.hpp"
|
#include "../core/pool_func.hpp"
|
||||||
#include "../gfx_func.h"
|
#include "../gfx_func.h"
|
||||||
#include "../error.h"
|
#include "../error.h"
|
||||||
|
#include "../core/checksum_func.hpp"
|
||||||
|
|
||||||
#include "../safeguards.h"
|
#include "../safeguards.h"
|
||||||
|
|
||||||
@@ -56,6 +57,7 @@ bool _network_server; ///< network-server is active
|
|||||||
bool _network_available; ///< is network mode available?
|
bool _network_available; ///< is network mode available?
|
||||||
bool _network_dedicated; ///< are we a dedicated server?
|
bool _network_dedicated; ///< are we a dedicated server?
|
||||||
bool _is_network_server; ///< Does this client wants to be a network-server?
|
bool _is_network_server; ///< Does this client wants to be a network-server?
|
||||||
|
bool _network_settings_access; ///< Can this client change server settings?
|
||||||
NetworkServerGameInfo _network_game_info; ///< Information about our game.
|
NetworkServerGameInfo _network_game_info; ///< Information about our game.
|
||||||
NetworkCompanyState *_network_company_states = nullptr; ///< Statistics about some companies.
|
NetworkCompanyState *_network_company_states = nullptr; ///< Statistics about some companies.
|
||||||
ClientID _network_own_client_id; ///< Our client identifier.
|
ClientID _network_own_client_id; ///< Our client identifier.
|
||||||
@@ -74,6 +76,7 @@ uint32 _sync_seed_1; ///< Seed to compare during sync checks.
|
|||||||
#ifdef NETWORK_SEND_DOUBLE_SEED
|
#ifdef NETWORK_SEND_DOUBLE_SEED
|
||||||
uint32 _sync_seed_2; ///< Second part of the seed.
|
uint32 _sync_seed_2; ///< Second part of the seed.
|
||||||
#endif
|
#endif
|
||||||
|
uint64 _sync_state_checksum; ///< State checksum to compare during sync checks.
|
||||||
uint32 _sync_frame; ///< The frame to perform the sync check.
|
uint32 _sync_frame; ///< The frame to perform the sync check.
|
||||||
bool _network_first_time; ///< Whether we have finished joining or not.
|
bool _network_first_time; ///< Whether we have finished joining or not.
|
||||||
bool _network_udp_server; ///< Is the UDP server started?
|
bool _network_udp_server; ///< Is the UDP server started?
|
||||||
@@ -893,7 +896,7 @@ void NetworkGameLoop()
|
|||||||
/* We don't want to log multiple times if paused. */
|
/* We don't want to log multiple times if paused. */
|
||||||
static Date last_log;
|
static Date last_log;
|
||||||
if (last_log != _date) {
|
if (last_log != _date) {
|
||||||
DEBUG(desync, 1, "sync: date{%08x; %02x; %02x}; %08x; %08x", _date, _date_fract, _tick_skip_counter, _random.state[0], _random.state[1]);
|
DEBUG(desync, 2, "sync: date{%08x; %02x; %02x}; %08x; %08x", _date, _date_fract, _tick_skip_counter, _random.state[0], _random.state[1]);
|
||||||
last_log = _date;
|
last_log = _date;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1028,6 +1031,7 @@ void NetworkGameLoop()
|
|||||||
#ifdef NETWORK_SEND_DOUBLE_SEED
|
#ifdef NETWORK_SEND_DOUBLE_SEED
|
||||||
_sync_seed_2 = _random.state[1];
|
_sync_seed_2 = _random.state[1];
|
||||||
#endif
|
#endif
|
||||||
|
_sync_state_checksum = _state_checksum.state;
|
||||||
|
|
||||||
NetworkServer_Tick(send_frame);
|
NetworkServer_Tick(send_frame);
|
||||||
} else {
|
} else {
|
||||||
|
@@ -22,5 +22,6 @@ extern bool _network_server; ///< network-server is active
|
|||||||
extern bool _network_available; ///< is network mode available?
|
extern bool _network_available; ///< is network mode available?
|
||||||
extern bool _network_dedicated; ///< are we a dedicated server?
|
extern bool _network_dedicated; ///< are we a dedicated server?
|
||||||
extern bool _is_network_server; ///< Does this client wants to be a network-server?
|
extern bool _is_network_server; ///< Does this client wants to be a network-server?
|
||||||
|
extern bool _network_settings_access; ///< Can this client change server settings?
|
||||||
|
|
||||||
#endif /* NETWORK_H */
|
#endif /* NETWORK_H */
|
||||||
|
@@ -32,6 +32,8 @@
|
|||||||
#include "../core/backup_type.hpp"
|
#include "../core/backup_type.hpp"
|
||||||
#include "../thread.h"
|
#include "../thread.h"
|
||||||
#include "../crashlog.h"
|
#include "../crashlog.h"
|
||||||
|
#include "../core/checksum_func.hpp"
|
||||||
|
#include "../fileio_func.h"
|
||||||
|
|
||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
|
|
||||||
@@ -134,6 +136,7 @@ void ClientNetworkEmergencySave()
|
|||||||
{
|
{
|
||||||
if (!_settings_client.gui.autosave_on_network_disconnect) return;
|
if (!_settings_client.gui.autosave_on_network_disconnect) return;
|
||||||
if (!_networking) return;
|
if (!_networking) return;
|
||||||
|
if (!ClientNetworkGameSocketHandler::EmergencySavePossible()) return;
|
||||||
|
|
||||||
const char *filename = "netsave.sav";
|
const char *filename = "netsave.sav";
|
||||||
DEBUG(net, 0, "Client: Performing emergency save (%s)", filename);
|
DEBUG(net, 0, "Client: Performing emergency save (%s)", filename);
|
||||||
@@ -158,8 +161,18 @@ ClientNetworkGameSocketHandler::~ClientNetworkGameSocketHandler()
|
|||||||
{
|
{
|
||||||
assert(ClientNetworkGameSocketHandler::my_client == this);
|
assert(ClientNetworkGameSocketHandler::my_client == this);
|
||||||
ClientNetworkGameSocketHandler::my_client = nullptr;
|
ClientNetworkGameSocketHandler::my_client = nullptr;
|
||||||
|
_network_settings_access = false;
|
||||||
|
|
||||||
delete this->savegame;
|
delete this->savegame;
|
||||||
|
|
||||||
|
if (this->desync_log_file) {
|
||||||
|
if (!this->server_desync_log.empty()) {
|
||||||
|
fwrite("\n", 1, 1, this->desync_log_file);
|
||||||
|
fwrite(this->server_desync_log.data(), 1, this->server_desync_log.size(), this->desync_log_file);
|
||||||
|
}
|
||||||
|
FioFCloseFile(this->desync_log_file);
|
||||||
|
this->desync_log_file = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkRecvStatus ClientNetworkGameSocketHandler::CloseConnection(NetworkRecvStatus status)
|
NetworkRecvStatus ClientNetworkGameSocketHandler::CloseConnection(NetworkRecvStatus status)
|
||||||
@@ -173,6 +186,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::CloseConnection(NetworkRecvSta
|
|||||||
* that code any more complex or more aware of the validity of the socket.
|
* that code any more complex or more aware of the validity of the socket.
|
||||||
*/
|
*/
|
||||||
if (this->sock == INVALID_SOCKET) return status;
|
if (this->sock == INVALID_SOCKET) return status;
|
||||||
|
if (this->status == STATUS_CLOSING) return status;
|
||||||
|
|
||||||
DEBUG(net, 1, "Shutting down client connection %d", this->client_id);
|
DEBUG(net, 1, "Shutting down client connection %d", this->client_id);
|
||||||
|
|
||||||
@@ -190,6 +204,12 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::CloseConnection(NetworkRecvSta
|
|||||||
|
|
||||||
DEBUG(net, 1, "Shutdown client connection %d", this->client_id);
|
DEBUG(net, 1, "Shutdown client connection %d", this->client_id);
|
||||||
|
|
||||||
|
if (status == NETWORK_RECV_STATUS_DESYNC) {
|
||||||
|
this->status = STATUS_CLOSING;
|
||||||
|
this->ignore_close = true;
|
||||||
|
this->ReceivePackets();
|
||||||
|
}
|
||||||
|
|
||||||
delete this->GetInfo();
|
delete this->GetInfo();
|
||||||
delete this;
|
delete this;
|
||||||
|
|
||||||
@@ -282,16 +302,26 @@ void ClientNetworkGameSocketHandler::ClientError(NetworkRecvStatus res)
|
|||||||
if (_sync_frame != 0) {
|
if (_sync_frame != 0) {
|
||||||
if (_sync_frame == _frame_counter) {
|
if (_sync_frame == _frame_counter) {
|
||||||
#ifdef NETWORK_SEND_DOUBLE_SEED
|
#ifdef NETWORK_SEND_DOUBLE_SEED
|
||||||
if (_sync_seed_1 != _random.state[0] || _sync_seed_2 != _random.state[1]) {
|
if (_sync_seed_1 != _random.state[0] || _sync_seed_2 != _random.state[1] || _sync_state_checksum != _state_checksum.state) {
|
||||||
#else
|
#else
|
||||||
if (_sync_seed_1 != _random.state[0]) {
|
if (_sync_seed_1 != _random.state[0] || _sync_state_checksum != _state_checksum.state) {
|
||||||
#endif
|
#endif
|
||||||
|
DesyncExtraInfo info;
|
||||||
|
if (_sync_seed_1 != _random.state[0]) info.flags |= DesyncExtraInfo::DEIF_RAND1;
|
||||||
|
#ifdef NETWORK_SEND_DOUBLE_SEED
|
||||||
|
if (_sync_seed_2 != _random.state[1]) info.flags |= DesyncExtraInfo::DEIF_RAND2;
|
||||||
|
info.flags |= DesyncExtraInfo::DEIF_DBL_RAND;
|
||||||
|
#endif
|
||||||
|
if (_sync_state_checksum != _state_checksum.state) info.flags |= DesyncExtraInfo::DEIF_STATE;
|
||||||
|
|
||||||
NetworkError(STR_NETWORK_ERROR_DESYNC);
|
NetworkError(STR_NETWORK_ERROR_DESYNC);
|
||||||
DEBUG(desync, 1, "sync_err: date{%08x; %02x; %02x}", _date, _date_fract, _tick_skip_counter);
|
DEBUG(desync, 1, "sync_err: date{%08x; %02x; %02x} {%x, " OTTD_PRINTFHEX64 "} != {%x, " OTTD_PRINTFHEX64 "}"
|
||||||
|
, _date, _date_fract, _tick_skip_counter, _sync_seed_1, _sync_state_checksum, _random.state[0], _state_checksum.state);
|
||||||
DEBUG(net, 0, "Sync error detected!");
|
DEBUG(net, 0, "Sync error detected!");
|
||||||
|
|
||||||
std::string desync_log;
|
std::string desync_log;
|
||||||
CrashLog::DesyncCrashLog(nullptr, &desync_log);
|
info.log_file = &(my_client->desync_log_file);
|
||||||
|
CrashLog::DesyncCrashLog(nullptr, &desync_log, info);
|
||||||
my_client->SendDesyncLog(desync_log);
|
my_client->SendDesyncLog(desync_log);
|
||||||
my_client->ClientError(NETWORK_RECV_STATUS_DESYNC);
|
my_client->ClientError(NETWORK_RECV_STATUS_DESYNC);
|
||||||
return false;
|
return false;
|
||||||
@@ -315,6 +345,14 @@ void ClientNetworkGameSocketHandler::ClientError(NetworkRecvStatus res)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* static */ bool ClientNetworkGameSocketHandler::EmergencySavePossible()
|
||||||
|
{
|
||||||
|
if (!my_client) return false;
|
||||||
|
if (my_client->emergency_save_done) return false;
|
||||||
|
my_client->emergency_save_done = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Our client's connection. */
|
/** Our client's connection. */
|
||||||
ClientNetworkGameSocketHandler * ClientNetworkGameSocketHandler::my_client = nullptr;
|
ClientNetworkGameSocketHandler * ClientNetworkGameSocketHandler::my_client = nullptr;
|
||||||
@@ -323,8 +361,14 @@ ClientNetworkGameSocketHandler * ClientNetworkGameSocketHandler::my_client = nul
|
|||||||
static uint32 last_ack_frame;
|
static uint32 last_ack_frame;
|
||||||
|
|
||||||
/** One bit of 'entropy' used to generate a salt for the company passwords. */
|
/** One bit of 'entropy' used to generate a salt for the company passwords. */
|
||||||
static uint32 _password_game_seed;
|
static uint32 _company_password_game_seed;
|
||||||
/** The other bit of 'entropy' used to generate a salt for the company passwords. */
|
/** One bit of 'entropy' used to generate a salt for the server passwords. */
|
||||||
|
static uint32 _server_password_game_seed;
|
||||||
|
/** One bit of 'entropy' used to generate a salt for the rcon passwords. */
|
||||||
|
static uint32 _rcon_password_game_seed;
|
||||||
|
/** One bit of 'entropy' used to generate a salt for the settings passwords. */
|
||||||
|
static uint32 _settings_password_game_seed;
|
||||||
|
/** The other bit of 'entropy' used to generate a salt for the company, server, rcon, and settings passwords. */
|
||||||
static char _password_server_id[NETWORK_SERVER_ID_LENGTH];
|
static char _password_server_id[NETWORK_SERVER_ID_LENGTH];
|
||||||
|
|
||||||
/** Maximum number of companies of the currently joined server. */
|
/** Maximum number of companies of the currently joined server. */
|
||||||
@@ -392,7 +436,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendNewGRFsOk()
|
|||||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendGamePassword(const char *password)
|
NetworkRecvStatus ClientNetworkGameSocketHandler::SendGamePassword(const char *password)
|
||||||
{
|
{
|
||||||
Packet *p = new Packet(PACKET_CLIENT_GAME_PASSWORD);
|
Packet *p = new Packet(PACKET_CLIENT_GAME_PASSWORD);
|
||||||
p->Send_string(password);
|
p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _server_password_game_seed));
|
||||||
my_client->SendPacket(p);
|
my_client->SendPacket(p);
|
||||||
return NETWORK_RECV_STATUS_OKAY;
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
}
|
}
|
||||||
@@ -404,7 +448,19 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendGamePassword(const char *p
|
|||||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendCompanyPassword(const char *password)
|
NetworkRecvStatus ClientNetworkGameSocketHandler::SendCompanyPassword(const char *password)
|
||||||
{
|
{
|
||||||
Packet *p = new Packet(PACKET_CLIENT_COMPANY_PASSWORD);
|
Packet *p = new Packet(PACKET_CLIENT_COMPANY_PASSWORD);
|
||||||
p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _password_game_seed));
|
p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _company_password_game_seed));
|
||||||
|
my_client->SendPacket(p);
|
||||||
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the game password as requested.
|
||||||
|
* @param password The game password.
|
||||||
|
*/
|
||||||
|
NetworkRecvStatus ClientNetworkGameSocketHandler::SendSettingsPassword(const char *password)
|
||||||
|
{
|
||||||
|
Packet *p = new Packet(PACKET_CLIENT_SETTINGS_PASSWORD);
|
||||||
|
p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _settings_password_game_seed));
|
||||||
my_client->SendPacket(p);
|
my_client->SendPacket(p);
|
||||||
return NETWORK_RECV_STATUS_OKAY;
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
}
|
}
|
||||||
@@ -502,7 +558,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendSetPassword(const char *pa
|
|||||||
{
|
{
|
||||||
Packet *p = new Packet(PACKET_CLIENT_SET_PASSWORD);
|
Packet *p = new Packet(PACKET_CLIENT_SET_PASSWORD);
|
||||||
|
|
||||||
p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _password_game_seed));
|
p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _company_password_game_seed));
|
||||||
my_client->SendPacket(p);
|
my_client->SendPacket(p);
|
||||||
return NETWORK_RECV_STATUS_OKAY;
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
}
|
}
|
||||||
@@ -539,7 +595,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendQuit()
|
|||||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendRCon(const char *pass, const char *command)
|
NetworkRecvStatus ClientNetworkGameSocketHandler::SendRCon(const char *pass, const char *command)
|
||||||
{
|
{
|
||||||
Packet *p = new Packet(PACKET_CLIENT_RCON);
|
Packet *p = new Packet(PACKET_CLIENT_RCON);
|
||||||
p->Send_string(pass);
|
p->Send_string(GenerateCompanyPasswordHash(pass, _password_server_id, _rcon_password_game_seed));
|
||||||
p->Send_string(command);
|
p->Send_string(command);
|
||||||
my_client->SendPacket(p);
|
my_client->SendPacket(p);
|
||||||
return NETWORK_RECV_STATUS_OKAY;
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
@@ -554,7 +610,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendMove(CompanyID company, co
|
|||||||
{
|
{
|
||||||
Packet *p = new Packet(PACKET_CLIENT_MOVE);
|
Packet *p = new Packet(PACKET_CLIENT_MOVE);
|
||||||
p->Send_uint8(company);
|
p->Send_uint8(company);
|
||||||
p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _password_game_seed));
|
p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _company_password_game_seed));
|
||||||
my_client->SendPacket(p);
|
my_client->SendPacket(p);
|
||||||
return NETWORK_RECV_STATUS_OKAY;
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
}
|
}
|
||||||
@@ -771,6 +827,10 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_NEED_GAME_PASSW
|
|||||||
if (this->status < STATUS_JOIN || this->status >= STATUS_AUTH_GAME) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
if (this->status < STATUS_JOIN || this->status >= STATUS_AUTH_GAME) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||||
this->status = STATUS_AUTH_GAME;
|
this->status = STATUS_AUTH_GAME;
|
||||||
|
|
||||||
|
_server_password_game_seed = p->Recv_uint32();
|
||||||
|
p->Recv_string(_password_server_id, sizeof(_password_server_id));
|
||||||
|
if (this->HasClientQuit()) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||||
|
|
||||||
const char *password = _network_join_server_password;
|
const char *password = _network_join_server_password;
|
||||||
if (!StrEmpty(password)) {
|
if (!StrEmpty(password)) {
|
||||||
return SendGamePassword(password);
|
return SendGamePassword(password);
|
||||||
@@ -786,7 +846,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_NEED_COMPANY_PA
|
|||||||
if (this->status < STATUS_JOIN || this->status >= STATUS_AUTH_COMPANY) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
if (this->status < STATUS_JOIN || this->status >= STATUS_AUTH_COMPANY) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||||
this->status = STATUS_AUTH_COMPANY;
|
this->status = STATUS_AUTH_COMPANY;
|
||||||
|
|
||||||
_password_game_seed = p->Recv_uint32();
|
_company_password_game_seed = p->Recv_uint32();
|
||||||
p->Recv_string(_password_server_id, sizeof(_password_server_id));
|
p->Recv_string(_password_server_id, sizeof(_password_server_id));
|
||||||
if (this->HasClientQuit()) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
if (this->HasClientQuit()) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||||
|
|
||||||
@@ -808,7 +868,10 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_WELCOME(Packet
|
|||||||
_network_own_client_id = (ClientID)p->Recv_uint32();
|
_network_own_client_id = (ClientID)p->Recv_uint32();
|
||||||
|
|
||||||
/* Initialize the password hash salting variables, even if they were previously. */
|
/* Initialize the password hash salting variables, even if they were previously. */
|
||||||
_password_game_seed = p->Recv_uint32();
|
_company_password_game_seed = p->Recv_uint32();
|
||||||
|
_server_password_game_seed = p->Recv_uint32();
|
||||||
|
_rcon_password_game_seed = p->Recv_uint32();
|
||||||
|
_settings_password_game_seed = p->Recv_uint32();
|
||||||
p->Recv_string(_password_server_id, sizeof(_password_server_id));
|
p->Recv_string(_password_server_id, sizeof(_password_server_id));
|
||||||
|
|
||||||
/* Start receiving the map */
|
/* Start receiving the map */
|
||||||
@@ -932,6 +995,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_DONE(Packet
|
|||||||
|
|
||||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_FRAME(Packet *p)
|
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_FRAME(Packet *p)
|
||||||
{
|
{
|
||||||
|
if (this->status == STATUS_CLOSING) return NETWORK_RECV_STATUS_OKAY;
|
||||||
if (this->status != STATUS_ACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
if (this->status != STATUS_ACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||||
|
|
||||||
_frame_counter_server = p->Recv_uint32();
|
_frame_counter_server = p->Recv_uint32();
|
||||||
@@ -945,6 +1009,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_FRAME(Packet *p
|
|||||||
#ifdef NETWORK_SEND_DOUBLE_SEED
|
#ifdef NETWORK_SEND_DOUBLE_SEED
|
||||||
_sync_seed_2 = p->Recv_uint32();
|
_sync_seed_2 = p->Recv_uint32();
|
||||||
#endif
|
#endif
|
||||||
|
_sync_state_checksum = p->Recv_uint64();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
/* Receive the token. */
|
/* Receive the token. */
|
||||||
@@ -965,6 +1030,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_FRAME(Packet *p
|
|||||||
|
|
||||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_SYNC(Packet *p)
|
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_SYNC(Packet *p)
|
||||||
{
|
{
|
||||||
|
if (this->status == STATUS_CLOSING) return NETWORK_RECV_STATUS_OKAY;
|
||||||
if (this->status != STATUS_ACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
if (this->status != STATUS_ACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||||
|
|
||||||
_sync_frame = p->Recv_uint32();
|
_sync_frame = p->Recv_uint32();
|
||||||
@@ -972,12 +1038,14 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_SYNC(Packet *p)
|
|||||||
#ifdef NETWORK_SEND_DOUBLE_SEED
|
#ifdef NETWORK_SEND_DOUBLE_SEED
|
||||||
_sync_seed_2 = p->Recv_uint32();
|
_sync_seed_2 = p->Recv_uint32();
|
||||||
#endif
|
#endif
|
||||||
|
_sync_state_checksum = p->Recv_uint64();
|
||||||
|
|
||||||
return NETWORK_RECV_STATUS_OKAY;
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_COMMAND(Packet *p)
|
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_COMMAND(Packet *p)
|
||||||
{
|
{
|
||||||
|
if (this->status == STATUS_CLOSING) return NETWORK_RECV_STATUS_OKAY;
|
||||||
if (this->status != STATUS_ACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
if (this->status != STATUS_ACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||||
|
|
||||||
CommandPacket cp;
|
CommandPacket cp;
|
||||||
@@ -997,6 +1065,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_COMMAND(Packet
|
|||||||
|
|
||||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CHAT(Packet *p)
|
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CHAT(Packet *p)
|
||||||
{
|
{
|
||||||
|
if (this->status == STATUS_CLOSING) return NETWORK_RECV_STATUS_OKAY;
|
||||||
if (this->status != STATUS_ACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
if (this->status != STATUS_ACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||||
|
|
||||||
char name[NETWORK_NAME_LENGTH], msg[NETWORK_CHAT_LENGTH];
|
char name[NETWORK_NAME_LENGTH], msg[NETWORK_CHAT_LENGTH];
|
||||||
@@ -1054,6 +1123,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_ERROR_QUIT(Pack
|
|||||||
if (this->status < STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
if (this->status < STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||||
|
|
||||||
ClientID client_id = (ClientID)p->Recv_uint32();
|
ClientID client_id = (ClientID)p->Recv_uint32();
|
||||||
|
if (client_id == _network_own_client_id) return NETWORK_RECV_STATUS_OKAY; // do not try to clear our own client info
|
||||||
|
|
||||||
NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id);
|
NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id);
|
||||||
if (ci != nullptr) {
|
if (ci != nullptr) {
|
||||||
@@ -1066,6 +1136,15 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_ERROR_QUIT(Pack
|
|||||||
return NETWORK_RECV_STATUS_OKAY;
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_DESYNC_LOG(Packet *p)
|
||||||
|
{
|
||||||
|
uint size = p->Recv_uint16();
|
||||||
|
this->server_desync_log.resize(this->server_desync_log.size() + size);
|
||||||
|
p->Recv_binary(const_cast<char *>(this->server_desync_log.data() + this->server_desync_log.size() - size), size);
|
||||||
|
DEBUG(net, 2, "Received %u bytes of server desync log", size);
|
||||||
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_QUIT(Packet *p)
|
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_QUIT(Packet *p)
|
||||||
{
|
{
|
||||||
if (this->status < STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
if (this->status < STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||||
@@ -1195,6 +1274,17 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_COMPANY_UPDATE(
|
|||||||
return NETWORK_RECV_STATUS_OKAY;
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_SETTINGS_ACCESS(Packet *p)
|
||||||
|
{
|
||||||
|
if (this->status < STATUS_ACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||||
|
|
||||||
|
_network_settings_access = p->Recv_bool();
|
||||||
|
|
||||||
|
ReInitAllWindows();
|
||||||
|
|
||||||
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check the connection's state, i.e. is the connection still up?
|
* Check the connection's state, i.e. is the connection still up?
|
||||||
*/
|
*/
|
||||||
@@ -1249,6 +1339,16 @@ void NetworkClientSendRcon(const char *password, const char *command)
|
|||||||
MyClient::SendRCon(password, command);
|
MyClient::SendRCon(password, command);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send settings password.
|
||||||
|
* @param password The password.
|
||||||
|
* @param command The command to execute.
|
||||||
|
*/
|
||||||
|
void NetworkClientSendSettingsPassword(const char *password)
|
||||||
|
{
|
||||||
|
MyClient::SendSettingsPassword(password);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify the server of this client wanting to be moved to another company.
|
* Notify the server of this client wanting to be moved to another company.
|
||||||
* @param company_id id of the company the client wishes to be moved to.
|
* @param company_id id of the company the client wishes to be moved to.
|
||||||
|
@@ -32,11 +32,16 @@ private:
|
|||||||
STATUS_MAP_WAIT, ///< The client is waiting as someone else is downloading the map.
|
STATUS_MAP_WAIT, ///< The client is waiting as someone else is downloading the map.
|
||||||
STATUS_MAP, ///< The client is downloading the map.
|
STATUS_MAP, ///< The client is downloading the map.
|
||||||
STATUS_ACTIVE, ///< The client is active within in the game.
|
STATUS_ACTIVE, ///< The client is active within in the game.
|
||||||
|
STATUS_CLOSING, ///< The client connection is in the process of being closed.
|
||||||
STATUS_END, ///< Must ALWAYS be on the end of this list!! (period)
|
STATUS_END, ///< Must ALWAYS be on the end of this list!! (period)
|
||||||
};
|
};
|
||||||
|
|
||||||
ServerStatus status; ///< Status of the connection with the server.
|
ServerStatus status; ///< Status of the connection with the server.
|
||||||
|
|
||||||
|
FILE *desync_log_file = nullptr;
|
||||||
|
std::string server_desync_log;
|
||||||
|
bool emergency_save_done = false;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend void NetworkExecuteLocalCommandQueue();
|
friend void NetworkExecuteLocalCommandQueue();
|
||||||
friend void NetworkClose(bool close_admins);
|
friend void NetworkClose(bool close_admins);
|
||||||
@@ -49,6 +54,7 @@ protected:
|
|||||||
NetworkRecvStatus Receive_SERVER_CLIENT_INFO(Packet *p) override;
|
NetworkRecvStatus Receive_SERVER_CLIENT_INFO(Packet *p) override;
|
||||||
NetworkRecvStatus Receive_SERVER_NEED_GAME_PASSWORD(Packet *p) override;
|
NetworkRecvStatus Receive_SERVER_NEED_GAME_PASSWORD(Packet *p) override;
|
||||||
NetworkRecvStatus Receive_SERVER_NEED_COMPANY_PASSWORD(Packet *p) override;
|
NetworkRecvStatus Receive_SERVER_NEED_COMPANY_PASSWORD(Packet *p) override;
|
||||||
|
NetworkRecvStatus Receive_SERVER_SETTINGS_ACCESS(Packet *p) override;
|
||||||
NetworkRecvStatus Receive_SERVER_WELCOME(Packet *p) override;
|
NetworkRecvStatus Receive_SERVER_WELCOME(Packet *p) override;
|
||||||
NetworkRecvStatus Receive_SERVER_WAIT(Packet *p) override;
|
NetworkRecvStatus Receive_SERVER_WAIT(Packet *p) override;
|
||||||
NetworkRecvStatus Receive_SERVER_MAP_BEGIN(Packet *p) override;
|
NetworkRecvStatus Receive_SERVER_MAP_BEGIN(Packet *p) override;
|
||||||
@@ -62,6 +68,7 @@ protected:
|
|||||||
NetworkRecvStatus Receive_SERVER_CHAT(Packet *p) override;
|
NetworkRecvStatus Receive_SERVER_CHAT(Packet *p) override;
|
||||||
NetworkRecvStatus Receive_SERVER_QUIT(Packet *p) override;
|
NetworkRecvStatus Receive_SERVER_QUIT(Packet *p) override;
|
||||||
NetworkRecvStatus Receive_SERVER_ERROR_QUIT(Packet *p) override;
|
NetworkRecvStatus Receive_SERVER_ERROR_QUIT(Packet *p) override;
|
||||||
|
NetworkRecvStatus Receive_SERVER_DESYNC_LOG(Packet *p) override;
|
||||||
NetworkRecvStatus Receive_SERVER_SHUTDOWN(Packet *p) override;
|
NetworkRecvStatus Receive_SERVER_SHUTDOWN(Packet *p) override;
|
||||||
NetworkRecvStatus Receive_SERVER_NEWGAME(Packet *p) override;
|
NetworkRecvStatus Receive_SERVER_NEWGAME(Packet *p) override;
|
||||||
NetworkRecvStatus Receive_SERVER_RCON(Packet *p) override;
|
NetworkRecvStatus Receive_SERVER_RCON(Packet *p) override;
|
||||||
@@ -92,6 +99,7 @@ public:
|
|||||||
|
|
||||||
static NetworkRecvStatus SendGamePassword(const char *password);
|
static NetworkRecvStatus SendGamePassword(const char *password);
|
||||||
static NetworkRecvStatus SendCompanyPassword(const char *password);
|
static NetworkRecvStatus SendCompanyPassword(const char *password);
|
||||||
|
static NetworkRecvStatus SendSettingsPassword(const char *password);
|
||||||
|
|
||||||
static NetworkRecvStatus SendChat(NetworkAction action, DestType type, int dest, const char *msg, NetworkTextMessageData data);
|
static NetworkRecvStatus SendChat(NetworkAction action, DestType type, int dest, const char *msg, NetworkTextMessageData data);
|
||||||
static NetworkRecvStatus SendSetPassword(const char *password);
|
static NetworkRecvStatus SendSetPassword(const char *password);
|
||||||
@@ -104,6 +112,8 @@ public:
|
|||||||
static void Send();
|
static void Send();
|
||||||
static bool Receive();
|
static bool Receive();
|
||||||
static bool GameLoop();
|
static bool GameLoop();
|
||||||
|
|
||||||
|
static bool EmergencySavePossible();
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Helper to make the code look somewhat nicer. */
|
/** Helper to make the code look somewhat nicer. */
|
||||||
|
@@ -54,6 +54,7 @@ void NetworkClientsToSpectators(CompanyID cid);
|
|||||||
void NetworkClientConnectGame(NetworkAddress address, CompanyID join_as, const char *join_server_password = nullptr, const char *join_company_password = nullptr);
|
void NetworkClientConnectGame(NetworkAddress address, CompanyID join_as, const char *join_server_password = nullptr, const char *join_company_password = nullptr);
|
||||||
void NetworkClientRequestMove(CompanyID company, const char *pass = "");
|
void NetworkClientRequestMove(CompanyID company, const char *pass = "");
|
||||||
void NetworkClientSendRcon(const char *password, const char *command);
|
void NetworkClientSendRcon(const char *password, const char *command);
|
||||||
|
void NetworkClientSendSettingsPassword(const char *password);
|
||||||
void NetworkClientSendChat(NetworkAction action, DestType type, int dest, const char *msg, NetworkTextMessageData data = NetworkTextMessageData());
|
void NetworkClientSendChat(NetworkAction action, DestType type, int dest, const char *msg, NetworkTextMessageData data = NetworkTextMessageData());
|
||||||
bool NetworkClientPreferTeamChat(const NetworkClientInfo *cio);
|
bool NetworkClientPreferTeamChat(const NetworkClientInfo *cio);
|
||||||
bool NetworkCompanyIsPassworded(CompanyID company_id);
|
bool NetworkCompanyIsPassworded(CompanyID company_id);
|
||||||
|
@@ -118,6 +118,7 @@ extern uint32 _sync_seed_1;
|
|||||||
#ifdef NETWORK_SEND_DOUBLE_SEED
|
#ifdef NETWORK_SEND_DOUBLE_SEED
|
||||||
extern uint32 _sync_seed_2;
|
extern uint32 _sync_seed_2;
|
||||||
#endif
|
#endif
|
||||||
|
extern uint64 _sync_state_checksum;
|
||||||
extern uint32 _sync_frame;
|
extern uint32 _sync_frame;
|
||||||
extern bool _network_first_time;
|
extern bool _network_first_time;
|
||||||
/* Vars needed for the join-GUI */
|
/* Vars needed for the join-GUI */
|
||||||
|
@@ -216,6 +216,9 @@ ServerNetworkGameSocketHandler::ServerNetworkGameSocketHandler(SOCKET s) : Netwo
|
|||||||
this->status = STATUS_INACTIVE;
|
this->status = STATUS_INACTIVE;
|
||||||
this->client_id = _network_client_id++;
|
this->client_id = _network_client_id++;
|
||||||
this->receive_limit = _settings_client.network.bytes_per_frame_burst;
|
this->receive_limit = _settings_client.network.bytes_per_frame_burst;
|
||||||
|
this->server_hash_bits = InteractiveRandom();
|
||||||
|
this->rcon_hash_bits = InteractiveRandom();
|
||||||
|
this->settings_hash_bits = InteractiveRandom();
|
||||||
|
|
||||||
/* The Socket and Info pools need to be the same in size. After all,
|
/* The Socket and Info pools need to be the same in size. After all,
|
||||||
* each Socket will be associated with at most one Info object. As
|
* each Socket will be associated with at most one Info object. As
|
||||||
@@ -320,7 +323,14 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::CloseConnection(NetworkRecvSta
|
|||||||
NetworkClientSocket *cs;
|
NetworkClientSocket *cs;
|
||||||
FOR_ALL_CLIENT_SOCKETS(cs) {
|
FOR_ALL_CLIENT_SOCKETS(cs) {
|
||||||
if (cs->writable) {
|
if (cs->writable) {
|
||||||
if (cs->SendPackets() != SPS_CLOSED && cs->status == STATUS_MAP) {
|
if (cs->status == STATUS_CLOSE_PENDING) {
|
||||||
|
SendPacketsState send_state = cs->SendPackets(true);
|
||||||
|
if (send_state == SPS_CLOSED) {
|
||||||
|
cs->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST);
|
||||||
|
} else if (send_state != SPS_PARTLY_SENT && send_state != SPS_NONE_SENT) {
|
||||||
|
ShutdownSocket(cs->sock, true, false, 2);
|
||||||
|
}
|
||||||
|
} else if (cs->SendPackets() != SPS_CLOSED && cs->status == STATUS_MAP) {
|
||||||
/* This client is in the middle of a map-send, call the function for that */
|
/* This client is in the middle of a map-send, call the function for that */
|
||||||
cs->SendMap();
|
cs->SendMap();
|
||||||
}
|
}
|
||||||
@@ -461,6 +471,20 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendError(NetworkErrorCode err
|
|||||||
return this->CloseConnection(NETWORK_RECV_STATUS_SERVER_ERROR);
|
return this->CloseConnection(NETWORK_RECV_STATUS_SERVER_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NetworkRecvStatus ServerNetworkGameSocketHandler::SendDesyncLog(const std::string &log)
|
||||||
|
{
|
||||||
|
for (size_t offset = 0; offset < log.size();) {
|
||||||
|
Packet *p = new Packet(PACKET_SERVER_DESYNC_LOG);
|
||||||
|
size_t size = min<size_t>(log.size() - offset, SHRT_MAX - 2 - p->size);
|
||||||
|
p->Send_uint16(size);
|
||||||
|
p->Send_binary(log.data() + offset, size);
|
||||||
|
this->SendPacket(p);
|
||||||
|
|
||||||
|
offset += size;
|
||||||
|
}
|
||||||
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
/** Send the check for the NewGRFs. */
|
/** Send the check for the NewGRFs. */
|
||||||
NetworkRecvStatus ServerNetworkGameSocketHandler::SendNewGRFCheck()
|
NetworkRecvStatus ServerNetworkGameSocketHandler::SendNewGRFCheck()
|
||||||
{
|
{
|
||||||
@@ -492,6 +516,8 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendNeedGamePassword()
|
|||||||
this->last_frame = this->last_frame_server = _frame_counter;
|
this->last_frame = this->last_frame_server = _frame_counter;
|
||||||
|
|
||||||
Packet *p = new Packet(PACKET_SERVER_NEED_GAME_PASSWORD);
|
Packet *p = new Packet(PACKET_SERVER_NEED_GAME_PASSWORD);
|
||||||
|
p->Send_uint32(_settings_game.game_creation.generation_seed ^ this->server_hash_bits);
|
||||||
|
p->Send_string(_settings_client.network.network_id);
|
||||||
this->SendPacket(p);
|
this->SendPacket(p);
|
||||||
return NETWORK_RECV_STATUS_OKAY;
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
}
|
}
|
||||||
@@ -531,6 +557,9 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendWelcome()
|
|||||||
p = new Packet(PACKET_SERVER_WELCOME);
|
p = new Packet(PACKET_SERVER_WELCOME);
|
||||||
p->Send_uint32(this->client_id);
|
p->Send_uint32(this->client_id);
|
||||||
p->Send_uint32(_settings_game.game_creation.generation_seed);
|
p->Send_uint32(_settings_game.game_creation.generation_seed);
|
||||||
|
p->Send_uint32(_settings_game.game_creation.generation_seed ^ this->server_hash_bits);
|
||||||
|
p->Send_uint32(_settings_game.game_creation.generation_seed ^ this->rcon_hash_bits);
|
||||||
|
p->Send_uint32(_settings_game.game_creation.generation_seed ^ this->settings_hash_bits);
|
||||||
p->Send_string(_settings_client.network.network_id);
|
p->Send_string(_settings_client.network.network_id);
|
||||||
this->SendPacket(p);
|
this->SendPacket(p);
|
||||||
|
|
||||||
@@ -689,6 +718,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendFrame()
|
|||||||
#ifdef NETWORK_SEND_DOUBLE_SEED
|
#ifdef NETWORK_SEND_DOUBLE_SEED
|
||||||
p->Send_uint32(_sync_seed_2);
|
p->Send_uint32(_sync_seed_2);
|
||||||
#endif
|
#endif
|
||||||
|
p->Send_uint64(_sync_state_checksum);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* If token equals 0, we need to make a new token and send that. */
|
/* If token equals 0, we need to make a new token and send that. */
|
||||||
@@ -711,6 +741,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendSync()
|
|||||||
#ifdef NETWORK_SEND_DOUBLE_SEED
|
#ifdef NETWORK_SEND_DOUBLE_SEED
|
||||||
p->Send_uint32(_sync_seed_2);
|
p->Send_uint32(_sync_seed_2);
|
||||||
#endif
|
#endif
|
||||||
|
p->Send_uint64(_sync_state_checksum);
|
||||||
this->SendPacket(p);
|
this->SendPacket(p);
|
||||||
return NETWORK_RECV_STATUS_OKAY;
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
}
|
}
|
||||||
@@ -852,6 +883,15 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendConfigUpdate()
|
|||||||
return NETWORK_RECV_STATUS_OKAY;
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NetworkRecvStatus ServerNetworkGameSocketHandler::SendSettingsAccessUpdate(bool ok)
|
||||||
|
{
|
||||||
|
Packet *p = new Packet(PACKET_SERVER_SETTINGS_ACCESS);
|
||||||
|
p->Send_bool(ok);
|
||||||
|
this->SendPacket(p);
|
||||||
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********
|
/***********
|
||||||
* Receiving functions
|
* Receiving functions
|
||||||
* DEF_SERVER_RECEIVE_COMMAND has parameter: NetworkClientSocket *cs, Packet *p
|
* DEF_SERVER_RECEIVE_COMMAND has parameter: NetworkClientSocket *cs, Packet *p
|
||||||
@@ -970,7 +1010,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_GAME_PASSWORD(P
|
|||||||
|
|
||||||
/* Check game password. Allow joining if we cleared the password meanwhile */
|
/* Check game password. Allow joining if we cleared the password meanwhile */
|
||||||
if (!StrEmpty(_settings_client.network.server_password) &&
|
if (!StrEmpty(_settings_client.network.server_password) &&
|
||||||
strcmp(password, _settings_client.network.server_password) != 0) {
|
strcmp(password, GenerateCompanyPasswordHash(_settings_client.network.server_password, _settings_client.network.network_id, _settings_game.game_creation.generation_seed ^ this->server_hash_bits)) != 0) {
|
||||||
/* Password is invalid */
|
/* Password is invalid */
|
||||||
return this->SendError(NETWORK_ERROR_WRONG_PASSWORD);
|
return this->SendError(NETWORK_ERROR_WRONG_PASSWORD);
|
||||||
}
|
}
|
||||||
@@ -1006,6 +1046,29 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_COMPANY_PASSWOR
|
|||||||
return this->SendWelcome();
|
return this->SendWelcome();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_SETTINGS_PASSWORD(Packet *p)
|
||||||
|
{
|
||||||
|
if (this->status != STATUS_ACTIVE) {
|
||||||
|
/* Illegal call, return error and ignore the packet */
|
||||||
|
return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
char password[NETWORK_PASSWORD_LENGTH];
|
||||||
|
p->Recv_string(password, sizeof(password));
|
||||||
|
|
||||||
|
/* Check settings password. Deny if no password is set */
|
||||||
|
if (StrEmpty(_settings_client.network.settings_password) ||
|
||||||
|
strcmp(password, GenerateCompanyPasswordHash(_settings_client.network.settings_password, _settings_client.network.network_id, _settings_game.game_creation.generation_seed ^ this->settings_hash_bits)) != 0) {
|
||||||
|
DEBUG(net, 0, "[settings-ctrl] wrong password from client-id %d", this->client_id);
|
||||||
|
this->settings_authed = false;
|
||||||
|
} else {
|
||||||
|
DEBUG(net, 0, "[settings-ctrl] client-id %d", this->client_id);
|
||||||
|
this->settings_authed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this->SendSettingsAccessUpdate(this->settings_authed);
|
||||||
|
}
|
||||||
|
|
||||||
NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_GETMAP(Packet *p)
|
NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_GETMAP(Packet *p)
|
||||||
{
|
{
|
||||||
NetworkClientSocket *new_cs;
|
NetworkClientSocket *new_cs;
|
||||||
@@ -1100,12 +1163,12 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_COMMAND(Packet
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if ((GetCommandFlags(cp.cmd) & CMD_SERVER) && ci->client_id != CLIENT_ID_SERVER) {
|
if ((GetCommandFlags(cp.cmd) & CMD_SERVER) && ci->client_id != CLIENT_ID_SERVER && !this->settings_authed) {
|
||||||
IConsolePrintF(CC_ERROR, "WARNING: server only command from: client %d (IP: %s), kicking...", ci->client_id, this->GetClientIP());
|
IConsolePrintF(CC_ERROR, "WARNING: server only command from: client %d (IP: %s), kicking...", ci->client_id, this->GetClientIP());
|
||||||
return this->SendError(NETWORK_ERROR_KICKED);
|
return this->SendError(NETWORK_ERROR_KICKED);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((GetCommandFlags(cp.cmd) & CMD_SPECTATOR) == 0 && !Company::IsValidID(cp.company) && ci->client_id != CLIENT_ID_SERVER) {
|
if ((GetCommandFlags(cp.cmd) & CMD_SPECTATOR) == 0 && !Company::IsValidID(cp.company) && ci->client_id != CLIENT_ID_SERVER && !this->settings_authed) {
|
||||||
IConsolePrintF(CC_ERROR, "WARNING: spectator issuing command from client %d (IP: %s), kicking...", ci->client_id, this->GetClientIP());
|
IConsolePrintF(CC_ERROR, "WARNING: spectator issuing command from client %d (IP: %s), kicking...", ci->client_id, this->GetClientIP());
|
||||||
return this->SendError(NETWORK_ERROR_KICKED);
|
return this->SendError(NETWORK_ERROR_KICKED);
|
||||||
}
|
}
|
||||||
@@ -1115,7 +1178,8 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_COMMAND(Packet
|
|||||||
* to match the company in the packet. If it doesn't, the client has done
|
* to match the company in the packet. If it doesn't, the client has done
|
||||||
* something pretty naughty (or a bug), and will be kicked
|
* something pretty naughty (or a bug), and will be kicked
|
||||||
*/
|
*/
|
||||||
if (!(cp.cmd == CMD_COMPANY_CTRL && cp.p1 == 0 && ci->client_playas == COMPANY_NEW_COMPANY) && ci->client_playas != cp.company) {
|
if (!(cp.cmd == CMD_COMPANY_CTRL && cp.p1 == 0 && ci->client_playas == COMPANY_NEW_COMPANY) && ci->client_playas != cp.company &&
|
||||||
|
!((GetCommandFlags(cp.cmd) & CMD_SERVER) && this->settings_authed)) {
|
||||||
IConsolePrintF(CC_ERROR, "WARNING: client %d (IP: %s) tried to execute a command as company %d, kicking...",
|
IConsolePrintF(CC_ERROR, "WARNING: client %d (IP: %s) tried to execute a command as company %d, kicking...",
|
||||||
ci->client_playas + 1, this->GetClientIP(), cp.company + 1);
|
ci->client_playas + 1, this->GetClientIP(), cp.company + 1);
|
||||||
return this->SendError(NETWORK_ERROR_COMPANY_MISMATCH);
|
return this->SendError(NETWORK_ERROR_COMPANY_MISMATCH);
|
||||||
@@ -1171,12 +1235,22 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_ERROR(Packet *p
|
|||||||
NetworkAdminClientError(this->client_id, errorno);
|
NetworkAdminClientError(this->client_id, errorno);
|
||||||
|
|
||||||
if (errorno == NETWORK_ERROR_DESYNC) {
|
if (errorno == NETWORK_ERROR_DESYNC) {
|
||||||
CrashLog::DesyncCrashLog(&(this->desync_log), nullptr);
|
std::string server_desync_log;
|
||||||
|
CrashLog::DesyncCrashLog(&(this->desync_log), &server_desync_log, DesyncExtraInfo{});
|
||||||
|
this->SendDesyncLog(server_desync_log);
|
||||||
|
|
||||||
|
// decrease the sync frequency for this point onwards
|
||||||
|
_settings_client.network.sync_freq = min<uint16>(_settings_client.network.sync_freq, 16);
|
||||||
|
|
||||||
// have the server and all clients run some sanity checks
|
// have the server and all clients run some sanity checks
|
||||||
NetworkSendCommand(0, 0, 0, CMD_DESYNC_CHECK, nullptr, nullptr, _local_company, 0);
|
NetworkSendCommand(0, 0, 0, CMD_DESYNC_CHECK, nullptr, nullptr, _local_company, 0);
|
||||||
}
|
|
||||||
|
|
||||||
|
SendPacketsState send_state = this->SendPackets(true);
|
||||||
|
if (send_state != SPS_CLOSED) {
|
||||||
|
this->status = STATUS_CLOSE_PENDING;
|
||||||
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
|
}
|
||||||
|
}
|
||||||
return this->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST);
|
return this->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1476,7 +1550,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_RCON(Packet *p)
|
|||||||
p->Recv_string(pass, sizeof(pass));
|
p->Recv_string(pass, sizeof(pass));
|
||||||
p->Recv_string(command, sizeof(command));
|
p->Recv_string(command, sizeof(command));
|
||||||
|
|
||||||
if (strcmp(pass, _settings_client.network.rcon_password) != 0) {
|
if (strcmp(pass, GenerateCompanyPasswordHash(_settings_client.network.rcon_password, _settings_client.network.network_id, _settings_game.game_creation.generation_seed ^ this->rcon_hash_bits)) != 0) {
|
||||||
DEBUG(net, 0, "[rcon] wrong password from client-id %d", this->client_id);
|
DEBUG(net, 0, "[rcon] wrong password from client-id %d", this->client_id);
|
||||||
return NETWORK_RECV_STATUS_OKAY;
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
}
|
}
|
||||||
@@ -1910,6 +1984,7 @@ void NetworkServer_Tick(bool send_frame)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case NetworkClientSocket::STATUS_MAP_WAIT:
|
case NetworkClientSocket::STATUS_MAP_WAIT:
|
||||||
|
case NetworkClientSocket::STATUS_CLOSE_PENDING:
|
||||||
/* This is an internal state where we do not wait
|
/* This is an internal state where we do not wait
|
||||||
* on the client to move to a different state. */
|
* on the client to move to a different state. */
|
||||||
break;
|
break;
|
||||||
@@ -1919,7 +1994,7 @@ void NetworkServer_Tick(bool send_frame)
|
|||||||
NOT_REACHED();
|
NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cs->status >= NetworkClientSocket::STATUS_PRE_ACTIVE) {
|
if (cs->status >= NetworkClientSocket::STATUS_PRE_ACTIVE && cs->status != NetworkClientSocket::STATUS_CLOSE_PENDING) {
|
||||||
/* Check if we can send command, and if we have anything in the queue */
|
/* Check if we can send command, and if we have anything in the queue */
|
||||||
NetworkHandleCommandQueue(cs);
|
NetworkHandleCommandQueue(cs);
|
||||||
|
|
||||||
@@ -1981,7 +2056,8 @@ void NetworkServerShowStatusToConsole()
|
|||||||
"loading map",
|
"loading map",
|
||||||
"map done",
|
"map done",
|
||||||
"ready",
|
"ready",
|
||||||
"active"
|
"active",
|
||||||
|
"close pending"
|
||||||
};
|
};
|
||||||
assert_compile(lengthof(stat_str) == NetworkClientSocket::STATUS_END);
|
assert_compile(lengthof(stat_str) == NetworkClientSocket::STATUS_END);
|
||||||
|
|
||||||
|
@@ -29,6 +29,7 @@ protected:
|
|||||||
NetworkRecvStatus Receive_CLIENT_COMPANY_INFO(Packet *p) override;
|
NetworkRecvStatus Receive_CLIENT_COMPANY_INFO(Packet *p) override;
|
||||||
NetworkRecvStatus Receive_CLIENT_GAME_PASSWORD(Packet *p) override;
|
NetworkRecvStatus Receive_CLIENT_GAME_PASSWORD(Packet *p) override;
|
||||||
NetworkRecvStatus Receive_CLIENT_COMPANY_PASSWORD(Packet *p) override;
|
NetworkRecvStatus Receive_CLIENT_COMPANY_PASSWORD(Packet *p) override;
|
||||||
|
NetworkRecvStatus Receive_CLIENT_SETTINGS_PASSWORD(Packet *p) override;
|
||||||
NetworkRecvStatus Receive_CLIENT_GETMAP(Packet *p) override;
|
NetworkRecvStatus Receive_CLIENT_GETMAP(Packet *p) override;
|
||||||
NetworkRecvStatus Receive_CLIENT_MAP_OK(Packet *p) override;
|
NetworkRecvStatus Receive_CLIENT_MAP_OK(Packet *p) override;
|
||||||
NetworkRecvStatus Receive_CLIENT_ACK(Packet *p) override;
|
NetworkRecvStatus Receive_CLIENT_ACK(Packet *p) override;
|
||||||
@@ -63,6 +64,7 @@ public:
|
|||||||
STATUS_DONE_MAP, ///< The client has downloaded the map.
|
STATUS_DONE_MAP, ///< The client has downloaded the map.
|
||||||
STATUS_PRE_ACTIVE, ///< The client is catching up the delayed frames.
|
STATUS_PRE_ACTIVE, ///< The client is catching up the delayed frames.
|
||||||
STATUS_ACTIVE, ///< The client is active within in the game.
|
STATUS_ACTIVE, ///< The client is active within in the game.
|
||||||
|
STATUS_CLOSE_PENDING, ///< The client connection is pending closure.
|
||||||
STATUS_END, ///< Must ALWAYS be on the end of this list!! (period).
|
STATUS_END, ///< Must ALWAYS be on the end of this list!! (period).
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -72,6 +74,10 @@ public:
|
|||||||
ClientStatus status; ///< Status of this client
|
ClientStatus status; ///< Status of this client
|
||||||
CommandQueue outgoing_queue; ///< The command-queue awaiting delivery
|
CommandQueue outgoing_queue; ///< The command-queue awaiting delivery
|
||||||
int receive_limit; ///< Amount of bytes that we can receive at this moment
|
int receive_limit; ///< Amount of bytes that we can receive at this moment
|
||||||
|
uint32 server_hash_bits; ///< Server password hash entropy bits
|
||||||
|
uint32 rcon_hash_bits; ///< Rcon password hash entropy bits
|
||||||
|
uint32 settings_hash_bits; ///< Settings password hash entropy bits
|
||||||
|
bool settings_authed = false;///< Authorised to control all game settings
|
||||||
|
|
||||||
struct PacketWriter *savegame; ///< Writer used to write the savegame.
|
struct PacketWriter *savegame; ///< Writer used to write the savegame.
|
||||||
NetworkAddress client_address; ///< IP-address of the client (so he can be banned)
|
NetworkAddress client_address; ///< IP-address of the client (so he can be banned)
|
||||||
@@ -95,6 +101,7 @@ public:
|
|||||||
|
|
||||||
NetworkRecvStatus SendClientInfo(NetworkClientInfo *ci);
|
NetworkRecvStatus SendClientInfo(NetworkClientInfo *ci);
|
||||||
NetworkRecvStatus SendError(NetworkErrorCode error);
|
NetworkRecvStatus SendError(NetworkErrorCode error);
|
||||||
|
NetworkRecvStatus SendDesyncLog(const std::string &log);
|
||||||
NetworkRecvStatus SendChat(NetworkAction action, ClientID client_id, bool self_send, const char *msg, NetworkTextMessageData data);
|
NetworkRecvStatus SendChat(NetworkAction action, ClientID client_id, bool self_send, const char *msg, NetworkTextMessageData data);
|
||||||
NetworkRecvStatus SendJoin(ClientID client_id);
|
NetworkRecvStatus SendJoin(ClientID client_id);
|
||||||
NetworkRecvStatus SendFrame();
|
NetworkRecvStatus SendFrame();
|
||||||
@@ -102,6 +109,7 @@ public:
|
|||||||
NetworkRecvStatus SendCommand(const CommandPacket *cp);
|
NetworkRecvStatus SendCommand(const CommandPacket *cp);
|
||||||
NetworkRecvStatus SendCompanyUpdate();
|
NetworkRecvStatus SendCompanyUpdate();
|
||||||
NetworkRecvStatus SendConfigUpdate();
|
NetworkRecvStatus SendConfigUpdate();
|
||||||
|
NetworkRecvStatus SendSettingsAccessUpdate(bool ok);
|
||||||
|
|
||||||
static void Send();
|
static void Send();
|
||||||
static void AcceptConnection(SOCKET s, const NetworkAddress &address);
|
static void AcceptConnection(SOCKET s, const NetworkAddress &address);
|
||||||
|
@@ -719,9 +719,12 @@ bool NewHouseTileLoop(TileIndex tile)
|
|||||||
|
|
||||||
/* Check callback 21, which determines if a house should be destroyed. */
|
/* Check callback 21, which determines if a house should be destroyed. */
|
||||||
if (HasBit(hs->callback_mask, CBM_HOUSE_DESTRUCTION)) {
|
if (HasBit(hs->callback_mask, CBM_HOUSE_DESTRUCTION)) {
|
||||||
uint16 callback_res = GetHouseCallback(CBID_HOUSE_DESTRUCTION, 0, 0, GetHouseType(tile), Town::GetByTile(tile), tile);
|
Town *t = Town::GetByTile(tile);
|
||||||
|
uint16 callback_res = GetHouseCallback(CBID_HOUSE_DESTRUCTION, 0, 0, GetHouseType(tile), t, tile);
|
||||||
if (callback_res != CALLBACK_FAILED && Convert8bitBooleanCallback(hs->grf_prop.grffile, CBID_HOUSE_DESTRUCTION, callback_res)) {
|
if (callback_res != CALLBACK_FAILED && Convert8bitBooleanCallback(hs->grf_prop.grffile, CBID_HOUSE_DESTRUCTION, callback_res)) {
|
||||||
ClearTownHouse(Town::GetByTile(tile), tile);
|
ClearTownHouse(t, tile);
|
||||||
|
extern void RemoveNearbyStations(Town *t);
|
||||||
|
RemoveNearbyStations(t);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -78,6 +78,7 @@
|
|||||||
#include "string_func_extra.h"
|
#include "string_func_extra.h"
|
||||||
#include "industry.h"
|
#include "industry.h"
|
||||||
#include "cargopacket.h"
|
#include "cargopacket.h"
|
||||||
|
#include "core/checksum_func.hpp"
|
||||||
|
|
||||||
#include "linkgraph/linkgraphschedule.h"
|
#include "linkgraph/linkgraphschedule.h"
|
||||||
#include "tracerestrict.h"
|
#include "tracerestrict.h"
|
||||||
@@ -104,6 +105,8 @@ GameEventFlags _game_events_overall;
|
|||||||
|
|
||||||
time_t _game_load_time;
|
time_t _game_load_time;
|
||||||
|
|
||||||
|
SimpleChecksum64 _state_checksum;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Error handling for fatal user errors.
|
* Error handling for fatal user errors.
|
||||||
* @param s the string to print.
|
* @param s the string to print.
|
||||||
@@ -404,6 +407,7 @@ static void ShutdownGame()
|
|||||||
*/
|
*/
|
||||||
static void LoadIntroGame(bool load_newgrfs = true)
|
static void LoadIntroGame(bool load_newgrfs = true)
|
||||||
{
|
{
|
||||||
|
UnshowCriticalError();
|
||||||
Window *v;
|
Window *v;
|
||||||
FOR_ALL_WINDOWS_FROM_FRONT(v) delete v;
|
FOR_ALL_WINDOWS_FROM_FRONT(v) delete v;
|
||||||
|
|
||||||
@@ -1636,6 +1640,12 @@ void CheckCaches(bool force_check, std::function<void(const char *)> log)
|
|||||||
|
|
||||||
if (!CargoPacket::ValidateDeferredCargoPayments()) CCLOG("Cargo packets deferred payments validation failed");
|
if (!CargoPacket::ValidateDeferredCargoPayments()) CCLOG("Cargo packets deferred payments validation failed");
|
||||||
|
|
||||||
|
if (_order_destination_refcount_map_valid) {
|
||||||
|
btree::btree_map<uint32, uint32> saved_order_destination_refcount_map = std::move(_order_destination_refcount_map);
|
||||||
|
IntialiseOrderDestinationRefcountMap();
|
||||||
|
if (saved_order_destination_refcount_map != _order_destination_refcount_map) CCLOG("Order destination refcount map mismatch");
|
||||||
|
}
|
||||||
|
|
||||||
#undef CCLOG
|
#undef CCLOG
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1745,6 +1755,11 @@ void StateGameLoop()
|
|||||||
CallWindowGameTickEvent();
|
CallWindowGameTickEvent();
|
||||||
NewsLoop();
|
NewsLoop();
|
||||||
cur_company.Restore();
|
cur_company.Restore();
|
||||||
|
|
||||||
|
Company *c;
|
||||||
|
FOR_ALL_COMPANIES(c) {
|
||||||
|
UpdateStateChecksum(c->money);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(IsLocalCompany());
|
assert(IsLocalCompany());
|
||||||
|
@@ -63,6 +63,7 @@ void IntialiseOrderDestinationRefcountMap()
|
|||||||
ClearOrderDestinationRefcountMap();
|
ClearOrderDestinationRefcountMap();
|
||||||
const Vehicle *v;
|
const Vehicle *v;
|
||||||
FOR_ALL_VEHICLES(v) {
|
FOR_ALL_VEHICLES(v) {
|
||||||
|
if (v != v->FirstShared()) continue;
|
||||||
const Order *order;
|
const Order *order;
|
||||||
FOR_VEHICLE_ORDERS(v, order) {
|
FOR_VEHICLE_ORDERS(v, order) {
|
||||||
if (order->IsType(OT_GOTO_STATION) || order->IsType(OT_GOTO_WAYPOINT) || order->IsType(OT_IMPLICIT)) {
|
if (order->IsType(OT_GOTO_STATION) || order->IsType(OT_GOTO_WAYPOINT) || order->IsType(OT_IMPLICIT)) {
|
||||||
|
@@ -516,8 +516,8 @@ void CDECL HandleCrash(int signum, siginfo_t *si, void *context)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ void CrashLog::DesyncCrashLog(const std::string *log_in, std::string *log_out)
|
/* static */ void CrashLog::DesyncCrashLog(const std::string *log_in, std::string *log_out, const DesyncExtraInfo &info)
|
||||||
{
|
{
|
||||||
CrashLogOSX log(CrashLogOSX::DesyncTag{});
|
CrashLogOSX log(CrashLogOSX::DesyncTag{});
|
||||||
log.MakeDesyncCrashLog(log_in, log_out);
|
log.MakeDesyncCrashLog(log_in, log_out, info);
|
||||||
}
|
}
|
||||||
|
@@ -620,8 +620,8 @@ static void CDECL HandleCrash(int signum)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ void CrashLog::DesyncCrashLog(const std::string *log_in, std::string *log_out)
|
/* static */ void CrashLog::DesyncCrashLog(const std::string *log_in, std::string *log_out, const DesyncExtraInfo &info)
|
||||||
{
|
{
|
||||||
CrashLogUnix log(CrashLogUnix::DesyncTag{});
|
CrashLogUnix log(CrashLogUnix::DesyncTag{});
|
||||||
log.MakeDesyncCrashLog(log_in, log_out);
|
log.MakeDesyncCrashLog(log_in, log_out, info);
|
||||||
}
|
}
|
||||||
|
@@ -612,10 +612,10 @@ static void CDECL CustomAbort(int signal)
|
|||||||
SetUnhandledExceptionFilter(ExceptionHandler);
|
SetUnhandledExceptionFilter(ExceptionHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ void CrashLog::DesyncCrashLog(const std::string *log_in, std::string *log_out)
|
/* static */ void CrashLog::DesyncCrashLog(const std::string *log_in, std::string *log_out, const DesyncExtraInfo &info)
|
||||||
{
|
{
|
||||||
CrashLogWindows log(nullptr);
|
CrashLogWindows log(nullptr);
|
||||||
log.MakeDesyncCrashLog(log_in, log_out);
|
log.MakeDesyncCrashLog(log_in, log_out, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The crash log GUI */
|
/* The crash log GUI */
|
||||||
|
@@ -39,6 +39,7 @@
|
|||||||
#include "framerate_type.h"
|
#include "framerate_type.h"
|
||||||
#include "scope_info.h"
|
#include "scope_info.h"
|
||||||
#include "string_func.h"
|
#include "string_func.h"
|
||||||
|
#include "core/checksum_func.hpp"
|
||||||
|
|
||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
|
|
||||||
@@ -1067,6 +1068,7 @@ static Trackdir RoadFindPathToDest(RoadVehicle *v, TileIndex tile, DiagDirection
|
|||||||
|
|
||||||
default: NOT_REACHED();
|
default: NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
UpdateStateChecksum((((uint64) v->index) << 32) | (path_found << 16) | best_track);
|
||||||
v->HandlePathfindingResult(path_found);
|
v->HandlePathfindingResult(path_found);
|
||||||
|
|
||||||
found_best_track:;
|
found_best_track:;
|
||||||
@@ -1746,6 +1748,8 @@ Money RoadVehicle::GetRunningCost() const
|
|||||||
|
|
||||||
bool RoadVehicle::Tick()
|
bool RoadVehicle::Tick()
|
||||||
{
|
{
|
||||||
|
UpdateStateChecksum((((uint64) this->x_pos) << 32) | this->y_pos);
|
||||||
|
UpdateStateChecksum((((uint64) this->state) << 32) | this->frame);
|
||||||
if (this->IsFrontEngine()) {
|
if (this->IsFrontEngine()) {
|
||||||
if (!(this->IsRoadVehicleStopped())) this->running_ticks++;
|
if (!(this->IsRoadVehicleStopped())) this->running_ticks++;
|
||||||
return RoadVehController(this);
|
return RoadVehController(this);
|
||||||
|
@@ -108,6 +108,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
|
|||||||
{ XSLFI_GAME_EVENTS, XSCF_NULL, 1, 1, "game_events", nullptr, nullptr, nullptr },
|
{ XSLFI_GAME_EVENTS, XSCF_NULL, 1, 1, "game_events", nullptr, nullptr, nullptr },
|
||||||
{ XSLFI_ROAD_LAYOUT_CHANGE_CTR, XSCF_NULL, 1, 1, "road_layout_change_ctr", nullptr, nullptr, nullptr },
|
{ XSLFI_ROAD_LAYOUT_CHANGE_CTR, XSCF_NULL, 1, 1, "road_layout_change_ctr", nullptr, nullptr, nullptr },
|
||||||
{ XSLFI_TOWN_CARGO_MATRIX, XSCF_NULL, 1, 1, "town_cargo_matrix", nullptr, nullptr, nullptr },
|
{ XSLFI_TOWN_CARGO_MATRIX, XSCF_NULL, 1, 1, "town_cargo_matrix", nullptr, nullptr, nullptr },
|
||||||
|
{ XSLFI_STATE_CHECKSUM, XSCF_NULL, 1, 1, "state_checksum", nullptr, nullptr, nullptr },
|
||||||
{ XSLFI_DEBUG, XSCF_IGNORABLE_ALL, 1, 1, "debug", nullptr, nullptr, "DBGL" },
|
{ XSLFI_DEBUG, XSCF_IGNORABLE_ALL, 1, 1, "debug", nullptr, nullptr, "DBGL" },
|
||||||
{ XSLFI_NULL, XSCF_NULL, 0, 0, nullptr, nullptr, nullptr, nullptr },// This is the end marker
|
{ XSLFI_NULL, XSCF_NULL, 0, 0, nullptr, nullptr, nullptr, nullptr },// This is the end marker
|
||||||
};
|
};
|
||||||
|
@@ -75,6 +75,7 @@ enum SlXvFeatureIndex {
|
|||||||
XSLFI_GAME_EVENTS, ///< Game event flags
|
XSLFI_GAME_EVENTS, ///< Game event flags
|
||||||
XSLFI_ROAD_LAYOUT_CHANGE_CTR, ///< Road layout change counter
|
XSLFI_ROAD_LAYOUT_CHANGE_CTR, ///< Road layout change counter
|
||||||
XSLFI_TOWN_CARGO_MATRIX, ///< Town cargo matrix savegame format changes
|
XSLFI_TOWN_CARGO_MATRIX, ///< Town cargo matrix savegame format changes
|
||||||
|
XSLFI_STATE_CHECKSUM, ///< State checksum
|
||||||
XSLFI_DEBUG, ///< Debugging info
|
XSLFI_DEBUG, ///< Debugging info
|
||||||
|
|
||||||
XSLFI_RIFF_HEADER_60_BIT, ///< Size field in RIFF chunk header is 60 bit
|
XSLFI_RIFF_HEADER_60_BIT, ///< Size field in RIFF chunk header is 60 bit
|
||||||
|
@@ -19,6 +19,7 @@
|
|||||||
#include "../core/random_func.hpp"
|
#include "../core/random_func.hpp"
|
||||||
#include "../fios.h"
|
#include "../fios.h"
|
||||||
#include "../road_type.h"
|
#include "../road_type.h"
|
||||||
|
#include "../core/checksum_func.hpp"
|
||||||
|
|
||||||
#include "saveload.h"
|
#include "saveload.h"
|
||||||
|
|
||||||
@@ -86,6 +87,7 @@ static const SaveLoadGlobVarList _date_desc[] = {
|
|||||||
SLE_CONDNULL(2, SL_MIN_VERSION, SLV_120),
|
SLE_CONDNULL(2, SL_MIN_VERSION, SLV_120),
|
||||||
SLEG_VAR(_random.state[0], SLE_UINT32),
|
SLEG_VAR(_random.state[0], SLE_UINT32),
|
||||||
SLEG_VAR(_random.state[1], SLE_UINT32),
|
SLEG_VAR(_random.state[1], SLE_UINT32),
|
||||||
|
SLEG_CONDVAR_X(_state_checksum.state, SLE_UINT64, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_STATE_CHECKSUM)),
|
||||||
SLE_CONDNULL(1, SL_MIN_VERSION, SLV_10),
|
SLE_CONDNULL(1, SL_MIN_VERSION, SLV_10),
|
||||||
SLE_CONDNULL(4, SLV_10, SLV_120),
|
SLE_CONDNULL(4, SLV_10, SLV_120),
|
||||||
SLEG_VAR(_cur_company_tick_index, SLE_FILE_U8 | SLE_VAR_U32),
|
SLEG_VAR(_cur_company_tick_index, SLE_FILE_U8 | SLE_VAR_U32),
|
||||||
@@ -114,6 +116,7 @@ static const SaveLoadGlobVarList _date_check_desc[] = {
|
|||||||
SLE_CONDNULL(2, SL_MIN_VERSION, SLV_120),
|
SLE_CONDNULL(2, SL_MIN_VERSION, SLV_120),
|
||||||
SLE_NULL(4), // _random.state[0]
|
SLE_NULL(4), // _random.state[0]
|
||||||
SLE_NULL(4), // _random.state[1]
|
SLE_NULL(4), // _random.state[1]
|
||||||
|
SLE_CONDNULL_X(8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_STATE_CHECKSUM)), // _state_checksum.state
|
||||||
SLE_CONDNULL(1, SL_MIN_VERSION, SLV_10),
|
SLE_CONDNULL(1, SL_MIN_VERSION, SLV_10),
|
||||||
SLE_CONDNULL(4, SLV_10, SLV_120),
|
SLE_CONDNULL(4, SLV_10, SLV_120),
|
||||||
SLE_NULL(1), // _cur_company_tick_index
|
SLE_NULL(1), // _cur_company_tick_index
|
||||||
|
@@ -336,13 +336,12 @@ static void Load_TOWN()
|
|||||||
uint arr_len = t->cargo_accepted.area.w / AcceptanceMatrix::GRID * t->cargo_accepted.area.h / AcceptanceMatrix::GRID;
|
uint arr_len = t->cargo_accepted.area.w / AcceptanceMatrix::GRID * t->cargo_accepted.area.h / AcceptanceMatrix::GRID;
|
||||||
t->cargo_accepted.data = MallocT<CargoTypes>(arr_len);
|
t->cargo_accepted.data = MallocT<CargoTypes>(arr_len);
|
||||||
SlArray(t->cargo_accepted.data, arr_len, SLE_UINT64);
|
SlArray(t->cargo_accepted.data, arr_len, SLE_UINT64);
|
||||||
|
}
|
||||||
/* Rebuild total cargo acceptance. */
|
/* Rebuild total cargo acceptance. */
|
||||||
UpdateTownCargoTotal(t);
|
UpdateTownCargoTotal(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/** Fix pointers when loading town data. */
|
/** Fix pointers when loading town data. */
|
||||||
static void Ptrs_TOWN()
|
static void Ptrs_TOWN()
|
||||||
|
@@ -810,7 +810,7 @@ void IniSaveWindowSettings(IniFile *ini, const char *grpname, void *desc)
|
|||||||
*/
|
*/
|
||||||
bool SettingDesc::IsEditable(bool do_command) const
|
bool SettingDesc::IsEditable(bool do_command) const
|
||||||
{
|
{
|
||||||
if (!do_command && !(this->save.conv & SLF_NO_NETWORK_SYNC) && _networking && !_network_server && !(this->desc.flags & SGF_PER_COMPANY)) return false;
|
if (!do_command && !(this->save.conv & SLF_NO_NETWORK_SYNC) && _networking && !(_network_server || _network_settings_access) && !(this->desc.flags & SGF_PER_COMPANY)) return false;
|
||||||
if ((this->desc.flags & SGF_NETWORK_ONLY) && !_networking && _game_mode != GM_MENU) return false;
|
if ((this->desc.flags & SGF_NETWORK_ONLY) && !_networking && _game_mode != GM_MENU) return false;
|
||||||
if ((this->desc.flags & SGF_NO_NETWORK) && _networking) return false;
|
if ((this->desc.flags & SGF_NO_NETWORK) && _networking) return false;
|
||||||
if ((this->desc.flags & SGF_NEWGAME_ONLY) &&
|
if ((this->desc.flags & SGF_NEWGAME_ONLY) &&
|
||||||
@@ -1264,7 +1264,7 @@ static bool MaxNoAIsChange(int32 i)
|
|||||||
{
|
{
|
||||||
if (GetGameSettings().difficulty.max_no_competitors != 0 &&
|
if (GetGameSettings().difficulty.max_no_competitors != 0 &&
|
||||||
AI::GetInfoList()->size() == 0 &&
|
AI::GetInfoList()->size() == 0 &&
|
||||||
(!_networking || _network_server)) {
|
(!_networking || (_network_server || _network_settings_access))) {
|
||||||
ShowErrorMessage(STR_WARNING_NO_SUITABLE_AI, INVALID_STRING_ID, WL_CRITICAL);
|
ShowErrorMessage(STR_WARNING_NO_SUITABLE_AI, INVALID_STRING_ID, WL_CRITICAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1499,6 +1499,15 @@ static bool UpdateRconPassword(int32 p1)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool UpdateSettingsPassword(int32 p1)
|
||||||
|
{
|
||||||
|
if (strcmp(_settings_client.network.settings_password, "*") == 0) {
|
||||||
|
_settings_client.network.settings_password[0] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool UpdateClientConfigValues(int32 p1)
|
static bool UpdateClientConfigValues(int32 p1)
|
||||||
{
|
{
|
||||||
if (_network_server) NetworkServerSendConfigUpdate();
|
if (_network_server) NetworkServerSendConfigUpdate();
|
||||||
@@ -2116,7 +2125,7 @@ bool SetSettingValue(uint index, int32 value, bool force_newgame)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* send non-company-based settings over the network */
|
/* send non-company-based settings over the network */
|
||||||
if (!_networking || (_networking && _network_server)) {
|
if (!_networking || (_networking && (_network_server || _network_settings_access))) {
|
||||||
return DoCommandP(0, index, value, CMD_CHANGE_SETTING);
|
return DoCommandP(0, index, value, CMD_CHANGE_SETTING);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -2276,7 +2285,7 @@ void IConsoleSetSetting(const char *name, const char *value, bool force_newgame)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
if (_network_server) {
|
if ((_network_server || _network_settings_access)) {
|
||||||
IConsoleError("This command/variable is not available during network games.");
|
IConsoleError("This command/variable is not available during network games.");
|
||||||
} else {
|
} else {
|
||||||
IConsoleError("This command/variable is only available to a network server.");
|
IConsoleError("This command/variable is only available to a network server.");
|
||||||
|
@@ -228,7 +228,7 @@ struct GameOptionsWindow : Window {
|
|||||||
/* You can only change the drive side if you are in the menu or ingame with
|
/* You can only change the drive side if you are in the menu or ingame with
|
||||||
* no vehicles present. In a networking game only the server can change it */
|
* no vehicles present. In a networking game only the server can change it */
|
||||||
extern bool RoadVehiclesAreBuilt();
|
extern bool RoadVehiclesAreBuilt();
|
||||||
if ((_game_mode != GM_MENU && RoadVehiclesAreBuilt()) || (_networking && !_network_server)) {
|
if ((_game_mode != GM_MENU && RoadVehiclesAreBuilt()) || (_networking && !(_network_server || _network_settings_access))) {
|
||||||
disabled = ~(1 << this->opt->vehicle.road_side); // disable the other value
|
disabled = ~(1 << this->opt->vehicle.road_side); // disable the other value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -303,6 +303,7 @@ struct NetworkSettings {
|
|||||||
char server_password[NETWORK_PASSWORD_LENGTH]; ///< password for joining this server
|
char server_password[NETWORK_PASSWORD_LENGTH]; ///< password for joining this server
|
||||||
char rcon_password[NETWORK_PASSWORD_LENGTH]; ///< password for rconsole (server side)
|
char rcon_password[NETWORK_PASSWORD_LENGTH]; ///< password for rconsole (server side)
|
||||||
char admin_password[NETWORK_PASSWORD_LENGTH]; ///< password for the admin network
|
char admin_password[NETWORK_PASSWORD_LENGTH]; ///< password for the admin network
|
||||||
|
char settings_password[NETWORK_PASSWORD_LENGTH]; ///< password for game settings (server side)
|
||||||
bool server_advertise; ///< advertise the server to the masterserver
|
bool server_advertise; ///< advertise the server to the masterserver
|
||||||
uint8 lan_internet; ///< search on the LAN or internet for servers
|
uint8 lan_internet; ///< search on the LAN or internet for servers
|
||||||
char client_name[NETWORK_CLIENT_NAME_LENGTH]; ///< name of the player (as client)
|
char client_name[NETWORK_CLIENT_NAME_LENGTH]; ///< name of the player (as client)
|
||||||
|
@@ -37,6 +37,7 @@
|
|||||||
#include "framerate_type.h"
|
#include "framerate_type.h"
|
||||||
#include "industry.h"
|
#include "industry.h"
|
||||||
#include "industry_map.h"
|
#include "industry_map.h"
|
||||||
|
#include "core/checksum_func.hpp"
|
||||||
|
|
||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
|
|
||||||
@@ -524,6 +525,7 @@ static Track ChooseShipTrack(Ship *v, TileIndex tile, DiagDirection enterdir, Tr
|
|||||||
default: NOT_REACHED();
|
default: NOT_REACHED();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
UpdateStateChecksum((((uint64) v->index) << 32) | (path_found << 16) | track);
|
||||||
|
|
||||||
v->HandlePathfindingResult(path_found);
|
v->HandlePathfindingResult(path_found);
|
||||||
return track;
|
return track;
|
||||||
@@ -972,6 +974,7 @@ reverse_direction:
|
|||||||
|
|
||||||
bool Ship::Tick()
|
bool Ship::Tick()
|
||||||
{
|
{
|
||||||
|
UpdateStateChecksum((((uint64) this->x_pos) << 32) | this->y_pos);
|
||||||
if (!(this->vehstatus & VS_STOPPED)) this->running_ticks++;
|
if (!(this->vehstatus & VS_STOPPED)) this->running_ticks++;
|
||||||
|
|
||||||
ShipController(this);
|
ShipController(this);
|
||||||
|
@@ -616,6 +616,13 @@ class NIHTown : public NIHelper {
|
|||||||
SetDParam(0, t->cargo_accepted_total);
|
SetDParam(0, t->cargo_accepted_total);
|
||||||
b = GetString(b, STR_JUST_CARGO_LIST, lastof(buffer));
|
b = GetString(b, STR_JUST_CARGO_LIST, lastof(buffer));
|
||||||
print(buffer);
|
print(buffer);
|
||||||
|
|
||||||
|
seprintf(buffer, lastof(buffer), " Nearby stations: %u", (uint) t->stations_near.size());
|
||||||
|
print(buffer);
|
||||||
|
for (const Station *st : t->stations_near) {
|
||||||
|
seprintf(buffer, lastof(buffer), " %u: %s", st->index, st->GetCachedName());
|
||||||
|
print(buffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -53,6 +53,7 @@ static bool EnableSingleVehSharedOrderGuiChanged(int32 p1);
|
|||||||
static bool UpdateClientName(int32 p1);
|
static bool UpdateClientName(int32 p1);
|
||||||
static bool UpdateServerPassword(int32 p1);
|
static bool UpdateServerPassword(int32 p1);
|
||||||
static bool UpdateRconPassword(int32 p1);
|
static bool UpdateRconPassword(int32 p1);
|
||||||
|
static bool UpdateSettingsPassword(int32 p1);
|
||||||
static bool UpdateClientConfigValues(int32 p1);
|
static bool UpdateClientConfigValues(int32 p1);
|
||||||
static bool CheckSharingRail(int32 p1);
|
static bool CheckSharingRail(int32 p1);
|
||||||
static bool CheckSharingRoad(int32 p1);
|
static bool CheckSharingRoad(int32 p1);
|
||||||
@@ -5093,6 +5094,15 @@ guiflags = SGF_NETWORK_ONLY
|
|||||||
def = nullptr
|
def = nullptr
|
||||||
cat = SC_BASIC
|
cat = SC_BASIC
|
||||||
|
|
||||||
|
[SDTC_STR]
|
||||||
|
var = network.settings_password
|
||||||
|
type = SLE_STRB
|
||||||
|
flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
|
||||||
|
guiflags = SGF_NETWORK_ONLY
|
||||||
|
def = nullptr
|
||||||
|
proc = UpdateSettingsPassword
|
||||||
|
cat = SC_EXPERT
|
||||||
|
|
||||||
[SDTC_STR]
|
[SDTC_STR]
|
||||||
var = network.default_company_pass
|
var = network.default_company_pass
|
||||||
type = SLE_STRB
|
type = SLE_STRB
|
||||||
|
@@ -277,7 +277,7 @@ static CallBackFunction SelectSignTool()
|
|||||||
|
|
||||||
static CallBackFunction ToolbarPauseClick(Window *w)
|
static CallBackFunction ToolbarPauseClick(Window *w)
|
||||||
{
|
{
|
||||||
if (_networking && !_network_server) return CBF_NONE; // only server can pause the game
|
if (_networking && !(_network_server || _network_settings_access)) return CBF_NONE; // only server can pause the game
|
||||||
|
|
||||||
if (DoCommandP(0, PM_PAUSED_NORMAL, _pause_mode == PM_UNPAUSED, CMD_PAUSE)) {
|
if (DoCommandP(0, PM_PAUSED_NORMAL, _pause_mode == PM_UNPAUSED, CMD_PAUSE)) {
|
||||||
if (_settings_client.sound.confirm) SndPlayFx(SND_15_BEEP);
|
if (_settings_client.sound.confirm) SndPlayFx(SND_15_BEEP);
|
||||||
@@ -2061,7 +2061,6 @@ struct MainToolbarWindow : Window {
|
|||||||
|
|
||||||
_last_started_action = CBF_NONE;
|
_last_started_action = CBF_NONE;
|
||||||
CLRBITS(this->flags, WF_WHITE_BORDER);
|
CLRBITS(this->flags, WF_WHITE_BORDER);
|
||||||
this->SetWidgetDisabledState(WID_TN_PAUSE, _networking && !_network_server); // if not server, disable pause button
|
|
||||||
this->SetWidgetDisabledState(WID_TN_FAST_FORWARD, _networking); // if networking, disable fast-forward button
|
this->SetWidgetDisabledState(WID_TN_FAST_FORWARD, _networking); // if networking, disable fast-forward button
|
||||||
PositionMainToolbar(this);
|
PositionMainToolbar(this);
|
||||||
DoZoomInOutWindow(ZOOM_NONE, this);
|
DoZoomInOutWindow(ZOOM_NONE, this);
|
||||||
@@ -2091,6 +2090,8 @@ struct MainToolbarWindow : Window {
|
|||||||
this->SetWidgetDisabledState(WID_TN_TRAMS, !CanBuildVehicleInfrastructure(VEH_ROAD, RTT_TRAM));
|
this->SetWidgetDisabledState(WID_TN_TRAMS, !CanBuildVehicleInfrastructure(VEH_ROAD, RTT_TRAM));
|
||||||
this->SetWidgetDisabledState(WID_TN_AIR, !CanBuildVehicleInfrastructure(VEH_AIRCRAFT));
|
this->SetWidgetDisabledState(WID_TN_AIR, !CanBuildVehicleInfrastructure(VEH_AIRCRAFT));
|
||||||
|
|
||||||
|
this->SetWidgetDisabledState(WID_TN_PAUSE, _networking && !(_network_server || _network_settings_access)); // if not server, disable pause button
|
||||||
|
|
||||||
this->DrawWidgets();
|
this->DrawWidgets();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -573,7 +573,7 @@ uint32 GetWorldPopulation()
|
|||||||
* Remove stations from nearby station list if a town is no longer in the catchment area of each.
|
* Remove stations from nearby station list if a town is no longer in the catchment area of each.
|
||||||
* @param t Town to work on
|
* @param t Town to work on
|
||||||
*/
|
*/
|
||||||
static void RemoveNearbyStations(Town *t)
|
void RemoveNearbyStations(Town *t)
|
||||||
{
|
{
|
||||||
for (StationList::iterator it = t->stations_near.begin(); it != t->stations_near.end(); /* incremented inside loop */) {
|
for (StationList::iterator it = t->stations_near.begin(); it != t->stations_near.end(); /* incremented inside loop */) {
|
||||||
const Station *st = *it;
|
const Station *st = *it;
|
||||||
@@ -1010,12 +1010,12 @@ void UpdateTownCargoes(Town *t)
|
|||||||
t->cargo_produced = 0;
|
t->cargo_produced = 0;
|
||||||
|
|
||||||
const TileArea &area = t->cargo_accepted.GetArea();
|
const TileArea &area = t->cargo_accepted.GetArea();
|
||||||
if (area.tile == INVALID_TILE) return;
|
if (area.tile != INVALID_TILE) {
|
||||||
|
|
||||||
/* Update acceptance for each grid square. */
|
/* Update acceptance for each grid square. */
|
||||||
TILE_AREA_LOOP_STEP(tile, area, AcceptanceMatrix::GRID) {
|
TILE_AREA_LOOP_STEP(tile, area, AcceptanceMatrix::GRID) {
|
||||||
UpdateTownCargoesSingleGridArea(t, tile, false);
|
UpdateTownCargoesSingleGridArea(t, tile, false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Update the total acceptance. */
|
/* Update the total acceptance. */
|
||||||
UpdateTownCargoTotal(t);
|
UpdateTownCargoTotal(t);
|
||||||
|
@@ -322,9 +322,6 @@ public:
|
|||||||
this->flags |= WF_DISABLE_VP_SCROLL;
|
this->flags |= WF_DISABLE_VP_SCROLL;
|
||||||
NWidgetViewport *nvp = this->GetWidget<NWidgetViewport>(WID_TV_VIEWPORT);
|
NWidgetViewport *nvp = this->GetWidget<NWidgetViewport>(WID_TV_VIEWPORT);
|
||||||
nvp->InitializeViewport(this, this->town->xy, ZOOM_LVL_NEWS);
|
nvp->InitializeViewport(this, this->town->xy, ZOOM_LVL_NEWS);
|
||||||
|
|
||||||
/* disable renaming town in network games if you are not the server */
|
|
||||||
this->SetWidgetDisabledState(WID_TV_CHANGE_NAME, _networking && !_network_server);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~TownViewWindow()
|
~TownViewWindow()
|
||||||
@@ -341,6 +338,7 @@ public:
|
|||||||
{
|
{
|
||||||
extern const Town *_viewport_highlight_town;
|
extern const Town *_viewport_highlight_town;
|
||||||
this->SetWidgetLoweredState(WID_TV_CATCHMENT, _viewport_highlight_town == this->town);
|
this->SetWidgetLoweredState(WID_TV_CATCHMENT, _viewport_highlight_town == this->town);
|
||||||
|
this->SetWidgetDisabledState(WID_TV_CHANGE_NAME, _networking && !(_network_server || _network_settings_access));
|
||||||
|
|
||||||
this->DrawWidgets();
|
this->DrawWidgets();
|
||||||
}
|
}
|
||||||
|
@@ -870,8 +870,8 @@ void SetTraceRestrictValueDefault(TraceRestrictItem &item, TraceRestrictValueTyp
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case TRVT_CARGO_ID:
|
case TRVT_CARGO_ID:
|
||||||
assert(_sorted_standard_cargo_specs_size > 0);
|
assert(_standard_cargo_mask != 0);
|
||||||
SetTraceRestrictValue(item, _sorted_cargo_specs[0]->Index());
|
SetTraceRestrictValue(item, FindFirstBit64(_standard_cargo_mask));
|
||||||
SetTraceRestrictAuxField(item, 0);
|
SetTraceRestrictAuxField(item, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@@ -43,6 +43,7 @@
|
|||||||
#include "engine_func.h"
|
#include "engine_func.h"
|
||||||
#include "bridge_signal_map.h"
|
#include "bridge_signal_map.h"
|
||||||
#include "scope_info.h"
|
#include "scope_info.h"
|
||||||
|
#include "core/checksum_func.hpp"
|
||||||
|
|
||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
#include "table/train_cmd.h"
|
#include "table/train_cmd.h"
|
||||||
@@ -1549,6 +1550,7 @@ CommandCost CmdMoveRailVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, u
|
|||||||
TraceRestrictRemoveVehicleFromAllSlots(src->index);
|
TraceRestrictRemoveVehicleFromAllSlots(src->index);
|
||||||
ClrBit(src->flags, VRF_HAVE_SLOT);
|
ClrBit(src->flags, VRF_HAVE_SLOT);
|
||||||
}
|
}
|
||||||
|
OrderBackup::ClearVehicle(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We weren't a front engine but are becoming one. So
|
/* We weren't a front engine but are becoming one. So
|
||||||
@@ -2175,6 +2177,53 @@ void ReverseTrainDirection(Train *v)
|
|||||||
/* Clear path reservation in front if train is not stuck. */
|
/* Clear path reservation in front if train is not stuck. */
|
||||||
if (!HasBit(v->flags, VRF_TRAIN_STUCK)) FreeTrainTrackReservation(v);
|
if (!HasBit(v->flags, VRF_TRAIN_STUCK)) FreeTrainTrackReservation(v);
|
||||||
|
|
||||||
|
std::vector<Train *> re_reserve_trains;
|
||||||
|
{
|
||||||
|
/* Temporarily clear and restore reservations to bidi tunnel/bridge entrances when reversing train inside,
|
||||||
|
* to avoid outgoing and incoming reservations becoming merged */
|
||||||
|
auto find_train_reservations = [&re_reserve_trains, &v](TileIndex tile) {
|
||||||
|
TrackBits reserved = GetAcrossTunnelBridgeReservationTrackBits(tile);
|
||||||
|
Track track;
|
||||||
|
while ((track = RemoveFirstTrack(&reserved)) != INVALID_TRACK) {
|
||||||
|
Train *res_train = GetTrainForReservation(tile, track);
|
||||||
|
if (res_train != nullptr && res_train != v) {
|
||||||
|
FreeTrainTrackReservation(res_train);
|
||||||
|
re_reserve_trains.push_back(res_train);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (IsTunnelBridgeWithSignalSimulation(v->tile) && IsTunnelBridgeSignalSimulationBidirectional(v->tile)) {
|
||||||
|
find_train_reservations(v->tile);
|
||||||
|
find_train_reservations(GetOtherTunnelBridgeEnd(v->tile));
|
||||||
|
}
|
||||||
|
Train *last = v->Last();
|
||||||
|
if (IsTunnelBridgeWithSignalSimulation(last->tile) && IsTunnelBridgeSignalSimulationBidirectional(last->tile)) {
|
||||||
|
find_train_reservations(last->tile);
|
||||||
|
find_train_reservations(GetOtherTunnelBridgeEnd(last->tile));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((v->track & TRACK_BIT_WORMHOLE) && IsTunnelBridgeWithSignalSimulation(v->tile)) {
|
||||||
|
/* Clear exit tile reservation if train was on approach to exit and had reserved it */
|
||||||
|
Axis axis = DiagDirToAxis(GetTunnelBridgeDirection(v->tile));
|
||||||
|
DiagDirection axial_dir = DirToDiagDirAlongAxis(v->direction, axis);
|
||||||
|
TileIndex next_tile = TileVirtXY(v->x_pos, v->y_pos) + TileOffsByDiagDir(axial_dir);
|
||||||
|
if (next_tile == v->tile || next_tile == GetOtherTunnelBridgeEnd(v->tile)) {
|
||||||
|
Trackdir exit_td = TrackEnterdirToTrackdir(FindFirstTrack(GetAcrossTunnelBridgeTrackBits(next_tile)), ReverseDiagDir(GetTunnelBridgeDirection(next_tile)));
|
||||||
|
CFollowTrackRail ft(GetTileOwner(next_tile), GetRailTypeInfo(v->railtype)->compatible_railtypes);
|
||||||
|
if (ft.Follow(next_tile, exit_td)) {
|
||||||
|
TrackdirBits reserved = ft.m_new_td_bits & TrackBitsToTrackdirBits(GetReservedTrackbits(ft.m_new_tile));
|
||||||
|
if (reserved == TRACKDIR_BIT_NONE) {
|
||||||
|
UnreserveAcrossRailTunnelBridge(next_tile);
|
||||||
|
MarkTileDirtyByTile(next_tile, ZOOM_LVL_DRAW_MAP);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
UnreserveAcrossRailTunnelBridge(next_tile);
|
||||||
|
MarkTileDirtyByTile(next_tile, ZOOM_LVL_DRAW_MAP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Check if we were approaching a rail/road-crossing */
|
/* Check if we were approaching a rail/road-crossing */
|
||||||
TileIndex crossing = TrainApproachingCrossingTile(v);
|
TileIndex crossing = TrainApproachingCrossingTile(v);
|
||||||
|
|
||||||
@@ -2214,6 +2263,10 @@ void ReverseTrainDirection(Train *v)
|
|||||||
crossing = TrainApproachingCrossingTile(v);
|
crossing = TrainApproachingCrossingTile(v);
|
||||||
if (crossing != INVALID_TILE) MaybeBarCrossingWithSound(crossing);
|
if (crossing != INVALID_TILE) MaybeBarCrossingWithSound(crossing);
|
||||||
|
|
||||||
|
for (uint i = 0; i < re_reserve_trains.size(); ++i) {
|
||||||
|
TryPathReserve(re_reserve_trains[i], true);
|
||||||
|
}
|
||||||
|
|
||||||
/* If we are inside a depot after reversing, don't bother with path reserving. */
|
/* If we are inside a depot after reversing, don't bother with path reserving. */
|
||||||
if (v->track == TRACK_BIT_DEPOT) {
|
if (v->track == TRACK_BIT_DEPOT) {
|
||||||
/* Can't be stuck here as inside a depot is always a safe tile. */
|
/* Can't be stuck here as inside a depot is always a safe tile. */
|
||||||
@@ -2724,6 +2777,9 @@ void FreeTrainTrackReservation(const Train *v, TileIndex origin, Trackdir orig_t
|
|||||||
/* Don't free reservation if it's not ours. */
|
/* Don't free reservation if it's not ours. */
|
||||||
if (TracksOverlap(GetReservedTrackbits(tile) | TrackToTrackBits(TrackdirToTrack(td)))) return;
|
if (TracksOverlap(GetReservedTrackbits(tile) | TrackToTrackBits(TrackdirToTrack(td)))) return;
|
||||||
|
|
||||||
|
/* Do not attempt to unreserve out of a signalled tunnel/bridge entrance, as this would unreserve the reservations of another train coming in */
|
||||||
|
if (IsTunnelBridgeWithSignalSimulation(tile) && TrackdirExitsTunnelBridge(tile, td) && IsTunnelBridgeSignalSimulationEntranceOnly(tile)) return;
|
||||||
|
|
||||||
CFollowTrackRail ft(v, GetRailTypeInfo(v->railtype)->compatible_railtypes);
|
CFollowTrackRail ft(v, GetRailTypeInfo(v->railtype)->compatible_railtypes);
|
||||||
while (ft.Follow(tile, td)) {
|
while (ft.Follow(tile, td)) {
|
||||||
tile = ft.m_new_tile;
|
tile = ft.m_new_tile;
|
||||||
@@ -3127,6 +3183,7 @@ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir,
|
|||||||
TileIndex new_tile = res_dest.tile;
|
TileIndex new_tile = res_dest.tile;
|
||||||
|
|
||||||
Track next_track = DoTrainPathfind(v, new_tile, dest_enterdir, tracks, path_found, do_track_reservation, &res_dest);
|
Track next_track = DoTrainPathfind(v, new_tile, dest_enterdir, tracks, path_found, do_track_reservation, &res_dest);
|
||||||
|
UpdateStateChecksum((((uint64) v->index) << 32) | (path_found << 16) | next_track);
|
||||||
if (new_tile == tile) best_track = next_track;
|
if (new_tile == tile) best_track = next_track;
|
||||||
v->HandlePathfindingResult(path_found);
|
v->HandlePathfindingResult(path_found);
|
||||||
}
|
}
|
||||||
@@ -4217,7 +4274,10 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
|||||||
}
|
}
|
||||||
if (v->Next() == nullptr) {
|
if (v->Next() == nullptr) {
|
||||||
if (v->tunnel_bridge_signal_num > 0 && distance == (TILE_SIZE * _settings_game.construction.simulated_wormhole_signals) - TILE_SIZE) HandleSignalBehindTrain(v, v->tunnel_bridge_signal_num - 2);
|
if (v->tunnel_bridge_signal_num > 0 && distance == (TILE_SIZE * _settings_game.construction.simulated_wormhole_signals) - TILE_SIZE) HandleSignalBehindTrain(v, v->tunnel_bridge_signal_num - 2);
|
||||||
if (old_tile == v->tile) {
|
DiagDirection tunnel_bridge_dir = GetTunnelBridgeDirection(v->tile);
|
||||||
|
Axis axis = DiagDirToAxis(tunnel_bridge_dir);
|
||||||
|
DiagDirection axial_dir = DirToDiagDirAlongAxis(v->direction, axis);
|
||||||
|
if (old_tile == ((axial_dir == tunnel_bridge_dir) ? v->tile : GetOtherTunnelBridgeEnd(v->tile))) {
|
||||||
/* We left ramp into wormhole. */
|
/* We left ramp into wormhole. */
|
||||||
v->x_pos = gp.x;
|
v->x_pos = gp.x;
|
||||||
v->y_pos = gp.y;
|
v->y_pos = gp.y;
|
||||||
@@ -4971,6 +5031,7 @@ Money Train::GetRunningCost() const
|
|||||||
*/
|
*/
|
||||||
bool Train::Tick()
|
bool Train::Tick()
|
||||||
{
|
{
|
||||||
|
UpdateStateChecksum((((uint64) this->x_pos) << 32) | (this->y_pos << 16) | this->track );
|
||||||
if (this->IsFrontEngine()) {
|
if (this->IsFrontEngine()) {
|
||||||
if (!(this->vehstatus & VS_STOPPED) || this->cur_speed > 0) this->running_ticks++;
|
if (!(this->vehstatus & VS_STOPPED) || this->cur_speed > 0) this->running_ticks++;
|
||||||
|
|
||||||
|
@@ -372,6 +372,18 @@ static inline bool IsTunnelBridgeSignalSimulationEntrance(TileIndex t)
|
|||||||
return HasBit(_m[t].m5, 5);
|
return HasBit(_m[t].m5, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this a tunnel/bridge entrance tile with signal only?
|
||||||
|
* @param t the tile that might be a tunnel/bridge.
|
||||||
|
* @pre IsTileType(t, MP_TUNNELBRIDGE)
|
||||||
|
* @return true if and only if this tile is a tunnel/bridge entrance only.
|
||||||
|
*/
|
||||||
|
static inline bool IsTunnelBridgeSignalSimulationEntranceOnly(TileIndex t)
|
||||||
|
{
|
||||||
|
assert_tile(IsTileType(t, MP_TUNNELBRIDGE), t);
|
||||||
|
return HasBit(_m[t].m5, 5) && !HasBit(_m[t].m5, 6);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is this a tunnel/bridge exit?
|
* Is this a tunnel/bridge exit?
|
||||||
* @param t the tile that might be a tunnel/bridge.
|
* @param t the tile that might be a tunnel/bridge.
|
||||||
|
Reference in New Issue
Block a user