Fix: Don't allow right-click to close world generation progress window. (#13084)
[openttd-github.git] / src / order_backup.cpp
blobf696d8435dea594de21e607013018696a0ee81e9
1 /*
2 * This file is part of OpenTTD.
3 * 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.
4 * 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.
5 * 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/>.
6 */
8 /** @file order_backup.cpp Handling of order backups. */
10 #include "stdafx.h"
11 #include "command_func.h"
12 #include "core/pool_func.hpp"
13 #include "network/network.h"
14 #include "network/network_func.h"
15 #include "order_backup.h"
16 #include "vehicle_base.h"
17 #include "window_func.h"
18 #include "station_map.h"
19 #include "order_cmd.h"
20 #include "group_cmd.h"
21 #include "vehicle_func.h"
23 #include "safeguards.h"
25 OrderBackupPool _order_backup_pool("BackupOrder");
26 INSTANTIATE_POOL_METHODS(OrderBackup)
28 /** Free everything that is allocated. */
29 OrderBackup::~OrderBackup()
31 if (CleaningPool()) return;
33 Order *o = this->orders;
34 while (o != nullptr) {
35 Order *next = o->next;
36 delete o;
37 o = next;
41 /**
42 * Create an order backup for the given vehicle.
43 * @param v The vehicle to make a backup of.
44 * @param user The user that is requesting the backup.
46 OrderBackup::OrderBackup(const Vehicle *v, uint32_t user)
48 this->user = user;
49 this->tile = v->tile;
50 this->group = v->group_id;
52 this->CopyConsistPropertiesFrom(v);
54 /* If we have shared orders, store the vehicle we share the order with. */
55 if (v->IsOrderListShared()) {
56 this->clone = (v->FirstShared() == v) ? v->NextShared() : v->FirstShared();
57 } else {
58 /* Else copy the orders */
59 Order **tail = &this->orders;
61 /* Count the number of orders */
62 for (const Order *order : v->Orders()) {
63 Order *copy = new Order();
64 copy->AssignOrder(*order);
65 *tail = copy;
66 tail = &copy->next;
71 /**
72 * Restore the data of this order to the given vehicle.
73 * @param v The vehicle to restore to.
75 void OrderBackup::DoRestore(Vehicle *v)
77 /* If we had shared orders, recover that */
78 if (this->clone != nullptr) {
79 Command<CMD_CLONE_ORDER>::Do(DC_EXEC, CO_SHARE, v->index, this->clone->index);
80 } else if (this->orders != nullptr && OrderList::CanAllocateItem()) {
81 v->orders = new OrderList(this->orders, v);
82 this->orders = nullptr;
83 /* Make sure buoys/oil rigs are updated in the station list. */
84 InvalidateWindowClassesData(WC_STATION_LIST, 0);
87 /* Remove backed up name if it's no longer unique. */
88 if (!IsUniqueVehicleName(this->name)) this->name.clear();
90 v->CopyConsistPropertiesFrom(this);
92 /* Make sure orders are in range */
93 v->UpdateRealOrderIndex();
94 if (v->cur_implicit_order_index >= v->GetNumOrders()) v->cur_implicit_order_index = v->cur_real_order_index;
96 /* Restore vehicle group */
97 Command<CMD_ADD_VEHICLE_GROUP>::Do(DC_EXEC, this->group, v->index, false, VehicleListIdentifier{});
101 * Create an order backup for the given vehicle.
102 * @param v The vehicle to make a backup of.
103 * @param user The user that is requesting the backup.
104 * @note Will automatically remove any previous backups of this user.
106 /* static */ void OrderBackup::Backup(const Vehicle *v, uint32_t user)
108 /* Don't use reset as that broadcasts over the network to reset the variable,
109 * which is what we are doing at the moment. */
110 for (OrderBackup *ob : OrderBackup::Iterate()) {
111 if (ob->user == user) delete ob;
113 if (OrderBackup::CanAllocateItem()) {
114 new OrderBackup(v, user);
119 * Restore the data of this order to the given vehicle.
120 * @param v The vehicle to restore to.
121 * @param user The user that built the vehicle, thus wants to restore.
122 * @note After restoration the backup will automatically be removed.
124 /* static */ void OrderBackup::Restore(Vehicle *v, uint32_t user)
126 for (OrderBackup *ob : OrderBackup::Iterate()) {
127 if (v->tile != ob->tile || ob->user != user) continue;
129 ob->DoRestore(v);
130 delete ob;
135 * Reset an OrderBackup given a tile and user.
136 * @param tile The tile associated with the OrderBackup.
137 * @param user The user associated with the OrderBackup.
138 * @note Must not be used from the GUI!
140 /* static */ void OrderBackup::ResetOfUser(TileIndex tile, uint32_t user)
142 for (OrderBackup *ob : OrderBackup::Iterate()) {
143 if (ob->user == user && (ob->tile == tile || tile == INVALID_TILE)) delete ob;
148 * Clear an OrderBackup
149 * @param flags For command.
150 * @param tile Tile related to the to-be-cleared OrderBackup.
151 * @param user_id User that had the OrderBackup.
152 * @return The cost of this operation or an error.
154 CommandCost CmdClearOrderBackup(DoCommandFlag flags, TileIndex tile, ClientID user_id)
156 /* No need to check anything. If the tile or user don't exist we just ignore it. */
157 if (flags & DC_EXEC) OrderBackup::ResetOfUser(tile == 0 ? INVALID_TILE : tile, user_id);
159 return CommandCost();
163 * Reset an user's OrderBackup if needed.
164 * @param user The user associated with the OrderBackup.
165 * @pre _network_server.
166 * @note Must not be used from a command.
168 /* static */ void OrderBackup::ResetUser(uint32_t user)
170 assert(_network_server);
172 for (OrderBackup *ob : OrderBackup::Iterate()) {
173 /* If it's not a backup of us, ignore it. */
174 if (ob->user != user) continue;
176 Command<CMD_CLEAR_ORDER_BACKUP>::Post(0, static_cast<ClientID>(user));
177 return;
182 * Reset the OrderBackups from GUI/game logic.
183 * @param t The tile of the order backup.
184 * @param from_gui Whether the call came from the GUI, i.e. whether
185 * it must be synced over the network.
187 /* static */ void OrderBackup::Reset(TileIndex t, bool from_gui)
189 /* The user has CLIENT_ID_SERVER as default when network play is not active,
190 * but compiled it. A network client has its own variable for the unique
191 * client/user identifier. Finally if networking isn't compiled in the
192 * default is just plain and simple: 0. */
193 uint32_t user = _networking && !_network_server ? _network_own_client_id : CLIENT_ID_SERVER;
195 for (OrderBackup *ob : OrderBackup::Iterate()) {
196 /* If this is a GUI action, and it's not a backup of us, ignore it. */
197 if (from_gui && ob->user != user) continue;
198 /* If it's not for our chosen tile either, ignore it. */
199 if (t != INVALID_TILE && t != ob->tile) continue;
201 if (from_gui) {
202 /* We need to circumvent the "prevention" from this command being executed
203 * while the game is paused, so use the internal method. Nor do we want
204 * this command to get its cost estimated when shift is pressed. */
205 Command<CMD_CLEAR_ORDER_BACKUP>::Unsafe<CommandCallback>(STR_NULL, nullptr, true, false, ob->tile, CommandTraits<CMD_CLEAR_ORDER_BACKUP>::Args{ ob->tile, static_cast<ClientID>(user) });
206 } else {
207 /* The command came from the game logic, i.e. the clearing of a tile.
208 * In that case we have no need to actually sync this, just do it. */
209 delete ob;
215 * Clear the group of all backups having this group ID.
216 * @param group The group to clear.
218 /* static */ void OrderBackup::ClearGroup(GroupID group)
220 for (OrderBackup *ob : OrderBackup::Iterate()) {
221 if (ob->group == group) ob->group = DEFAULT_GROUP;
226 * Clear/update the (clone) vehicle from an order backup.
227 * @param v The vehicle to clear.
228 * @pre v != nullptr
229 * @note If it is not possible to set another vehicle as clone
230 * "example", then this backed up order will be removed.
232 /* static */ void OrderBackup::ClearVehicle(const Vehicle *v)
234 assert(v != nullptr);
235 for (OrderBackup *ob : OrderBackup::Iterate()) {
236 if (ob->clone == v) {
237 /* Get another item in the shared list. */
238 ob->clone = (v->FirstShared() == v) ? v->NextShared() : v->FirstShared();
239 /* But if that isn't there, remove it. */
240 if (ob->clone == nullptr) delete ob;
246 * Removes an order from all vehicles. Triggers when, say, a station is removed.
247 * @param type The type of the order (OT_GOTO_[STATION|DEPOT|WAYPOINT]).
248 * @param destination The destination. Can be a StationID, DepotID or WaypointID.
249 * @param hangar Only used for airports in the destination.
250 * When false, remove airport and hangar orders.
251 * When true, remove either airport or hangar order.
253 /* static */ void OrderBackup::RemoveOrder(OrderType type, DestinationID destination, bool hangar)
255 for (OrderBackup *ob : OrderBackup::Iterate()) {
256 for (Order *order = ob->orders; order != nullptr; order = order->next) {
257 OrderType ot = order->GetType();
258 if (ot == OT_GOTO_DEPOT && (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) continue;
259 if (ot == OT_GOTO_DEPOT && hangar && !IsHangarTile(ob->tile)) continue; // Not an aircraft? Can't have a hangar order.
260 if (ot == OT_IMPLICIT || (IsHangarTile(ob->tile) && ot == OT_GOTO_DEPOT && !hangar)) ot = OT_GOTO_STATION;
261 if (ot == type && order->GetDestination() == destination) {
262 /* Remove the order backup! If a station/depot gets removed, we can't/shouldn't restore those broken orders. */
263 delete ob;
264 break;