1
0
Fork 0

(svn r19603) [1.0] -Backport from trunk:

- Fix: Desync debugging; false positives in the cache validity checks and saving/loading the command stream (r19601, r19600, r19596, r19593, r19592, r19589, r19587, r19586)
release/1.0
rubidium 2010-04-11 10:57:21 +00:00
parent d197bcae1c
commit 83cca3a75a
12 changed files with 225 additions and 143 deletions

View File

@ -188,6 +188,8 @@ CommandProc CmdSetVehicleOnTime;
CommandProc CmdAutofillTimetable;
CommandProc CmdSetTimetableStart;
#define DEF_CMD(proc, flags) {proc, #proc, flags}
/**
* The master command table
*
@ -196,141 +198,141 @@ CommandProc CmdSetTimetableStart;
* as the value from the CMD_* enums.
*/
static const Command _command_proc_table[] = {
{CmdBuildRailroadTrack, CMD_NO_WATER | CMD_AUTO}, // CMD_BUILD_RAILROAD_TRACK
{CmdRemoveRailroadTrack, CMD_AUTO}, // CMD_REMOVE_RAILROAD_TRACK
{CmdBuildSingleRail, CMD_NO_WATER | CMD_AUTO}, // CMD_BUILD_SINGLE_RAIL
{CmdRemoveSingleRail, CMD_AUTO}, // CMD_REMOVE_SINGLE_RAIL
{CmdLandscapeClear, 0}, // CMD_LANDSCAPE_CLEAR
{CmdBuildBridge, CMD_AUTO}, // CMD_BUILD_BRIDGE
{CmdBuildRailStation, CMD_NO_WATER | CMD_AUTO}, // CMD_BUILD_RAIL_STATION
{CmdBuildTrainDepot, CMD_NO_WATER | CMD_AUTO}, // CMD_BUILD_TRAIN_DEPOT
{CmdBuildSingleSignal, CMD_AUTO}, // CMD_BUILD_SIGNALS
{CmdRemoveSingleSignal, CMD_AUTO}, // CMD_REMOVE_SIGNALS
{CmdTerraformLand, CMD_ALL_TILES | CMD_AUTO}, // CMD_TERRAFORM_LAND
{CmdPurchaseLandArea, CMD_NO_WATER | CMD_AUTO}, // CMD_PURCHASE_LAND_AREA
{CmdSellLandArea, 0}, // CMD_SELL_LAND_AREA
{CmdBuildTunnel, CMD_AUTO}, // CMD_BUILD_TUNNEL
{CmdRemoveFromRailStation, 0}, // CMD_REMOVE_FROM_RAIL_STATION
{CmdConvertRail, 0}, // CMD_CONVERT_RAILD
{CmdBuildRailWaypoint, 0}, // CMD_BUILD_RAIL_WAYPOINT
{CmdRenameWaypoint, 0}, // CMD_RENAME_WAYPOINT
{CmdRemoveFromRailWaypoint, 0}, // CMD_REMOVE_FROM_RAIL_WAYPOINT
DEF_CMD(CmdBuildRailroadTrack, CMD_NO_WATER | CMD_AUTO), // CMD_BUILD_RAILROAD_TRACK
DEF_CMD(CmdRemoveRailroadTrack, CMD_AUTO), // CMD_REMOVE_RAILROAD_TRACK
DEF_CMD(CmdBuildSingleRail, CMD_NO_WATER | CMD_AUTO), // CMD_BUILD_SINGLE_RAIL
DEF_CMD(CmdRemoveSingleRail, CMD_AUTO), // CMD_REMOVE_SINGLE_RAIL
DEF_CMD(CmdLandscapeClear, 0), // CMD_LANDSCAPE_CLEAR
DEF_CMD(CmdBuildBridge, CMD_AUTO), // CMD_BUILD_BRIDGE
DEF_CMD(CmdBuildRailStation, CMD_NO_WATER | CMD_AUTO), // CMD_BUILD_RAIL_STATION
DEF_CMD(CmdBuildTrainDepot, CMD_NO_WATER | CMD_AUTO), // CMD_BUILD_TRAIN_DEPOT
DEF_CMD(CmdBuildSingleSignal, CMD_AUTO), // CMD_BUILD_SIGNALS
DEF_CMD(CmdRemoveSingleSignal, CMD_AUTO), // CMD_REMOVE_SIGNALS
DEF_CMD(CmdTerraformLand, CMD_ALL_TILES | CMD_AUTO), // CMD_TERRAFORM_LAND
DEF_CMD(CmdPurchaseLandArea, CMD_NO_WATER | CMD_AUTO), // CMD_PURCHASE_LAND_AREA
DEF_CMD(CmdSellLandArea, 0), // CMD_SELL_LAND_AREA
DEF_CMD(CmdBuildTunnel, CMD_AUTO), // CMD_BUILD_TUNNEL
DEF_CMD(CmdRemoveFromRailStation, 0), // CMD_REMOVE_FROM_RAIL_STATION
DEF_CMD(CmdConvertRail, 0), // CMD_CONVERT_RAILD
DEF_CMD(CmdBuildRailWaypoint, 0), // CMD_BUILD_RAIL_WAYPOINT
DEF_CMD(CmdRenameWaypoint, 0), // CMD_RENAME_WAYPOINT
DEF_CMD(CmdRemoveFromRailWaypoint, 0), // CMD_REMOVE_FROM_RAIL_WAYPOINT
{CmdBuildRoadStop, CMD_NO_WATER | CMD_AUTO}, // CMD_BUILD_ROAD_STOP
{CmdRemoveRoadStop, 0}, // CMD_REMOVE_ROAD_STOP
{CmdBuildLongRoad, CMD_NO_WATER | CMD_AUTO}, // CMD_BUILD_LONG_ROAD
{CmdRemoveLongRoad, CMD_NO_TEST | CMD_AUTO}, // CMD_REMOVE_LONG_ROAD; towns may disallow removing road bits (as they are connected) in test, but in exec they're removed and thus removing is allowed.
{CmdBuildRoad, CMD_NO_WATER | CMD_AUTO}, // CMD_BUILD_ROAD
{CmdBuildRoadDepot, CMD_NO_WATER | CMD_AUTO}, // CMD_BUILD_ROAD_DEPOT
DEF_CMD(CmdBuildRoadStop, CMD_NO_WATER | CMD_AUTO), // CMD_BUILD_ROAD_STOP
DEF_CMD(CmdRemoveRoadStop, 0), // CMD_REMOVE_ROAD_STOP
DEF_CMD(CmdBuildLongRoad, CMD_NO_WATER | CMD_AUTO), // CMD_BUILD_LONG_ROAD
DEF_CMD(CmdRemoveLongRoad, CMD_NO_TEST | CMD_AUTO), // CMD_REMOVE_LONG_ROAD; towns may disallow removing road bits (as they are connected) in test, but in exec they're removed and thus removing is allowed.
DEF_CMD(CmdBuildRoad, CMD_NO_WATER | CMD_AUTO), // CMD_BUILD_ROAD
DEF_CMD(CmdBuildRoadDepot, CMD_NO_WATER | CMD_AUTO), // CMD_BUILD_ROAD_DEPOT
{CmdBuildAirport, CMD_NO_WATER | CMD_AUTO}, // CMD_BUILD_AIRPORT
{CmdBuildDock, CMD_AUTO}, // CMD_BUILD_DOCK
{CmdBuildShipDepot, CMD_AUTO}, // CMD_BUILD_SHIP_DEPOT
{CmdBuildBuoy, CMD_AUTO}, // CMD_BUILD_BUOY
{CmdPlantTree, CMD_AUTO}, // CMD_PLANT_TREE
{CmdBuildRailVehicle, 0}, // CMD_BUILD_RAIL_VEHICLE
{CmdMoveRailVehicle, 0}, // CMD_MOVE_RAIL_VEHICLE
DEF_CMD(CmdBuildAirport, CMD_NO_WATER | CMD_AUTO), // CMD_BUILD_AIRPORT
DEF_CMD(CmdBuildDock, CMD_AUTO), // CMD_BUILD_DOCK
DEF_CMD(CmdBuildShipDepot, CMD_AUTO), // CMD_BUILD_SHIP_DEPOT
DEF_CMD(CmdBuildBuoy, CMD_AUTO), // CMD_BUILD_BUOY
DEF_CMD(CmdPlantTree, CMD_AUTO), // CMD_PLANT_TREE
DEF_CMD(CmdBuildRailVehicle, 0), // CMD_BUILD_RAIL_VEHICLE
DEF_CMD(CmdMoveRailVehicle, 0), // CMD_MOVE_RAIL_VEHICLE
{CmdSellRailWagon, 0}, // CMD_SELL_RAIL_WAGON
{CmdSendTrainToDepot, 0}, // CMD_SEND_TRAIN_TO_DEPOT
{CmdForceTrainProceed, 0}, // CMD_FORCE_TRAIN_PROCEED
{CmdReverseTrainDirection, 0}, // CMD_REVERSE_TRAIN_DIRECTION
DEF_CMD(CmdSellRailWagon, 0), // CMD_SELL_RAIL_WAGON
DEF_CMD(CmdSendTrainToDepot, 0), // CMD_SEND_TRAIN_TO_DEPOT
DEF_CMD(CmdForceTrainProceed, 0), // CMD_FORCE_TRAIN_PROCEED
DEF_CMD(CmdReverseTrainDirection, 0), // CMD_REVERSE_TRAIN_DIRECTION
{CmdModifyOrder, 0}, // CMD_MODIFY_ORDER
{CmdSkipToOrder, 0}, // CMD_SKIP_TO_ORDER
{CmdDeleteOrder, 0}, // CMD_DELETE_ORDER
{CmdInsertOrder, 0}, // CMD_INSERT_ORDER
DEF_CMD(CmdModifyOrder, 0), // CMD_MODIFY_ORDER
DEF_CMD(CmdSkipToOrder, 0), // CMD_SKIP_TO_ORDER
DEF_CMD(CmdDeleteOrder, 0), // CMD_DELETE_ORDER
DEF_CMD(CmdInsertOrder, 0), // CMD_INSERT_ORDER
{CmdChangeServiceInt, 0}, // CMD_CHANGE_SERVICE_INT
DEF_CMD(CmdChangeServiceInt, 0), // CMD_CHANGE_SERVICE_INT
{CmdBuildIndustry, 0}, // CMD_BUILD_INDUSTRY
{CmdBuildCompanyHQ, CMD_NO_WATER | CMD_AUTO}, // CMD_BUILD_COMPANY_HQ
{CmdSetCompanyManagerFace, 0}, // CMD_SET_COMPANY_MANAGER_FACE
{CmdSetCompanyColour, 0}, // CMD_SET_COMPANY_COLOUR
DEF_CMD(CmdBuildIndustry, 0), // CMD_BUILD_INDUSTRY
DEF_CMD(CmdBuildCompanyHQ, CMD_NO_WATER | CMD_AUTO), // CMD_BUILD_COMPANY_HQ
DEF_CMD(CmdSetCompanyManagerFace, 0), // CMD_SET_COMPANY_MANAGER_FACE
DEF_CMD(CmdSetCompanyColour, 0), // CMD_SET_COMPANY_COLOUR
{CmdIncreaseLoan, 0}, // CMD_INCREASE_LOAN
{CmdDecreaseLoan, 0}, // CMD_DECREASE_LOAN
DEF_CMD(CmdIncreaseLoan, 0), // CMD_INCREASE_LOAN
DEF_CMD(CmdDecreaseLoan, 0), // CMD_DECREASE_LOAN
{CmdWantEnginePreview, 0}, // CMD_WANT_ENGINE_PREVIEW
DEF_CMD(CmdWantEnginePreview, 0), // CMD_WANT_ENGINE_PREVIEW
{CmdRenameVehicle, 0}, // CMD_RENAME_VEHICLE
{CmdRenameEngine, 0}, // CMD_RENAME_ENGINE
DEF_CMD(CmdRenameVehicle, 0), // CMD_RENAME_VEHICLE
DEF_CMD(CmdRenameEngine, 0), // CMD_RENAME_ENGINE
{CmdRenameCompany, 0}, // CMD_RENAME_COMPANY
{CmdRenamePresident, 0}, // CMD_RENAME_PRESIDENT
DEF_CMD(CmdRenameCompany, 0), // CMD_RENAME_COMPANY
DEF_CMD(CmdRenamePresident, 0), // CMD_RENAME_PRESIDENT
{CmdRenameStation, 0}, // CMD_RENAME_STATION
DEF_CMD(CmdRenameStation, 0), // CMD_RENAME_STATION
{CmdSellAircraft, 0}, // CMD_SELL_AIRCRAFT
DEF_CMD(CmdSellAircraft, 0), // CMD_SELL_AIRCRAFT
{CmdBuildAircraft, 0}, // CMD_BUILD_AIRCRAFT
{CmdSendAircraftToHangar, 0}, // CMD_SEND_AIRCRAFT_TO_HANGAR
{CmdRefitAircraft, 0}, // CMD_REFIT_AIRCRAFT
DEF_CMD(CmdBuildAircraft, 0), // CMD_BUILD_AIRCRAFT
DEF_CMD(CmdSendAircraftToHangar, 0), // CMD_SEND_AIRCRAFT_TO_HANGAR
DEF_CMD(CmdRefitAircraft, 0), // CMD_REFIT_AIRCRAFT
{CmdPlaceSign, 0}, // CMD_PLACE_SIGN
{CmdRenameSign, 0}, // CMD_RENAME_SIGN
DEF_CMD(CmdPlaceSign, 0), // CMD_PLACE_SIGN
DEF_CMD(CmdRenameSign, 0), // CMD_RENAME_SIGN
{CmdBuildRoadVeh, 0}, // CMD_BUILD_ROAD_VEH
{CmdSellRoadVeh, 0}, // CMD_SELL_ROAD_VEH
{CmdSendRoadVehToDepot, 0}, // CMD_SEND_ROADVEH_TO_DEPOT
{CmdTurnRoadVeh, 0}, // CMD_TURN_ROADVEH
{CmdRefitRoadVeh, 0}, // CMD_REFIT_ROAD_VEH
DEF_CMD(CmdBuildRoadVeh, 0), // CMD_BUILD_ROAD_VEH
DEF_CMD(CmdSellRoadVeh, 0), // CMD_SELL_ROAD_VEH
DEF_CMD(CmdSendRoadVehToDepot, 0), // CMD_SEND_ROADVEH_TO_DEPOT
DEF_CMD(CmdTurnRoadVeh, 0), // CMD_TURN_ROADVEH
DEF_CMD(CmdRefitRoadVeh, 0), // CMD_REFIT_ROAD_VEH
{CmdPause, CMD_SERVER}, // CMD_PAUSE
DEF_CMD(CmdPause, CMD_SERVER), // CMD_PAUSE
{CmdBuyShareInCompany, 0}, // CMD_BUY_SHARE_IN_COMPANY
{CmdSellShareInCompany, 0}, // CMD_SELL_SHARE_IN_COMPANY
{CmdBuyCompany, 0}, // CMD_BUY_COMANY
DEF_CMD(CmdBuyShareInCompany, 0), // CMD_BUY_SHARE_IN_COMPANY
DEF_CMD(CmdSellShareInCompany, 0), // CMD_SELL_SHARE_IN_COMPANY
DEF_CMD(CmdBuyCompany, 0), // CMD_BUY_COMANY
{CmdFoundTown, CMD_NO_TEST}, // CMD_FOUND_TOWN; founding random town can fail only in exec run
{CmdRenameTown, CMD_SERVER}, // CMD_RENAME_TOWN
{CmdDoTownAction, 0}, // CMD_DO_TOWN_ACTION
DEF_CMD(CmdFoundTown, CMD_NO_TEST), // CMD_FOUND_TOWN; founding random town can fail only in exec run
DEF_CMD(CmdRenameTown, CMD_SERVER), // CMD_RENAME_TOWN
DEF_CMD(CmdDoTownAction, 0), // CMD_DO_TOWN_ACTION
{CmdSellShip, 0}, // CMD_SELL_SHIP
{CmdBuildShip, 0}, // CMD_BUILD_SHIP
{CmdSendShipToDepot, 0}, // CMD_SEND_SHIP_TO_DEPOT
{CmdRefitShip, 0}, // CMD_REFIT_SHIP
DEF_CMD(CmdSellShip, 0), // CMD_SELL_SHIP
DEF_CMD(CmdBuildShip, 0), // CMD_BUILD_SHIP
DEF_CMD(CmdSendShipToDepot, 0), // CMD_SEND_SHIP_TO_DEPOT
DEF_CMD(CmdRefitShip, 0), // CMD_REFIT_SHIP
{CmdOrderRefit, 0}, // CMD_ORDER_REFIT
{CmdCloneOrder, 0}, // CMD_CLONE_ORDER
DEF_CMD(CmdOrderRefit, 0), // CMD_ORDER_REFIT
DEF_CMD(CmdCloneOrder, 0), // CMD_CLONE_ORDER
{CmdClearArea, CMD_NO_TEST}, // CMD_CLEAR_AREA; destroying multi-tile houses makes town rating differ between test and execution
DEF_CMD(CmdClearArea, CMD_NO_TEST), // CMD_CLEAR_AREA; destroying multi-tile houses makes town rating differ between test and execution
{CmdMoneyCheat, CMD_OFFLINE}, // CMD_MONEY_CHEAT
{CmdBuildCanal, CMD_AUTO}, // CMD_BUILD_CANAL
{CmdCompanyCtrl, CMD_SPECTATOR}, // CMD_COMPANY_CTRL
DEF_CMD(CmdMoneyCheat, CMD_OFFLINE), // CMD_MONEY_CHEAT
DEF_CMD(CmdBuildCanal, CMD_AUTO), // CMD_BUILD_CANAL
DEF_CMD(CmdCompanyCtrl, CMD_SPECTATOR), // CMD_COMPANY_CTRL
{CmdLevelLand, CMD_ALL_TILES | CMD_NO_TEST | CMD_AUTO}, // CMD_LEVEL_LAND; test run might clear tiles multiple times, in execution that only happens once
DEF_CMD(CmdLevelLand, CMD_ALL_TILES | CMD_NO_TEST | CMD_AUTO), // CMD_LEVEL_LAND; test run might clear tiles multiple times, in execution that only happens once
{CmdRefitRailVehicle, 0}, // CMD_REFIT_RAIL_VEHICLE
{CmdRestoreOrderIndex, 0}, // CMD_RESTORE_ORDER_INDEX
{CmdBuildLock, CMD_AUTO}, // CMD_BUILD_LOCK
DEF_CMD(CmdRefitRailVehicle, 0), // CMD_REFIT_RAIL_VEHICLE
DEF_CMD(CmdRestoreOrderIndex, 0), // CMD_RESTORE_ORDER_INDEX
DEF_CMD(CmdBuildLock, CMD_AUTO), // CMD_BUILD_LOCK
{CmdBuildSignalTrack, CMD_AUTO}, // CMD_BUILD_SIGNAL_TRACK
{CmdRemoveSignalTrack, CMD_AUTO}, // CMD_REMOVE_SIGNAL_TRACK
DEF_CMD(CmdBuildSignalTrack, CMD_AUTO), // CMD_BUILD_SIGNAL_TRACK
DEF_CMD(CmdRemoveSignalTrack, CMD_AUTO), // CMD_REMOVE_SIGNAL_TRACK
{CmdGiveMoney, 0}, // CMD_GIVE_MONEY
{CmdChangeSetting, CMD_SERVER}, // CMD_CHANGE_SETTING
{CmdChangeCompanySetting, 0}, // CMD_CHANGE_COMPANY_SETTING
{CmdSetAutoReplace, 0}, // CMD_SET_AUTOREPLACE
{CmdCloneVehicle, CMD_NO_TEST}, // CMD_CLONE_VEHICLE; NewGRF callbacks influence building and refitting making it impossible to correctly estimate the cost
{CmdStartStopVehicle, 0}, // CMD_START_STOP_VEHICLE
{CmdMassStartStopVehicle, 0}, // CMD_MASS_START_STOP
{CmdAutoreplaceVehicle, 0}, // CMD_AUTOREPLACE_VEHICLE
{CmdDepotSellAllVehicles, 0}, // CMD_DEPOT_SELL_ALL_VEHICLES
{CmdDepotMassAutoReplace, 0}, // CMD_DEPOT_MASS_AUTOREPLACE
{CmdCreateGroup, 0}, // CMD_CREATE_GROUP
{CmdDeleteGroup, 0}, // CMD_DELETE_GROUP
{CmdRenameGroup, 0}, // CMD_RENAME_GROUP
{CmdAddVehicleGroup, 0}, // CMD_ADD_VEHICLE_GROUP
{CmdAddSharedVehicleGroup, 0}, // CMD_ADD_SHARE_VEHICLE_GROUP
{CmdRemoveAllVehiclesGroup, 0}, // CMD_REMOVE_ALL_VEHICLES_GROUP
{CmdSetGroupReplaceProtection, 0}, // CMD_SET_GROUP_REPLACE_PROTECTION
{CmdMoveOrder, 0}, // CMD_MOVE_ORDER
{CmdChangeTimetable, 0}, // CMD_CHANGE_TIMETABLE
{CmdSetVehicleOnTime, 0}, // CMD_SET_VEHICLE_ON_TIME
{CmdAutofillTimetable, 0}, // CMD_AUTOFILL_TIMETABLE
{CmdSetTimetableStart, 0}, // CMD_SET_TIMETABLE_START
DEF_CMD(CmdGiveMoney, 0), // CMD_GIVE_MONEY
DEF_CMD(CmdChangeSetting, CMD_SERVER), // CMD_CHANGE_SETTING
DEF_CMD(CmdChangeCompanySetting, 0), // CMD_CHANGE_COMPANY_SETTING
DEF_CMD(CmdSetAutoReplace, 0), // CMD_SET_AUTOREPLACE
DEF_CMD(CmdCloneVehicle, CMD_NO_TEST), // CMD_CLONE_VEHICLE; NewGRF callbacks influence building and refitting making it impossible to correctly estimate the cost
DEF_CMD(CmdStartStopVehicle, 0), // CMD_START_STOP_VEHICLE
DEF_CMD(CmdMassStartStopVehicle, 0), // CMD_MASS_START_STOP
DEF_CMD(CmdAutoreplaceVehicle, 0), // CMD_AUTOREPLACE_VEHICLE
DEF_CMD(CmdDepotSellAllVehicles, 0), // CMD_DEPOT_SELL_ALL_VEHICLES
DEF_CMD(CmdDepotMassAutoReplace, 0), // CMD_DEPOT_MASS_AUTOREPLACE
DEF_CMD(CmdCreateGroup, 0), // CMD_CREATE_GROUP
DEF_CMD(CmdDeleteGroup, 0), // CMD_DELETE_GROUP
DEF_CMD(CmdRenameGroup, 0), // CMD_RENAME_GROUP
DEF_CMD(CmdAddVehicleGroup, 0), // CMD_ADD_VEHICLE_GROUP
DEF_CMD(CmdAddSharedVehicleGroup, 0), // CMD_ADD_SHARE_VEHICLE_GROUP
DEF_CMD(CmdRemoveAllVehiclesGroup, 0), // CMD_REMOVE_ALL_VEHICLES_GROUP
DEF_CMD(CmdSetGroupReplaceProtection, 0), // CMD_SET_GROUP_REPLACE_PROTECTION
DEF_CMD(CmdMoveOrder, 0), // CMD_MOVE_ORDER
DEF_CMD(CmdChangeTimetable, 0), // CMD_CHANGE_TIMETABLE
DEF_CMD(CmdSetVehicleOnTime, 0), // CMD_SET_VEHICLE_ON_TIME
DEF_CMD(CmdAutofillTimetable, 0), // CMD_AUTOFILL_TIMETABLE
DEF_CMD(CmdSetTimetableStart, 0), // CMD_SET_TIMETABLE_START
};
/*!
@ -362,6 +364,20 @@ byte GetCommandFlags(uint32 cmd)
return _command_proc_table[cmd & CMD_ID_MASK].flags;
}
/*!
* This function mask the parameter with CMD_ID_MASK and returns
* the name which belongs to the given command.
*
* @param cmd The integer value of the command
* @return The name for this command
*/
const char *GetCommandName(uint32 cmd)
{
assert(IsValidCommand(cmd));
return _command_proc_table[cmd & CMD_ID_MASK].name;
}
static int _docommand_recursive = 0;
/**
@ -640,7 +656,7 @@ CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd,
return_dcpi(CommandCost(), false);
}
#endif /* ENABLE_NETWORK */
DEBUG(desync, 1, "cmd: %08x; %08x; %1x; %06x; %08x; %08x; %04x; %s\n", _date, _date_fract, (int)_current_company, tile, p1, p2, cmd & ~CMD_NETWORK_COMMAND, text);
DEBUG(desync, 1, "cmd: %08x; %02x; %02x; %06x; %08x; %08x; %08x; \"%s\" (%s)", _date, _date_fract, (int)_current_company, tile, p1, p2, cmd & ~CMD_NETWORK_COMMAND, text, GetCommandName(cmd));
/* Actually try and execute the command. If no cost-type is given
* use the construction one */

