From 27e45d96a4b32fabce0d6158b493f4ab214d878f Mon Sep 17 00:00:00 2001 From: rubidium Date: Wed, 18 Aug 2010 20:48:38 +0000 Subject: [PATCH] (svn r20547) -Change: the way order backups are performed. Now restoring an order doesn't require up to 765 commands. --- src/command.cpp | 10 +-- src/command_type.h | 2 +- src/depot.cpp | 4 +- src/depot_gui.cpp | 7 +- src/network/core/tcp_game.cpp | 2 + src/order_backup.cpp | 162 +++++++++++++++++++++------------- src/order_backup.h | 50 ++++++++--- src/order_cmd.cpp | 39 -------- src/saveload/order_sl.cpp | 60 +++++++++++++ src/station_cmd.cpp | 2 +- src/train_cmd.cpp | 6 +- src/vehicle_cmd.cpp | 21 ++++- src/vehicle_gui.cpp | 2 - 13 files changed, 237 insertions(+), 130 deletions(-) diff --git a/src/command.cpp b/src/command.cpp index 273bdd0a62..7aaaaf3431 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -88,12 +88,12 @@ CommandProc CmdSendTrainToDepot; CommandProc CmdForceTrainProceed; CommandProc CmdReverseTrainDirection; +CommandProc CmdClearOrderBackup; CommandProc CmdModifyOrder; CommandProc CmdSkipToOrder; CommandProc CmdDeleteOrder; CommandProc CmdInsertOrder; CommandProc CmdChangeServiceInt; -CommandProc CmdRestoreOrderIndex; CommandProc CmdBuildIndustry; @@ -221,8 +221,8 @@ static const Command _command_proc_table[] = { DEF_CMD(CmdBuildBuoy, CMD_AUTO), // CMD_BUILD_BUOY DEF_CMD(CmdPlantTree, CMD_AUTO), // CMD_PLANT_TREE - DEF_CMD(CmdBuildVehicle, 0), // CMD_BUILD_VEHICLE - DEF_CMD(CmdSellVehicle, 0), // CMD_SELL_VEHICLE + DEF_CMD(CmdBuildVehicle, CMD_CLIENT_ID), // CMD_BUILD_VEHICLE + DEF_CMD(CmdSellVehicle, CMD_CLIENT_ID), // CMD_SELL_VEHICLE DEF_CMD(CmdRefitVehicle, 0), // CMD_REFIT_VEHICLE DEF_CMD(CmdMoveRailVehicle, 0), // CMD_MOVE_RAIL_VEHICLE @@ -230,6 +230,7 @@ static const Command _command_proc_table[] = { DEF_CMD(CmdForceTrainProceed, 0), // CMD_FORCE_TRAIN_PROCEED DEF_CMD(CmdReverseTrainDirection, 0), // CMD_REVERSE_TRAIN_DIRECTION + DEF_CMD(CmdClearOrderBackup, CMD_CLIENT_ID), // CMD_CLEAR_ORDER_BACKUP DEF_CMD(CmdModifyOrder, 0), // CMD_MODIFY_ORDER DEF_CMD(CmdSkipToOrder, 0), // CMD_SKIP_TO_ORDER DEF_CMD(CmdDeleteOrder, 0), // CMD_DELETE_ORDER @@ -288,7 +289,6 @@ static const Command _command_proc_table[] = { 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 - DEF_CMD(CmdRestoreOrderIndex, 0), // CMD_RESTORE_ORDER_INDEX DEF_CMD(CmdBuildLock, CMD_AUTO), // CMD_BUILD_LOCK DEF_CMD(CmdBuildSignalTrack, CMD_AUTO), // CMD_BUILD_SIGNAL_TRACK @@ -502,7 +502,7 @@ bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallbac #ifdef ENABLE_NETWORK /* Only set p2 when the command does not come from the network. */ - if (!(cmd & CMD_NETWORK_COMMAND) && GetCommandFlags(cmd) & CMD_CLIENT_ID) p2 = CLIENT_ID_SERVER; + if (!(cmd & CMD_NETWORK_COMMAND) && GetCommandFlags(cmd) & CMD_CLIENT_ID && p2 == 0) p2 = CLIENT_ID_SERVER; #endif CommandCost res = DoCommandPInternal(tile, p1, p2, cmd, callback, text, my_cmd, estimate_only); diff --git a/src/command_type.h b/src/command_type.h index 5d2d892fef..93e1497774 100644 --- a/src/command_type.h +++ b/src/command_type.h @@ -186,6 +186,7 @@ enum Commands { CMD_FORCE_TRAIN_PROCEED, ///< proceed a train to pass a red signal CMD_REVERSE_TRAIN_DIRECTION, ///< turn a train around + CMD_CLEAR_ORDER_BACKUP, ///< clear the order backup of a given user/tile CMD_MODIFY_ORDER, ///< modify an order (like set full-load) CMD_SKIP_TO_ORDER, ///< skip an order to the next of specific one CMD_DELETE_ORDER, ///< delete an order @@ -242,7 +243,6 @@ enum Commands { CMD_COMPANY_CTRL, ///< used in multiplayer to create a new companies etc. CMD_LEVEL_LAND, ///< level land - CMD_RESTORE_ORDER_INDEX, ///< restore vehicle order-index and service interval CMD_BUILD_LOCK, ///< build a lock CMD_BUILD_SIGNAL_TRACK, ///< add signals along a track (by dragging) diff --git a/src/depot.cpp b/src/depot.cpp index f53a51ff07..039ab5b34a 100644 --- a/src/depot.cpp +++ b/src/depot.cpp @@ -27,12 +27,14 @@ Depot::~Depot() { if (CleaningPool()) return; + /* Clear the order backup. */ + OrderBackup::Reset(this->xy, false); + /* Clear the depot from all order-lists */ RemoveOrderFromAllVehicles(OT_GOTO_DEPOT, this->index); /* Delete the depot-window */ DeleteWindowById(WC_VEHICLE_DEPOT, this->xy); - OrderBackup::Reset(this->xy); /* Delete the depot list */ WindowNumber wno = (this->index << 16) | VLW_DEPOT_LIST | GetTileOwner(this->xy); diff --git a/src/depot_gui.cpp b/src/depot_gui.cpp index e9ba9143fe..199971ac28 100644 --- a/src/depot_gui.cpp +++ b/src/depot_gui.cpp @@ -976,12 +976,7 @@ struct DepotWindow : Window { this->SetDirty(); int sell_cmd = (v->type == VEH_TRAIN && (widget == DEPOT_WIDGET_SELL_CHAIN || _ctrl_pressed)) ? 1 : 0; - - bool is_engine = (v->type != VEH_TRAIN || Train::From(v)->IsFrontEngine()); - - if (is_engine) OrderBackup::Backup(v); - - if (!DoCommandP(v->tile, v->index | sell_cmd << 16, 0, GetCmdSellVeh(v->type)) && is_engine) OrderBackup::Reset(this->window_number); + DoCommandP(v->tile, v->index | sell_cmd << 16 | MAKE_ORDER_BACKUP_FLAG, 0, GetCmdSellVeh(v->type)); break; } diff --git a/src/network/core/tcp_game.cpp b/src/network/core/tcp_game.cpp index 66a1b6f812..494c12a87e 100644 --- a/src/network/core/tcp_game.cpp +++ b/src/network/core/tcp_game.cpp @@ -18,6 +18,7 @@ #include "../network.h" #include "../network_internal.h" #include "../../core/pool_func.hpp" +#include "../../order_backup.h" #include "table/strings.h" @@ -37,6 +38,7 @@ NetworkClientSocket::NetworkClientSocket(ClientID client_id) NetworkClientSocket::~NetworkClientSocket() { if (_redirect_console_to_client == this->client_id) _redirect_console_to_client = INVALID_CLIENT_ID; + if (_network_server) OrderBackup::ResetUser(this->client_id); this->client_id = INVALID_CLIENT_ID; this->status = STATUS_INACTIVE; } diff --git a/src/order_backup.cpp b/src/order_backup.cpp index 1518b2bde2..0d54d5337f 100644 --- a/src/order_backup.cpp +++ b/src/order_backup.cpp @@ -12,6 +12,8 @@ #include "stdafx.h" #include "command_func.h" #include "core/pool_func.hpp" +#include "network/network.h" +#include "network/network_func.h" #include "order_backup.h" #include "order_base.h" #include "vehicle_base.h" @@ -23,11 +25,20 @@ INSTANTIATE_POOL_METHODS(OrderBackup) OrderBackup::~OrderBackup() { free(this->name); - free(this->orders); + + if (CleaningPool()) return; + + Order *o = this->orders; + while (o != NULL) { + Order *next = o->next; + delete o; + o = next; + } } -OrderBackup::OrderBackup(const Vehicle *v) +OrderBackup::OrderBackup(const Vehicle *v, uint32 user) { + this->user = user; this->tile = v->tile; this->orderindex = v->cur_order_index; this->group = v->group_id; @@ -40,99 +51,128 @@ OrderBackup::OrderBackup(const Vehicle *v) this->clone = (v->FirstShared() == v) ? v->NextShared() : v->FirstShared(); } else { /* Else copy the orders */ + Order **tail = &this->orders; /* Count the number of orders */ - uint cnt = 0; const Order *order; - FOR_VEHICLE_ORDERS(v, order) cnt++; - - /* Allocate memory for the orders plus an end-of-orders marker */ - this->orders = MallocT(cnt + 1); - - Order *dest = this->orders; - - /* Copy the orders */ FOR_VEHICLE_ORDERS(v, order) { - memcpy(dest, order, sizeof(Order)); - dest++; + Order *copy = new Order(); + copy->AssignOrder(*order); + *tail = copy; + tail = ©->next; } - /* End the list with an empty order */ - dest->Free(); } } -void OrderBackup::DoRestore(const Vehicle *v) +void OrderBackup::DoRestore(Vehicle *v) { /* If we have a custom name, process that */ - if (this->name != NULL) DoCommandP(0, v->index, 0, CMD_RENAME_VEHICLE, NULL, this->name); + v->name = this->name; + this->name = NULL; /* If we had shared orders, recover that */ if (this->clone != NULL) { - DoCommandP(0, v->index | (this->clone->index << 16), CO_SHARE, CMD_CLONE_ORDER); - } else if (this->orders != NULL) { - - /* CMD_NO_TEST_IF_IN_NETWORK is used here, because CMD_INSERT_ORDER checks if the - * order number is one more than the current amount of orders, and because - * in network the commands are queued before send, the second insert always - * fails in test mode. By bypassing the test-mode, that no longer is a problem. */ - for (uint i = 0; !this->orders[i].IsType(OT_NOTHING); i++) { - Order o = this->orders[i]; - /* Conditional orders need to have their destination to be valid on insertion. */ - if (o.IsType(OT_CONDITIONAL)) o.SetConditionSkipToOrder(0); - - if (!DoCommandP(0, v->index + (i << 16), o.Pack(), - CMD_INSERT_ORDER | CMD_NO_TEST_IF_IN_NETWORK)) { - break; - } - - /* Copy timetable if enabled */ - if (_settings_game.order.timetabling && !DoCommandP(0, v->index | (i << 16) | (1 << 25), - o.wait_time << 16 | o.travel_time, - CMD_CHANGE_TIMETABLE | CMD_NO_TEST_IF_IN_NETWORK)) { - break; - } - } - - /* Fix the conditional orders' destination. */ - for (uint i = 0; !this->orders[i].IsType(OT_NOTHING); i++) { - if (!this->orders[i].IsType(OT_CONDITIONAL)) continue; - - if (!DoCommandP(0, v->index + (i << 16), MOF_LOAD | (this->orders[i].GetConditionSkipToOrder() << 4), - CMD_MODIFY_ORDER | CMD_NO_TEST_IF_IN_NETWORK)) { - break; - } - } + DoCommand(0, v->index | (this->clone->index << 16), CO_SHARE, DC_EXEC, CMD_CLONE_ORDER); + } else if (this->orders != NULL && OrderList::CanAllocateItem()) { + v->orders.list = new OrderList(this->orders, v); + this->orders = NULL; } - /* Restore vehicle order-index and service interval */ - DoCommandP(0, v->index, this->orderindex | (this->service_interval << 16), CMD_RESTORE_ORDER_INDEX); + uint num_orders = v->GetNumOrders(); + if (num_orders != 0) v->cur_order_index = this->orderindex % num_orders; + v->service_interval = this->service_interval; /* Restore vehicle group */ - DoCommandP(0, this->group, v->index, CMD_ADD_VEHICLE_GROUP); + DoCommand(0, this->group, v->index, DC_EXEC, CMD_ADD_VEHICLE_GROUP); } -/* static */ void OrderBackup::Backup(const Vehicle *v) +/* static */ void OrderBackup::Backup(const Vehicle *v, uint32 user) { - OrderBackup::Reset(); - new OrderBackup(v); + /* Don't use reset as that broadcasts over the network to reset the variable, + * which is what we are doing at the moment. */ + OrderBackup *ob; + FOR_ALL_ORDER_BACKUPS(ob) { + if (ob->user == user) delete ob; + } + new OrderBackup(v, user); } -/* static */ void OrderBackup::Restore(const Vehicle *v) +/* static */ void OrderBackup::Restore(Vehicle *v, uint32 user) { OrderBackup *ob; FOR_ALL_ORDER_BACKUPS(ob) { - if (v->tile != ob->tile) continue; + if (v->tile != ob->tile || ob->user != user) continue; ob->DoRestore(v); delete ob; } } -/* static */ void OrderBackup::Reset(TileIndex t) +/* static */ void OrderBackup::ResetOfUser(TileIndex tile, uint32 user) +{ + OrderBackup *ob; + FOR_ALL_ORDER_BACKUPS(ob) { + if (ob->user == user && (ob->tile == tile || tile == INVALID_TILE)) delete ob; + } +} + +/** + * Clear an OrderBackup + * @param tile Tile related to the to-be-cleared OrderBackup. + * @param flags For command. + * @param p1 Unused. + * @param p2 User that had the OrderBackup. + * @param text Unused. + * @return The cost of this operation or an error. + */ +CommandCost CmdClearOrderBackup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { + /* No need to check anything. If the tile or user don't exist we just ignore it. */ + if (flags & DC_EXEC) OrderBackup::ResetOfUser(tile == 0 ? INVALID_TILE : tile, p2); + + return CommandCost(); +} + +/* static */ void OrderBackup::ResetUser(uint32 user) +{ + assert(_network_server); + OrderBackup *ob; FOR_ALL_ORDER_BACKUPS(ob) { - if (t == INVALID_TILE || t == ob->tile) delete ob; + /* If it's not an backup of us, so ignore it. */ + if (ob->user != user) continue; + + DoCommandP(0, 0, user, CMD_CLEAR_ORDER_BACKUP); + return; + } +} + +/* static */ void OrderBackup::Reset(TileIndex t, bool from_gui) +{ + /* The user has CLIENT_ID_SERVER as default when network play is not active, + * but compiled it. A network client has its own variable for the unique + * client/user identifier. Finally if networking isn't compiled in the + * default is just plain and simple: 0. */ +#ifdef ENABLE_NETWORK + uint32 user = _networking && !_network_server ? _network_own_client_id : CLIENT_ID_SERVER; +#else + uint32 user = 0; +#endif + + OrderBackup *ob; + FOR_ALL_ORDER_BACKUPS(ob) { + /* If it's not an backup of us, so ignore it. */ + if (ob->user != user) continue; + /* If it's not for our chosen tile either, ignore it. */ + if (t != INVALID_TILE && t != ob->tile) continue; + + if (from_gui) { + DoCommandP(ob->tile, 0, 0, CMD_CLEAR_ORDER_BACKUP); + } else { + /* The command came from the game logic, i.e. the clearing of a tile. + * In that case we have no need to actually sync this, just do it. */ + delete ob; + } } } diff --git a/src/order_backup.h b/src/order_backup.h index 3d4f81f92f..4fa42b3263 100644 --- a/src/order_backup.h +++ b/src/order_backup.h @@ -28,12 +28,18 @@ typedef Pool OrderBackupPool; /** The pool with order backups. */ extern OrderBackupPool _order_backup_pool; +/** Flag to pass to the vehicle construction command when an order should be preserved. */ +static const uint32 MAKE_ORDER_BACKUP_FLAG = 1 << 31; + /** * Data for backing up an order of a vehicle so it can be * restored after a vehicle is rebuilt in the same depot. */ struct OrderBackup : OrderBackupPool::PoolItem<&_order_backup_pool> { private: + friend const struct SaveLoad *GetOrderBackupDescription(); ///< Saving and loading of order backups. + friend void Load_BKOR(); ///< Creating empty orders upon savegame loading. + uint32 user; ///< The user that requested the backup. TileIndex tile; ///< Tile of the depot where the order was changed. GroupID group; ///< The group the vehicle was part of. uint16 service_interval; ///< The service interval of the vehicle. @@ -43,17 +49,21 @@ private: VehicleOrderID orderindex; ///< The order-index the vehicle had. Order *orders; ///< The actual orders if the vehicle was not a clone. + /** Creation for savegame restoration. */ + OrderBackup() {} + /** * Create an order backup for the given vehicle. - * @param v The vehicle to make a backup of. + * @param v The vehicle to make a backup of. + * @param user The user that is requesting the backup. */ - OrderBackup(const Vehicle *v); + OrderBackup(const Vehicle *v, uint32 user); /** * Restore the data of this order to the given vehicle. * @param v The vehicle to restore to. */ - void DoRestore(const Vehicle *v); + void DoRestore(Vehicle *v); public: /** Free everything that is allocated. */ @@ -61,23 +71,43 @@ public: /** * Create an order backup for the given vehicle. - * @param v The vehicle to make a backup of. + * @param v The vehicle to make a backup of. + * @param user The user that is requesting the backup. * @note Will automatically remove any previous backups of this user. */ - static void Backup(const Vehicle *v); + static void Backup(const Vehicle *v, uint32 user); /** * Restore the data of this order to the given vehicle. - * @param v The vehicle to restore to. + * @param v The vehicle to restore to. + * @param user The user that built the vehicle, thus wants to restore. * @note After restoration the backup will automatically be removed. */ - static void Restore(const Vehicle *v); + static void Restore(Vehicle *v, uint32 user); + + /** + * Reset an OrderBackup given a tile and user. + * @param tile The tile associated with the OrderBackup. + * @param user The user associated with the OrderBackup. + * @note Must not be used from the GUI! + */ + static void ResetOfUser(TileIndex tile, uint32 user); + + /** + * Reset an user's OrderBackup if needed. + * @param user The user associated with the OrderBackup. + * @pre _network_server. + * @note Must not be used from a command. + */ + static void ResetUser(uint32 user); /** - * Reset the OrderBackups. - * @param tile The tile of the order backup. + * Reset the OrderBackups from GUI/game logic. + * @param tile The tile of the order backup. + * @param from_gui Whether the call came from the GUI, i.e. whether + * it must be synced over the network. */ - static void Reset(TileIndex tile = INVALID_TILE); + static void Reset(TileIndex tile = INVALID_TILE, bool from_gui = true); /** * Clear the group of all backups having this group ID. diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index 2a3e998f8c..050ac366b8 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -1328,45 +1328,6 @@ CommandCost CmdOrderRefit(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 return CommandCost(); } -/** - * Restore the current order-index of a vehicle and sets service-interval. - * @param tile unused - * @param flags operation to perform - * @param p1 the ID of the vehicle - * @param p2 various bistuffed elements - * - p2 = (bit 0-15) - current order-index (p2 & 0xFFFF) - * - p2 = (bit 16-31) - service interval (p2 >> 16) - * @param text unused - * @return the cost of this operation or an error - * @todo Unfortunately you cannot safely restore the unitnumber or the old vehicle - * as far as I can see. We can store it in BackuppedOrders, and restore it, but - * but we have no way of seeing it has been tampered with or not, as we have no - * legit way of knowing what that ID was.@n - * If we do want to backup/restore it, just add UnitID uid to BackuppedOrders, and - * restore it as parameter 'y' (ugly hack I know) for example. "v->unitnumber = y;" - */ -CommandCost CmdRestoreOrderIndex(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) -{ - VehicleOrderID cur_ord = GB(p2, 0, 16); - uint16 serv_int = GB(p2, 16, 16); - - Vehicle *v = Vehicle::GetIfValid(p1); - /* Check the vehicle type and ownership, and if the service interval and order are in range */ - if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR; - - CommandCost ret = CheckOwnership(v->owner); - if (ret.Failed()) return ret; - - if (serv_int != GetServiceIntervalClamped(serv_int, v->owner) || cur_ord >= v->GetNumOrders()) return CMD_ERROR; - - if (flags & DC_EXEC) { - v->cur_order_index = cur_ord; - v->service_interval = serv_int; - } - - return CommandCost(); -} - /** * diff --git a/src/saveload/order_sl.cpp b/src/saveload/order_sl.cpp index 71bb09bd04..a8459a6529 100644 --- a/src/saveload/order_sl.cpp +++ b/src/saveload/order_sl.cpp @@ -11,7 +11,9 @@ #include "../stdafx.h" #include "../order_base.h" +#include "../order_backup.h" #include "../settings_type.h" +#include "../network/network.h" #include "saveload.h" @@ -235,7 +237,65 @@ static void Ptrs_ORDL() } } +const SaveLoad *GetOrderBackupDescription() +{ + static const SaveLoad _order_backup_desc[] = { + SLE_VAR(OrderBackup, user, SLE_UINT32), + SLE_VAR(OrderBackup, tile, SLE_UINT32), + SLE_VAR(OrderBackup, group, SLE_UINT16), + SLE_VAR(OrderBackup, service_interval, SLE_INT32), + SLE_STR(OrderBackup, name, SLE_STR, 0), + SLE_VAR(OrderBackup, clone, SLE_UINT16), + SLE_VAR(OrderBackup, orderindex, SLE_UINT8), + SLE_REF(OrderBackup, orders, REF_ORDER), + SLE_END() + }; + + return _order_backup_desc; +} + +static void Save_BKOR() +{ + /* We only save this when we're a network server + * as we want this information on our clients. For + * normal games this information isn't needed. */ + if (!_networking || !_network_server) return; + + OrderBackup *ob; + FOR_ALL_ORDER_BACKUPS(ob) { + SlSetArrayIndex(ob->index); + SlObject(ob, GetOrderBackupDescription()); + } +} + +void Load_BKOR() +{ + int index; + + while ((index = SlIterateArray()) != -1) { + /* set num_orders to 0 so it's a valid OrderList */ + OrderBackup *ob = new (index) OrderBackup(); + SlObject(ob, GetOrderBackupDescription()); + } + + /* If we are a network server, then we just loaded + * a previously saved-by-server savegame. There are + * no clients with a backup anymore, so clear it. */ + if (_networking && _network_server) { + _order_backup_pool.CleanPool(); + } +} + +static void Ptrs_BKOR() +{ + OrderBackup *ob; + FOR_ALL_ORDER_BACKUPS(ob) { + SlObject(ob, GetOrderBackupDescription()); + } +} + extern const ChunkHandler _order_chunk_handlers[] = { + { 'BKOR', Save_BKOR, Load_BKOR, Ptrs_BKOR, NULL, CH_ARRAY}, { 'ORDR', Save_ORDR, Load_ORDR, Ptrs_ORDR, NULL, CH_ARRAY}, { 'ORDL', Save_ORDL, Load_ORDL, Ptrs_ORDL, NULL, CH_ARRAY | CH_LAST}, }; diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index aa77f2327b..26a6cbd48f 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -2288,7 +2288,7 @@ static CommandCost RemoveAirport(TileIndex tile, DoCommandFlag flags) cost.AddCost(_price[PR_CLEAR_STATION_AIRPORT]); if (flags & DC_EXEC) { - if (IsHangarTile(tile_cur)) OrderBackup::Reset(tile_cur); + if (IsHangarTile(tile_cur)) OrderBackup::Reset(tile_cur, false); DeleteAnimatedTile(tile_cur); DoClearSquare(tile_cur); DeleteNewGRFInspectWindow(GSF_AIRPORTTILES, tile_cur); diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 420aa1b206..ece8cb5cf5 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -41,6 +41,7 @@ #include "engine_base.h" #include "engine_func.h" #include "newgrf.h" +#include "order_backup.h" #include "table/strings.h" #include "table/train_cmd.h" @@ -1325,9 +1326,10 @@ CommandCost CmdMoveRailVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, u * - data = 0: only sell the single dragged wagon/engine (and any belonging rear-engines) * - data = 1: sell the vehicle and all vehicles following it in the chain * if the wagon is dragged, don't delete the possibly belonging rear-engine to some front + * @param user the user for the order backup. * @return the cost of this operation or an error */ -CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *t, uint16 data) +CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *t, uint16 data, uint32 user) { /* Check if we deleted a vehicle window */ Window *w = NULL; @@ -1381,6 +1383,8 @@ CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *t, uint16 data) /* If we deleted a window then open a new one for the 'new' train */ if (IsLocalCompany() && w != NULL) ShowVehicleViewWindow(new_head); + } else if (v->IsPrimaryVehicle() && data & (MAKE_ORDER_BACKUP_FLAG >> 16)) { + OrderBackup::Backup(v, user); } /* We need to update the information about the train. */ diff --git a/src/vehicle_cmd.cpp b/src/vehicle_cmd.cpp index 0a2c255f62..45b6e36749 100644 --- a/src/vehicle_cmd.cpp +++ b/src/vehicle_cmd.cpp @@ -32,6 +32,7 @@ #include "articulated_vehicles.h" #include "autoreplace_gui.h" #include "company_base.h" +#include "order_backup.h" #include "table/strings.h" @@ -144,12 +145,14 @@ CommandCost CmdBuildVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint } Company::Get(_current_company)->num_engines[eid]++; + + if (v->IsPrimaryVehicle()) OrderBackup::Restore(v, p2); } return value; } -CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *v, uint16 data); +CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *v, uint16 data, uint32 user); /** * Sell a vehicle. @@ -157,7 +160,8 @@ CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *v, uint16 data); * @param flags for command. * @param p1 various bitstuffed data. * bits 0-15: vehicle ID being sold. - * bits 16-31: vehicle type specific bits passed on to the vehicle build functions. + * bits 16-30: vehicle type specific bits passed on to the vehicle build functions. + * bit 31: make a backup of the vehicle's order (if an engine). * @param p2 unused. * @param text unused. * @return the cost of this operation or an error. @@ -176,12 +180,23 @@ CommandCost CmdSellVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 if (!front->IsStoppedInDepot()) return_cmd_error(STR_ERROR_TRAIN_MUST_BE_STOPPED_INSIDE_DEPOT + front->type); + /* Can we actually make the order backup, i.e. are there enough orders? */ + if (p1 & MAKE_ORDER_BACKUP_FLAG && + front->orders.list != NULL && + !front->orders.list->IsShared() && + !Order::CanAllocateItem(front->orders.list->GetNumOrders())) { + /* Only happens in exceptional cases when there aren't enough orders anyhow. + * Thus it should be safe to just drop the orders in that case. */ + p1 &= ~MAKE_ORDER_BACKUP_FLAG; + } + if (v->type == VEH_TRAIN) { - ret = CmdSellRailWagon(flags, v, GB(p1, 16, 16)); + ret = CmdSellRailWagon(flags, v, GB(p1, 16, 16), p2); } else { ret = CommandCost(EXPENSES_NEW_VEHICLES, -front->value); if (flags & DC_EXEC) { + if (v->IsPrimaryVehicle() && p1 & MAKE_ORDER_BACKUP_FLAG) OrderBackup::Backup(v, p2); delete front; } } diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index a38a914923..ad954db7dc 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -44,7 +44,6 @@ #include "engine_func.h" #include "newgrf.h" #include "station_base.h" -#include "order_backup.h" #include "table/sprites.h" #include "table/strings.h" @@ -2373,6 +2372,5 @@ void CcBuildPrimaryVehicle(const CommandCost &result, TileIndex tile, uint32 p1, if (result.Failed()) return; const Vehicle *v = Vehicle::Get(_new_vehicle_id); - OrderBackup::Restore(v); ShowVehicleViewWindow(v); }