mirror of https://github.com/OpenTTD/OpenTTD
(svn r23795) [1.1] -Backport from trunk:
- Fix: Make default timeouts for certain network states lower and configurable [FS#4955] (r23764) - Fix: Check whether a water tile is really empty when overbuilding it with an object [FS#4956] (r23763) - Fix: Missing locking causing crash in extreme case when being in the MP lobby [FS#4938] (r23752) - Fix: Clear the backed up orders of a removed station as well, otherwise one could create orders to a station that was never in the original backupped orders. For example a road vehicle trying to go to a buoy [FS#4876] (r23464) - Fix: Do not assume all industries that cut trees have tile (0,0) and wait until all tiles of an industry are completed before starting to cut trees (r23458)release/1.1
parent
15a9cae86e
commit
7faba28c31
|
@ -376,7 +376,7 @@ static bool DisasterTick_Ufo(DisasterVehicle *v)
|
||||||
static void DestructIndustry(Industry *i)
|
static void DestructIndustry(Industry *i)
|
||||||
{
|
{
|
||||||
for (TileIndex tile = 0; tile != MapSize(); tile++) {
|
for (TileIndex tile = 0; tile != MapSize(); tile++) {
|
||||||
if (IsTileType(tile, MP_INDUSTRY) && GetIndustryIndex(tile) == i->index) {
|
if (i->TileBelongsToIndustry(tile)) {
|
||||||
ResetIndustryConstructionStage(tile);
|
ResetIndustryConstructionStage(tile);
|
||||||
MarkTileDirtyByTile(tile);
|
MarkTileDirtyByTile(tile);
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,6 +79,16 @@ struct Industry : IndustryPool::PoolItem<&_industry_pool> {
|
||||||
|
|
||||||
void RecomputeProductionMultipliers();
|
void RecomputeProductionMultipliers();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a given tile belongs to this industry.
|
||||||
|
* @param tile The tile to check.
|
||||||
|
* @return True if the tils is part of this industry.
|
||||||
|
*/
|
||||||
|
inline bool TileBelongsToIndustry(TileIndex tile) const
|
||||||
|
{
|
||||||
|
return IsTileType(tile, MP_INDUSTRY) && GetIndustryIndex(tile) == this->index;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the industry of the given tile
|
* Get the industry of the given tile
|
||||||
* @param tile the tile to get the industry from
|
* @param tile the tile to get the industry from
|
||||||
|
|
|
@ -1065,10 +1065,14 @@ static bool SearchLumberMillTrees(TileIndex tile, void *user_data)
|
||||||
*/
|
*/
|
||||||
static void ChopLumberMillTrees(Industry *i)
|
static void ChopLumberMillTrees(Industry *i)
|
||||||
{
|
{
|
||||||
|
/* We only want to cut trees if all tiles are completed. */
|
||||||
|
TILE_AREA_LOOP(tile_cur, i->location) {
|
||||||
|
if (i->TileBelongsToIndustry(tile_cur)) {
|
||||||
|
if (!IsIndustryCompleted(tile_cur)) return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TileIndex tile = i->location.tile;
|
TileIndex tile = i->location.tile;
|
||||||
|
|
||||||
if (!IsIndustryCompleted(tile)) return; // Can't proceed if not completed.
|
|
||||||
|
|
||||||
if (CircularTileSearch(&tile, 40, SearchLumberMillTrees, NULL)) { // 40x40 tiles to search.
|
if (CircularTileSearch(&tile, 40, SearchLumberMillTrees, NULL)) { // 40x40 tiles to search.
|
||||||
i->produced_cargo_waiting[0] = min(0xffff, i->produced_cargo_waiting[0] + 45); // Found a tree, add according value to waiting cargo.
|
i->produced_cargo_waiting[0] = min(0xffff, i->produced_cargo_waiting[0] + 45); // Found a tree, add according value to waiting cargo.
|
||||||
}
|
}
|
||||||
|
|
|
@ -1776,6 +1776,8 @@ STR_NETWORK_ERROR_SERVER_BANNED :{WHITE}You are
|
||||||
STR_NETWORK_ERROR_KICKED :{WHITE}You were kicked out of the game
|
STR_NETWORK_ERROR_KICKED :{WHITE}You were kicked out of the game
|
||||||
STR_NETWORK_ERROR_CHEATER :{WHITE}Cheating is not allowed on this server
|
STR_NETWORK_ERROR_CHEATER :{WHITE}Cheating is not allowed on this server
|
||||||
STR_NETWORK_ERROR_TOO_MANY_COMMANDS :{WHITE}You were sending too many commands to the server
|
STR_NETWORK_ERROR_TOO_MANY_COMMANDS :{WHITE}You were sending too many commands to the server
|
||||||
|
STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}You took too long to enter the password
|
||||||
|
STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}Your computer took too long to join
|
||||||
|
|
||||||
############ Leave those lines in this order!!
|
############ Leave those lines in this order!!
|
||||||
STR_NETWORK_ERROR_CLIENT_GENERAL :general error
|
STR_NETWORK_ERROR_CLIENT_GENERAL :general error
|
||||||
|
|
|
@ -819,20 +819,18 @@ static void NetworkSend()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We have to do some UDP checking */
|
/**
|
||||||
void NetworkUDPGameLoop()
|
* We have to do some (simple) background stuff that runs normally,
|
||||||
|
* even when we are not in multiplayer. For example stuff needed
|
||||||
|
* for finding servers or downloading content.
|
||||||
|
*/
|
||||||
|
void NetworkBackgroundLoop()
|
||||||
{
|
{
|
||||||
_network_content_client.SendReceive();
|
_network_content_client.SendReceive();
|
||||||
TCPConnecter::CheckCallbacks();
|
TCPConnecter::CheckCallbacks();
|
||||||
NetworkHTTPSocketHandler::HTTPReceive();
|
NetworkHTTPSocketHandler::HTTPReceive();
|
||||||
|
|
||||||
if (_network_udp_server) {
|
NetworkBackgroundUDPLoop();
|
||||||
_udp_server_socket->ReceivePackets();
|
|
||||||
_udp_master_socket->ReceivePackets();
|
|
||||||
} else {
|
|
||||||
_udp_client_socket->ReceivePackets();
|
|
||||||
if (_network_udp_broadcast > 0) _network_udp_broadcast--;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The main loop called from ttd.c
|
/* The main loop called from ttd.c
|
||||||
|
|
|
@ -633,6 +633,12 @@ DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_ERROR)
|
||||||
case NETWORK_ERROR_TOO_MANY_COMMANDS:
|
case NETWORK_ERROR_TOO_MANY_COMMANDS:
|
||||||
_switch_mode_errorstr = STR_NETWORK_ERROR_TOO_MANY_COMMANDS;
|
_switch_mode_errorstr = STR_NETWORK_ERROR_TOO_MANY_COMMANDS;
|
||||||
break;
|
break;
|
||||||
|
case NETWORK_ERROR_TIMEOUT_PASSWORD:
|
||||||
|
ShowErrorMessage(STR_NETWORK_ERROR_TIMEOUT_PASSWORD, INVALID_STRING_ID, WL_CRITICAL);
|
||||||
|
break;
|
||||||
|
case NETWORK_ERROR_TIMEOUT_COMPUTER:
|
||||||
|
ShowErrorMessage(STR_NETWORK_ERROR_TIMEOUT_COMPUTER, INVALID_STRING_ID, WL_CRITICAL);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
_switch_mode_errorstr = STR_NETWORK_ERROR_LOSTCONNECTION;
|
_switch_mode_errorstr = STR_NETWORK_ERROR_LOSTCONNECTION;
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ const char *NetworkChangeCompanyPassword(CompanyID company_id, const char *passw
|
||||||
void NetworkReboot();
|
void NetworkReboot();
|
||||||
void NetworkDisconnect(bool blocking = false, bool close_admins = true);
|
void NetworkDisconnect(bool blocking = false, bool close_admins = true);
|
||||||
void NetworkGameLoop();
|
void NetworkGameLoop();
|
||||||
void NetworkUDPGameLoop();
|
void NetworkBackgroundLoop();
|
||||||
void ParseConnectionString(const char **company, const char **port, char *connection_string);
|
void ParseConnectionString(const char **company, const char **port, char *connection_string);
|
||||||
void NetworkStartDebugLog(NetworkAddress address);
|
void NetworkStartDebugLog(NetworkAddress address);
|
||||||
void NetworkPopulateCompanyStats(NetworkCompanyStats *stats);
|
void NetworkPopulateCompanyStats(NetworkCompanyStats *stats);
|
||||||
|
|
|
@ -1717,55 +1717,94 @@ void NetworkServer_Tick(bool send_frame)
|
||||||
_settings_client.network.bytes_per_frame_burst);
|
_settings_client.network.bytes_per_frame_burst);
|
||||||
|
|
||||||
/* Check if the speed of the client is what we can expect from a client */
|
/* Check if the speed of the client is what we can expect from a client */
|
||||||
if (cs->status == NetworkClientSocket::STATUS_ACTIVE) {
|
uint lag = NetworkCalculateLag(cs);
|
||||||
/* 1 lag-point per day */
|
switch (cs->status) {
|
||||||
uint lag = NetworkCalculateLag(cs) / DAY_TICKS;
|
case NetworkClientSocket::STATUS_ACTIVE:
|
||||||
if (lag > 0) {
|
/* 1 lag-point per day */
|
||||||
if (lag > 3) {
|
lag /= DAY_TICKS;
|
||||||
/* Client did still not report in after 4 game-day, drop him
|
if (lag > 0) {
|
||||||
* (that is, the 3 of above, + 1 before any lag is counted) */
|
if (lag > 3) {
|
||||||
IConsolePrintF(CC_ERROR, cs->last_packet + 3 * DAY_TICKS * MILLISECONDS_PER_TICK > _realtime_tick ?
|
/* Client did still not report in after 4 game-day, drop him
|
||||||
/* A packet was received in the last three game days, so the client is likely lagging behind. */
|
* (that is, the 3 of above, + 1 before any lag is counted) */
|
||||||
"Client #%d is dropped because the client's game state is more than 4 game-days behind" :
|
IConsolePrintF(CC_ERROR, cs->last_packet + 3 * DAY_TICKS * MILLISECONDS_PER_TICK > _realtime_tick ?
|
||||||
/* No packet was received in the last three game days; sounds like a lost connection. */
|
/* A packet was received in the last three game days, so the client is likely lagging behind. */
|
||||||
"Client #%d is dropped because the client did not respond for more than 4 game-days",
|
"Client #%d is dropped because the client's game state is more than 4 game-days behind" :
|
||||||
cs->client_id);
|
/* No packet was received in the last three game days; sounds like a lost connection. */
|
||||||
cs->CloseConnection(NETWORK_RECV_STATUS_SERVER_ERROR);
|
"Client #%d is dropped because the client did not respond for more than 4 game-days",
|
||||||
|
cs->client_id);
|
||||||
|
cs->SendError(NETWORK_ERROR_TIMEOUT_COMPUTER);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Report once per time we detect the lag, and only when we
|
||||||
|
* received a packet in the last 2000 milliseconds. If we
|
||||||
|
* did not receive a packet, then the client is not just
|
||||||
|
* slow, but the connection is likely severed. Mentioning
|
||||||
|
* frame_freq is not useful in this case. */
|
||||||
|
if (cs->lag_test == 0 && cs->last_packet + DAY_TICKS * MILLISECONDS_PER_TICK > _realtime_tick) {
|
||||||
|
IConsolePrintF(CC_WARNING,"[%d] Client #%d is slow, try increasing [network.]frame_freq to a higher value!", _frame_counter, cs->client_id);
|
||||||
|
cs->lag_test = 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cs->lag_test = 0;
|
||||||
|
}
|
||||||
|
if (cs->last_frame_server - cs->last_token_frame >= 5 * DAY_TICKS) {
|
||||||
|
/* This is a bad client! It didn't send the right token back. */
|
||||||
|
IConsolePrintF(CC_ERROR, "Client #%d is dropped because it fails to send valid acks", cs->client_id);
|
||||||
|
cs->SendError(NETWORK_ERROR_TIMEOUT_COMPUTER);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
/* Report once per time we detect the lag, and only when we
|
case NetworkClientSocket::STATUS_INACTIVE:
|
||||||
* received a packet in the last 2000 milliseconds. If we
|
case NetworkClientSocket::STATUS_NEWGRFS_CHECK:
|
||||||
* did not receive a packet, then the client is not just
|
case NetworkClientSocket::STATUS_AUTHORIZED:
|
||||||
* slow, but the connection is likely severed. Mentioning
|
/* NewGRF check and authorized states should be handled almost instantly.
|
||||||
* frame_freq is not useful in this case. */
|
* So give them some lee-way, likewise for the query with inactive. */
|
||||||
if (cs->lag_test == 0 && cs->last_packet + DAY_TICKS * MILLISECONDS_PER_TICK > _realtime_tick) {
|
if (lag > 4 * DAY_TICKS) {
|
||||||
IConsolePrintF(CC_WARNING,"[%d] Client #%d is slow, try increasing [network.]frame_freq to a higher value!", _frame_counter, cs->client_id);
|
IConsolePrintF(CC_ERROR,"Client #%d is dropped because it took longer than %d ticks to start the joining process", cs->client_id, 4 * DAY_TICKS);
|
||||||
cs->lag_test = 1;
|
cs->SendError(NETWORK_ERROR_TIMEOUT_COMPUTER);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
break;
|
||||||
cs->lag_test = 0;
|
|
||||||
}
|
case NetworkClientSocket::STATUS_MAP:
|
||||||
if (cs->last_frame_server - cs->last_token_frame >= 5 * DAY_TICKS) {
|
/* Downloading the map... this is the amount of time since starting the saving. */
|
||||||
/* This is a bad client! It didn't send the right token back. */
|
if (lag > _settings_client.network.max_download_time) {
|
||||||
IConsolePrintF(CC_ERROR, "Client #%d is dropped because it fails to send valid acks", cs->client_id);
|
IConsolePrintF(CC_ERROR,"Client #%d is dropped because it took longer than %d ticks for him to download the map", cs->client_id, _settings_client.network.max_download_time);
|
||||||
cs->CloseConnection(NETWORK_RECV_STATUS_SERVER_ERROR);
|
cs->SendError(NETWORK_ERROR_TIMEOUT_COMPUTER);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else if (cs->status == NetworkClientSocket::STATUS_PRE_ACTIVE) {
|
break;
|
||||||
uint lag = NetworkCalculateLag(cs);
|
|
||||||
if (lag > _settings_client.network.max_join_time) {
|
case NetworkClientSocket::STATUS_DONE_MAP:
|
||||||
IConsolePrintF(CC_ERROR,"Client #%d is dropped because it took longer than %d ticks for him to join", cs->client_id, _settings_client.network.max_join_time);
|
case NetworkClientSocket::STATUS_PRE_ACTIVE:
|
||||||
cs->CloseConnection(NETWORK_RECV_STATUS_SERVER_ERROR);
|
/* The map has been sent, so this is for loading the map and syncing up. */
|
||||||
continue;
|
if (lag > _settings_client.network.max_join_time) {
|
||||||
}
|
IConsolePrintF(CC_ERROR,"Client #%d is dropped because it took longer than %d ticks for him to join", cs->client_id, _settings_client.network.max_join_time);
|
||||||
} else if (cs->status == NetworkClientSocket::STATUS_INACTIVE) {
|
cs->SendError(NETWORK_ERROR_TIMEOUT_COMPUTER);
|
||||||
uint lag = NetworkCalculateLag(cs);
|
continue;
|
||||||
if (lag > 4 * DAY_TICKS) {
|
}
|
||||||
IConsolePrintF(CC_ERROR,"Client #%d is dropped because it took longer than %d ticks to start the joining process", cs->client_id, 4 * DAY_TICKS);
|
break;
|
||||||
cs->CloseConnection(NETWORK_RECV_STATUS_SERVER_ERROR);
|
|
||||||
continue;
|
case NetworkClientSocket::STATUS_AUTH_GAME:
|
||||||
}
|
case NetworkClientSocket::STATUS_AUTH_COMPANY:
|
||||||
|
/* These don't block? */
|
||||||
|
if (lag > _settings_client.network.max_password_time) {
|
||||||
|
IConsolePrintF(CC_ERROR,"Client #%d is dropped because it took longer than %d to enter the password", cs->client_id, _settings_client.network.max_password_time);
|
||||||
|
cs->SendError(NETWORK_ERROR_TIMEOUT_PASSWORD);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NetworkClientSocket::STATUS_MAP_WAIT:
|
||||||
|
/* This is an internal state where we do not wait
|
||||||
|
* on the client to move to a different state. */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NetworkClientSocket::STATUS_END:
|
||||||
|
/* Bad server/code. */
|
||||||
|
NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cs->status >= NetworkClientSocket::STATUS_PRE_ACTIVE) {
|
if (cs->status >= NetworkClientSocket::STATUS_PRE_ACTIVE) {
|
||||||
|
|
|
@ -119,6 +119,8 @@ enum NetworkErrorCode {
|
||||||
NETWORK_ERROR_CHEATER,
|
NETWORK_ERROR_CHEATER,
|
||||||
NETWORK_ERROR_FULL,
|
NETWORK_ERROR_FULL,
|
||||||
NETWORK_ERROR_TOO_MANY_COMMANDS,
|
NETWORK_ERROR_TOO_MANY_COMMANDS,
|
||||||
|
NETWORK_ERROR_TIMEOUT_PASSWORD,
|
||||||
|
NETWORK_ERROR_TIMEOUT_COMPUTER,
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* ENABLE_NETWORK */
|
#endif /* ENABLE_NETWORK */
|
||||||
|
|
|
@ -637,4 +637,20 @@ void NetworkUDPClose()
|
||||||
DEBUG(net, 1, "[udp] closed listeners");
|
DEBUG(net, 1, "[udp] closed listeners");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Receive the UDP packets. */
|
||||||
|
void NetworkBackgroundUDPLoop()
|
||||||
|
{
|
||||||
|
_network_udp_mutex->BeginCritical();
|
||||||
|
|
||||||
|
if (_network_udp_server) {
|
||||||
|
_udp_server_socket->ReceivePackets();
|
||||||
|
_udp_master_socket->ReceivePackets();
|
||||||
|
} else {
|
||||||
|
_udp_client_socket->ReceivePackets();
|
||||||
|
if (_network_udp_broadcast > 0) _network_udp_broadcast--;
|
||||||
|
}
|
||||||
|
|
||||||
|
_network_udp_mutex->EndCritical();
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* ENABLE_NETWORK */
|
#endif /* ENABLE_NETWORK */
|
||||||
|
|
|
@ -23,6 +23,7 @@ void NetworkUDPQueryServer(NetworkAddress address, bool manually = false);
|
||||||
void NetworkUDPAdvertise();
|
void NetworkUDPAdvertise();
|
||||||
void NetworkUDPRemoveAdvertise(bool blocking);
|
void NetworkUDPRemoveAdvertise(bool blocking);
|
||||||
void NetworkUDPClose();
|
void NetworkUDPClose();
|
||||||
|
void NetworkBackgroundUDPLoop();
|
||||||
|
|
||||||
#endif /* ENABLE_NETWORK */
|
#endif /* ENABLE_NETWORK */
|
||||||
|
|
||||||
|
|
|
@ -242,7 +242,7 @@ uint32 IndustryGetVariable(const ResolverObject *object, byte variable, byte par
|
||||||
/* Get random tile bits at offset param */
|
/* Get random tile bits at offset param */
|
||||||
case 0x61:
|
case 0x61:
|
||||||
tile = GetNearbyTile(parameter, tile, false);
|
tile = GetNearbyTile(parameter, tile, false);
|
||||||
return (IsTileType(tile, MP_INDUSTRY) && Industry::GetByTile(tile) == industry) ? GetIndustryRandomBits(tile) : 0;
|
return industry->TileBelongsToIndustry(tile) ? GetIndustryRandomBits(tile) : 0;
|
||||||
|
|
||||||
/* Land info of nearby tiles */
|
/* Land info of nearby tiles */
|
||||||
case 0x62: return GetNearbyIndustryTileInformation(parameter, tile, INVALID_INDUSTRY, false);
|
case 0x62: return GetNearbyIndustryTileInformation(parameter, tile, INVALID_INDUSTRY, false);
|
||||||
|
@ -250,7 +250,7 @@ uint32 IndustryGetVariable(const ResolverObject *object, byte variable, byte par
|
||||||
/* Animation stage of nearby tiles */
|
/* Animation stage of nearby tiles */
|
||||||
case 0x63:
|
case 0x63:
|
||||||
tile = GetNearbyTile(parameter, tile, false);
|
tile = GetNearbyTile(parameter, tile, false);
|
||||||
if (IsTileType(tile, MP_INDUSTRY) && Industry::GetByTile(tile) == industry) {
|
if (industry->TileBelongsToIndustry(tile)) {
|
||||||
return GetAnimationFrame(tile);
|
return GetAnimationFrame(tile);
|
||||||
}
|
}
|
||||||
return 0xFFFFFFFF;
|
return 0xFFFFFFFF;
|
||||||
|
|
|
@ -331,7 +331,7 @@ bool StartStopIndustryTileAnimation(const Industry *ind, IndustryAnimationTrigge
|
||||||
bool ret = true;
|
bool ret = true;
|
||||||
uint32 random = Random();
|
uint32 random = Random();
|
||||||
TILE_AREA_LOOP(tile, ind->location) {
|
TILE_AREA_LOOP(tile, ind->location) {
|
||||||
if (IsTileType(tile, MP_INDUSTRY) && GetIndustryIndex(tile) == ind->index) {
|
if (ind->TileBelongsToIndustry(tile)) {
|
||||||
if (StartStopIndustryTileAnimation(tile, iat, random)) {
|
if (StartStopIndustryTileAnimation(tile, iat, random)) {
|
||||||
SB(random, 0, 16, Random());
|
SB(random, 0, 16, Random());
|
||||||
} else {
|
} else {
|
||||||
|
@ -415,7 +415,7 @@ void TriggerIndustry(Industry *ind, IndustryTileTrigger trigger)
|
||||||
{
|
{
|
||||||
uint32 reseed_industry = 0;
|
uint32 reseed_industry = 0;
|
||||||
TILE_AREA_LOOP(tile, ind->location) {
|
TILE_AREA_LOOP(tile, ind->location) {
|
||||||
if (IsTileType(tile, MP_INDUSTRY) && GetIndustryIndex(tile) == ind->index) {
|
if (ind->TileBelongsToIndustry(tile)) {
|
||||||
DoTriggerIndustryTile(tile, trigger, ind, reseed_industry);
|
DoTriggerIndustryTile(tile, trigger, ind, reseed_industry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include "newgrf_object.h"
|
#include "newgrf_object.h"
|
||||||
#include "date_func.h"
|
#include "date_func.h"
|
||||||
#include "newgrf_debug.h"
|
#include "newgrf_debug.h"
|
||||||
|
#include "vehicle_func.h"
|
||||||
|
|
||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
#include "table/object_land.h"
|
#include "table/object_land.h"
|
||||||
|
@ -221,6 +222,9 @@ CommandCost CmdBuildObject(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
||||||
/* Can't build on water owned by another company. */
|
/* Can't build on water owned by another company. */
|
||||||
Owner o = GetTileOwner(t);
|
Owner o = GetTileOwner(t);
|
||||||
if (o != OWNER_NONE && o != OWNER_WATER) cost.AddCost(CheckOwnership(o, t));
|
if (o != OWNER_NONE && o != OWNER_WATER) cost.AddCost(CheckOwnership(o, t));
|
||||||
|
|
||||||
|
/* However, the tile has to be clear of vehicles. */
|
||||||
|
cost.AddCost(EnsureNoVehicleOnGround(t));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!allow_ground) return_cmd_error(STR_ERROR_MUST_BE_BUILT_ON_WATER);
|
if (!allow_ground) return_cmd_error(STR_ERROR_MUST_BE_BUILT_ON_WATER);
|
||||||
|
|
|
@ -1268,7 +1268,7 @@ void GameLoop()
|
||||||
|
|
||||||
#ifdef ENABLE_NETWORK
|
#ifdef ENABLE_NETWORK
|
||||||
/* Check for UDP stuff */
|
/* Check for UDP stuff */
|
||||||
if (_network_available) NetworkUDPGameLoop();
|
if (_network_available) NetworkBackgroundLoop();
|
||||||
|
|
||||||
if (_networking && !IsGeneratingWorld()) {
|
if (_networking && !IsGeneratingWorld()) {
|
||||||
/* Multiplayer */
|
/* Multiplayer */
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "order_backup.h"
|
#include "order_backup.h"
|
||||||
#include "vehicle_base.h"
|
#include "vehicle_base.h"
|
||||||
#include "window_func.h"
|
#include "window_func.h"
|
||||||
|
#include "station_map.h"
|
||||||
|
|
||||||
OrderBackupPool _order_backup_pool("BackupOrder");
|
OrderBackupPool _order_backup_pool("BackupOrder");
|
||||||
INSTANTIATE_POOL_METHODS(OrderBackup)
|
INSTANTIATE_POOL_METHODS(OrderBackup)
|
||||||
|
@ -262,3 +263,25 @@ void InitializeOrderBackups()
|
||||||
{
|
{
|
||||||
_order_backup_pool.CleanPool();
|
_order_backup_pool.CleanPool();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes an order from all vehicles. Triggers when, say, a station is removed.
|
||||||
|
* @param type The type of the order (OT_GOTO_[STATION|DEPOT|WAYPOINT]).
|
||||||
|
* @param destination The destination. Can be a StationID, DepotID or WaypointID.
|
||||||
|
*/
|
||||||
|
/* static */ void OrderBackup::RemoveOrder(OrderType type, DestinationID destination)
|
||||||
|
{
|
||||||
|
OrderBackup *ob;
|
||||||
|
FOR_ALL_ORDER_BACKUPS(ob) {
|
||||||
|
for (Order *order = ob->orders; order != NULL; order = order->next) {
|
||||||
|
OrderType ot = order->GetType();
|
||||||
|
if (ot == OT_GOTO_DEPOT && (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) continue;
|
||||||
|
if (ot == OT_IMPLICIT || (IsHangarTile(ob->tile) && ot == OT_GOTO_DEPOT)) ot = OT_GOTO_STATION;
|
||||||
|
if (ot == type && order->GetDestination() == destination) {
|
||||||
|
/* Remove the order backup! If a station/depot gets removed, we can't/shouldn't restore those broken orders. */
|
||||||
|
delete ob;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -67,6 +67,7 @@ public:
|
||||||
|
|
||||||
static void ClearGroup(GroupID group);
|
static void ClearGroup(GroupID group);
|
||||||
static void ClearVehicle(const Vehicle *v);
|
static void ClearVehicle(const Vehicle *v);
|
||||||
|
static void RemoveOrder(OrderType type, DestinationID destination);
|
||||||
};
|
};
|
||||||
|
|
||||||
#define FOR_ALL_ORDER_BACKUPS_FROM(var, start) FOR_ALL_ITEMS_FROM(OrderBackup, order_backup_index, var, start)
|
#define FOR_ALL_ORDER_BACKUPS_FROM(var, start) FOR_ALL_ITEMS_FROM(OrderBackup, order_backup_index, var, start)
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "station_base.h"
|
#include "station_base.h"
|
||||||
#include "waypoint_base.h"
|
#include "waypoint_base.h"
|
||||||
#include "company_base.h"
|
#include "company_base.h"
|
||||||
|
#include "order_backup.h"
|
||||||
|
|
||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
|
|
||||||
|
@ -1699,6 +1700,8 @@ restart:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OrderBackup::RemoveOrder(type, destination);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -155,6 +155,8 @@ struct NetworkSettings {
|
||||||
uint16 bytes_per_frame; ///< how many bytes may, over a long period, be received per frame?
|
uint16 bytes_per_frame; ///< how many bytes may, over a long period, be received per frame?
|
||||||
uint16 bytes_per_frame_burst; ///< how many bytes may, over a short period, be received?
|
uint16 bytes_per_frame_burst; ///< how many bytes may, over a short period, be received?
|
||||||
uint16 max_join_time; ///< maximum amount of time, in game ticks, a client may take to join
|
uint16 max_join_time; ///< maximum amount of time, in game ticks, a client may take to join
|
||||||
|
uint16 max_download_time; ///< maximum amount of time, in game ticks, a client may take to download the map
|
||||||
|
uint16 max_password_time; ///< maximum amount of time, in game ticks, a client may take to enter the password
|
||||||
bool pause_on_join; ///< pause the game when people join
|
bool pause_on_join; ///< pause the game when people join
|
||||||
uint16 server_port; ///< port the server listens on
|
uint16 server_port; ///< port the server listens on
|
||||||
uint16 server_admin_port; ///< port the server listens on for the admin network
|
uint16 server_admin_port; ///< port the server listens on for the admin network
|
||||||
|
|
|
@ -645,6 +645,8 @@ const SettingDesc _settings[] = {
|
||||||
SDTC_VAR(network.bytes_per_frame, SLE_UINT16, S, NO, 8, 1, 65535, 0, STR_NULL, NULL),
|
SDTC_VAR(network.bytes_per_frame, SLE_UINT16, S, NO, 8, 1, 65535, 0, STR_NULL, NULL),
|
||||||
SDTC_VAR(network.bytes_per_frame_burst,SLE_UINT16, S, NO, 256, 1, 65535, 0, STR_NULL, NULL),
|
SDTC_VAR(network.bytes_per_frame_burst,SLE_UINT16, S, NO, 256, 1, 65535, 0, STR_NULL, NULL),
|
||||||
SDTC_VAR(network.max_join_time, SLE_UINT16, S, NO, 500, 0, 32000, 0, STR_NULL, NULL),
|
SDTC_VAR(network.max_join_time, SLE_UINT16, S, NO, 500, 0, 32000, 0, STR_NULL, NULL),
|
||||||
|
SDTC_VAR(network.max_download_time, SLE_UINT16, S, NO, 1000, 0, 32000, 0, STR_NULL, NULL),
|
||||||
|
SDTC_VAR(network.max_password_time, SLE_UINT16, S, NO, 2000, 0, 32000, 0, STR_NULL, NULL),
|
||||||
SDTC_BOOL(network.pause_on_join, S, NO, true, STR_NULL, NULL),
|
SDTC_BOOL(network.pause_on_join, S, NO, true, STR_NULL, NULL),
|
||||||
SDTC_VAR(network.server_port, SLE_UINT16, S, NO,NETWORK_DEFAULT_PORT,0,65535,0,STR_NULL, NULL),
|
SDTC_VAR(network.server_port, SLE_UINT16, S, NO,NETWORK_DEFAULT_PORT,0,65535,0,STR_NULL, NULL),
|
||||||
SDTC_VAR(network.server_admin_port, SLE_UINT16, S, NO, NETWORK_ADMIN_PORT,0,65535,0,STR_NULL, NULL),
|
SDTC_VAR(network.server_admin_port, SLE_UINT16, S, NO, NETWORK_ADMIN_PORT,0,65535,0,STR_NULL, NULL),
|
||||||
|
|
Loading…
Reference in New Issue