View File

@ -67,6 +67,10 @@ bool IsValidCommand(uint32 cmd);
* Returns the flags from a given command.
*/
byte GetCommandFlags(uint32 cmd);
/**
* Returns the name of a given command.
*/
const char *GetCommandName(uint32 cmd);
/**
* Returns the current money available which can be used for a command.
*/

View File

@ -382,8 +382,9 @@ typedef CommandCost CommandProc(TileIndex tile, DoCommandFlag flags, uint32 p1,
* the #CMD_AUTO, #CMD_OFFLINE and #CMD_SERVER values.
*/
struct Command {
CommandProc *proc;
byte flags;
CommandProc *proc; ///< The procedure to actually executing
const char *name; ///< A human readable name for the procedure
byte flags; ///< The (command) flags to that apply to this command
};
/**

View File

@ -218,12 +218,6 @@ static void OnNewYear()
*/
static void OnNewMonth()
{
if (_debug_desync_level > 2) {
char name[MAX_PATH];
snprintf(name, lengthof(name), "dmp_cmds_%08x_%08x.sav", _settings_game.game_creation.generation_seed, _date);
SaveOrLoad(name, SL_SAVE, AUTOSAVE_DIR);
}
if (_settings_client.gui.autosave != 0 && (_cur_month % _autosave_months[_settings_client.gui.autosave]) == 0) {
_do_autosave = true;
RedrawAutosave();

View File

@ -93,7 +93,7 @@ static void debug_print(const char *dbg, const char *buf)
static FILE *f = FioFOpenFile("commands-out.log", "wb", AUTOSAVE_DIR);
if (f == NULL) return;
fprintf(f, "%s%s", GetLogPrefix(), buf);
fprintf(f, "%s%s\n", GetLogPrefix(), buf);
fflush(f);
}
}

View File

@ -176,7 +176,7 @@ static void _GenerateWorld(void *)
ShowNewGRFError();
if (_network_dedicated) DEBUG(net, 0, "Map generated, starting game");
DEBUG(desync, 1, "new_map: %i\n", _settings_game.game_creation.generation_seed);
DEBUG(desync, 1, "new_map: %08x", _settings_game.game_creation.generation_seed);
if (_settings_client.gui.pause_on_newgame && _game_mode == GM_NORMAL) DoCommandP(0, PM_PAUSED_NORMAL, 1, CMD_PAUSE);
if (_debug_desync_level > 0) {

View File

@ -35,10 +35,13 @@
#include "../rev.h"
#include "../core/pool_func.hpp"
#include "../gfx_func.h"
#include "table/strings.h"
#ifdef DEBUG_DUMP_COMMANDS
#include "../fileio_func.h"
/** When running the server till the wait point, run as fast as we can! */
bool _ddc_fastforward = true;
#endif /* DEBUG_DUMP_COMMANDS */
#include "table/strings.h"
DECLARE_POSTFIX_INCREMENT(ClientID);
@ -249,7 +252,7 @@ void NetworkTextMessage(NetworkAction action, ConsoleColour colour, bool self_se
SetDParam(2, data);
GetString(message, strid, lastof(message));
DEBUG(desync, 1, "msg: %d; %d; %s\n", _date, _date_fract, message);
DEBUG(desync, 1, "msg: %08x; %02x; %s", _date, _date_fract, message);
IConsolePrintF(colour, "%s", message);
NetworkAddChatMessage((TextColour)colour, duration, "%s", message);
}
@ -1024,7 +1027,7 @@ static bool NetworkDoClientLoop()
if (_sync_seed_1 != _random.state[0]) {
#endif
NetworkError(STR_NETWORK_ERROR_DESYNC);
DEBUG(desync, 1, "sync_err: %d; %d\n", _date, _date_fract);
DEBUG(desync, 1, "sync_err: %08x; %02x", _date, _date_fract);
DEBUG(net, 0, "Sync error detected!");
NetworkClientError(NETWORK_RECV_STATUS_DESYNC, NetworkClientSocket::Get(0));
return false;
@ -1074,20 +1077,26 @@ void NetworkGameLoop()
if (!NetworkReceive()) return;
if (_network_server) {
/* Log the sync state to check for in-syncedness of replays. */
if (_date_fract == 0) DEBUG(desync, 1, "sync: %08x; %02x; %08x; %08x", _date, _date_fract, _random.state[0], _random.state[1]);
#ifdef DEBUG_DUMP_COMMANDS
/* Loading of the debug commands from -ddesync>=1 */
static FILE *f = FioFOpenFile("commands.log", "rb", SAVE_DIR);
static Date next_date = 0;
static uint32 next_date_fract;
static CommandPacket *cp = NULL;
if (f == NULL && next_date == 0) {
printf("Cannot open commands.log\n");
DEBUG(net, 0, "Cannot open commands.log");
next_date = 1;
}
while (f != NULL && !feof(f)) {
if (cp != NULL && _date == next_date && _date_fract == next_date_fract) {
_current_company = cp->company;
DoCommandP(cp->tile, cp->p1, cp->p2, cp->cmd, NULL, cp->text);
bool ret = DoCommandP(cp->tile, cp->p1, cp->p2, cp->cmd, NULL, cp->text);
DEBUG(net, 0, "injecting: %08x; %02x; %02x; %06x; %08x; %08x; %08x; \"%s\" (%s) -> %i", _date, _date_fract, (int)_current_company, cp->tile, cp->p1, cp->p2, cp->cmd, cp->text, GetCommandName(cp->cmd), (int)ret);
assert(ret);
free(cp);
cp = NULL;
}
@ -1096,11 +1105,41 @@ void NetworkGameLoop()
char buff[4096];
if (fgets(buff, lengthof(buff), f) == NULL) break;
if (strncmp(buff, "cmd: ", 8) != 0) continue;
cp = MallocT<CommandPacket>(1);
char *p = buff;
/* Ignore the "[date time] " part of the message */
if (*p == '[') {
p = strchr(p, ']');
if (p == NULL) break;
p += 2;
}
if (strncmp(p, "cmd: ", 5) == 0) {
cp = CallocT<CommandPacket>(1);
int company;
sscanf(&buff[8], "%d; %d; %d; %d; %d; %d; %d; %s", &next_date, &next_date_fract, &company, &cp->tile, &cp->p1, &cp->p2, &cp->cmd, cp->text);
int ret = sscanf(p + 5, "%x; %x; %x; %x; %x; %x; %x; \"%[^\"]\"", &next_date, &next_date_fract, &company, &cp->tile, &cp->p1, &cp->p2, &cp->cmd, cp->text);
/* There are 8 pieces of data to read, however the last is a
* string that might or might not exist. Ignore it if that
* string misses because in 99% of the time it's not used. */
assert(ret == 8 || ret == 7);
cp->company = (CompanyID)company;
} else if (strncmp(p, "join: ", 6) == 0) {
/* Manually insert a pause when joining; this way the client can join at the exact right time. */
int ret = sscanf(p + 6, "%x; %x", &next_date, &next_date_fract);
assert(ret == 2);
DEBUG(net, 0, "injecting pause for join at %08x:%02x; please join when paused", next_date, next_date_fract);
cp = MallocT<CommandPacket>(1);
cp->company = COMPANY_SPECTATOR;
cp->cmd = CMD_PAUSE;
cp->p1 = PM_PAUSED_NORMAL;
cp->p2 = 1;
_ddc_fastforward = false;
}
}
if (f != NULL && feof(f)) {
DEBUG(net, 0, "End of commands.log");
fclose(f);
f = NULL;
}
#endif /* DEBUG_DUMP_COMMANDS */
if (_frame_counter >= _frame_counter_max) {

View File

@ -38,6 +38,18 @@
#define NETWORK_SEND_DOUBLE_SEED
#endif /* RANDOM_DEBUG */
/**
* Helper variable to make the dedicated server go fast until the (first) join.
* Used to load the desync debug logs, i.e. for reproducing a desync.
* There's basically no need to ever enable this, unless you really know what
* you are doing, i.e. debugging a desync.
*/
#ifdef DEBUG_DUMP_COMMANDS
extern bool _ddc_fastforward;
#else
#define _ddc_fastforward (false)
#endif /* DEBUG_DUMP_COMMANDS */
enum MapPacket {
MAP_PACKET_START,
MAP_PACKET_NORMAL,

View File

@ -716,6 +716,7 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_JOIN)
strecpy(ci->client_name, name, lastof(ci->client_name));
ci->client_playas = playas;
ci->client_lang = client_lang;
DEBUG(desync, 1, "client: %08x; %02x; %02x; %04x", _date, _date_fract, (int)ci->client_playas, ci->index);
/* Make sure companies to which people try to join are not autocleaned */
if (Company::IsValidID(playas)) _network_company_states[playas].months_empty = 0;
@ -1396,6 +1397,8 @@ void NetworkUpdateClientInfo(ClientID client_id)
if (ci == NULL) return;
DEBUG(desync, 1, "client: %08x; %02x; %02x; %04x", _date, _date_fract, (int)ci->client_playas, client_id);
FOR_ALL_CLIENT_SOCKETS(cs) {
SEND_COMMAND(PACKET_SERVER_CLIENT_INFO)(cs, ci);
}

View File

@ -1110,16 +1110,18 @@ static void CheckCaches()
Vehicle *v;
FOR_ALL_VEHICLES(v) {
if (v != v->First()) continue;
if (v != v->First() || v->vehstatus & VS_CRASHED) continue;
switch (v->type) {
case VEH_ROAD: {
RoadVehicle *rv = RoadVehicle::From(v);
RoadVehicleCache cache = rv->rcache;
RoadVehicleCache cache;
memset(&cache, 0, sizeof(cache));
cache = rv->rcache;
RoadVehUpdateCache(rv);
if (memcmp(&cache, &rv->rcache, sizeof(RoadVehicleCache)) != 0) {
DEBUG(desync, 2, "cache mismatch: vehicle %i, company %i, unit number %i\n", v->index, (int)v->owner, v->unitnumber);
DEBUG(desync, 2, "cache mismatch: vehicle %i, company %i, unit number %i", v->index, (int)v->owner, v->unitnumber);
}
} break;
@ -1128,7 +1130,7 @@ static void CheckCaches()
Train *t = Train::From(v);
for (Vehicle *u = t; u != NULL; u = u->Next()) length++;
TrainCache *wagons = MallocT<TrainCache>(length);
TrainCache *wagons = CallocT<TrainCache>(length);
length = 0;
for (Train *u = t; u != NULL; u = u->Next()) wagons[length++] = u->tcache;
@ -1137,7 +1139,7 @@ static void CheckCaches()
length = 0;
for (Train *u = t; u != NULL; u = u->Next()) {
if (memcmp(&wagons[length], &u->tcache, sizeof(TrainCache)) != 0) {
DEBUG(desync, 2, "cache mismatch: vehicle %i, company %i, unit number %i, wagon %i\n", v->index, (int)v->owner, v->unitnumber, length);
DEBUG(desync, 2, "cache mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length);
}
length++;
}
@ -1147,11 +1149,13 @@ static void CheckCaches()
case VEH_AIRCRAFT: {
Aircraft *a = Aircraft::From(v);
AircraftCache cache = a->acache;
AircraftCache cache;
memset(&cache, 0, sizeof(cache));
cache = a->acache;
UpdateAircraftCache(a);
if (memcmp(&cache, &a->acache, sizeof(AircraftCache)) != 0) {
DEBUG(desync, 2, "cache mismatch: vehicle %i, company %i, unit number %i\n", v->index, (int)v->owner, v->unitnumber);
DEBUG(desync, 2, "cache mismatch: vehicle %i, company %i, unit number %i", v->index, (int)v->owner, v->unitnumber);
}
} break;
@ -1206,6 +1210,13 @@ void StateGameLoop()
} else {
CheckCaches();
if (_debug_desync_level > 2 && _date_fract == 0 && (_date & 0x1F) == 0) {
/* Save the desync savegame if needed. */
char name[MAX_PATH];
snprintf(name, lengthof(name), "dmp_cmds_%08x_%08x.sav", _settings_game.game_creation.generation_seed, _date);
SaveOrLoad(name, SL_SAVE, AUTOSAVE_DIR);
}
/* All these actions has to be done from OWNER_NONE
* for multiplayer compatibility */
CompanyID old_company = _current_company;

View File

@ -1882,7 +1882,7 @@ SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, boo
/* General tactic is to first save the game to memory, then use an available writer
* to write it to file, either in threaded mode if possible, or single-threaded */
if (mode == SL_SAVE) { // SAVE game
DEBUG(desync, 1, "save: %s\n", filename);
DEBUG(desync, 1, "save: %s", filename);
_sl.write_bytes = WriteMem;
_sl.excpt_uninit = UnInitMem;
@ -1906,7 +1906,7 @@ SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, boo
}
} else { // LOAD game
assert(mode == SL_LOAD);
DEBUG(desync, 1, "load: %s\n", filename);
DEBUG(desync, 1, "load: %s", filename);
/* Can't fseek to 0 as in tar files that is not correct */
long pos = ftell(_sl.fh);

View File

@ -300,13 +300,15 @@ void VideoDriver_Dedicated::MainLoop()
cur_ticks = GetTime();
_realtime_tick += cur_ticks - prev_cur_ticks;
if (cur_ticks >= next_tick || cur_ticks < prev_cur_ticks) {
if (cur_ticks >= next_tick || cur_ticks < prev_cur_ticks || _ddc_fastforward) {
next_tick = cur_ticks + 30;
GameLoop();
UpdateWindows();
}
CSleep(1);
/* Don't sleep when fast forwarding (for desync debugging) */
if (!_ddc_fastforward) CSleep(1);
}
}