OpenTTD

- Main Page
- Related Pages
- Modules
- Namespaces
- Data Structures
- Files

- File List
- Globals

order_backup.cpp
Go to the documentation of this file.
1 /* $Id: order_backup.cpp 26482 2014-04-23 20:13:33Z rubidium $ */
2
3 /*
4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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/>.
8 */
9
12 #include "stdafx.h"
13 #include "command_func.h"
14 #include "core/pool_func.hpp"
15 #include "network/network.h"
16 #include "network/network_func.h"
17 #include "order_backup.h"
18 #include "vehicle_base.h"
19 #include "window_func.h"
20 #include "station_map.h"
21
22 #include "safeguards.h"
23
24 OrderBackupPool _order_backup_pool("BackupOrder");
25 INSTANTIATE_POOL_METHODS(OrderBackup)
26
27
28 OrderBackup::~OrderBackup()
29 {
30 if (CleaningPool()) return;
31
32 Order *o = this->orders;
33 while (o != NULL) {
34 Order *next = o->next;
35 delete o;
36 o = next;
37 }
38 }
39
45 OrderBackup::OrderBackup(const Vehicle *v, uint32 user)
46 {
47 this->user = user;
48 this->tile = v->tile;
49 this->group = v->group_id;
50
51 this->CopyConsistPropertiesFrom(v);
52
53 /* If we have shared orders, store the vehicle we share the order with. */
54 if (v->IsOrderListShared()) {
55 this->clone = (v->FirstShared() == v) ? v->NextShared() : v->FirstShared();
56 } else {
57 /* Else copy the orders */
58 Order **tail = &this->orders;
59
60 /* Count the number of orders */
61 const Order *order;
62 FOR_VEHICLE_ORDERS(v, order) {
63 Order *copy = new Order();
64 copy->AssignOrder(*order);
65 *tail = copy;
66 tail = &copy->next;
67 }
68 }
69 }
70
75 void OrderBackup::DoRestore(Vehicle *v)
76 {
77 /* If we had shared orders, recover that */
78 if (this->clone != NULL) {
79 DoCommand(0, v->index | CO_SHARE << 30, this->clone->index, DC_EXEC, CMD_CLONE_ORDER);
80 } else if (this->orders != NULL && OrderList::CanAllocateItem()) {
81 v->orders.list = new OrderList(this->orders, v);
82 this->orders = NULL;
83 /* Make sure buoys/oil rigs are updated in the station list. */
84 InvalidateWindowClassesData(WC_STATION_LIST, 0);
85 }
86
87 v->CopyConsistPropertiesFrom(this);
88
89 /* Make sure orders are in range */
90 v->UpdateRealOrderIndex();
91 if (v->cur_implicit_order_index >= v->GetNumOrders()) v->cur_implicit_order_index = v->cur_real_order_index;
92
93 /* Restore vehicle group */
94 DoCommand(0, this->group, v->index, DC_EXEC, CMD_ADD_VEHICLE_GROUP);
95 }
96
103 /* static */ void OrderBackup::Backup(const Vehicle *v, uint32 user)
104 {
105 /* Don't use reset as that broadcasts over the network to reset the variable,
106 * which is what we are doing at the moment. */
107 OrderBackup *ob;
108 FOR_ALL_ORDER_BACKUPS(ob) {
109 if (ob->user == user) delete ob;
110 }
111 if (OrderBackup::CanAllocateItem()) {
112 new OrderBackup(v, user);
113 }
114 }
115
122 /* static */ void OrderBackup::Restore(Vehicle *v, uint32 user)
123 {
124 OrderBackup *ob;
125 FOR_ALL_ORDER_BACKUPS(ob) {
126 if (v->tile != ob->tile || ob->user != user) continue;
127
128 ob->DoRestore(v);
129 delete ob;
130 }
131 }
132
139 /* static */ void OrderBackup::ResetOfUser(TileIndex tile, uint32 user)
140 {
141 OrderBackup *ob;
142 FOR_ALL_ORDER_BACKUPS(ob) {
143 if (ob->user == user && (ob->tile == tile || tile == INVALID_TILE)) delete ob;
144 }
145 }
146
156 CommandCost CmdClearOrderBackup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
157 {
158 /* No need to check anything. If the tile or user don't exist we just ignore it. */
159 if (flags & DC_EXEC) OrderBackup::ResetOfUser(tile == 0 ? INVALID_TILE : tile, p2);
160
161 return CommandCost();
162 }
163
170 /* static */ void OrderBackup::ResetUser(uint32 user)
171 {
172 assert(_network_server);
173
174 OrderBackup *ob;
175 FOR_ALL_ORDER_BACKUPS(ob) {
176 /* If it's not an backup of us, so ignore it. */
177 if (ob->user != user) continue;
178
179 DoCommandP(0, 0, user, CMD_CLEAR_ORDER_BACKUP);
180 return;
181 }
182 }
183
190 /* static */ void OrderBackup::Reset(TileIndex t, bool from_gui)
191 {
192 /* The user has CLIENT_ID_SERVER as default when network play is not active,
193 * but compiled it. A network client has its own variable for the unique
194 * client/user identifier. Finally if networking isn't compiled in the
195 * default is just plain and simple: 0. */
196 #ifdef ENABLE_NETWORK
197 uint32 user = _networking && !_network_server ? _network_own_client_id : CLIENT_ID_SERVER;
198 #else
199 uint32 user = 0;
200 #endif
201
202 OrderBackup *ob;
203 FOR_ALL_ORDER_BACKUPS(ob) {
204 /* If it's not an backup of us, so ignore it. */
205 if (ob->user != user) continue;
206 /* If it's not for our chosen tile either, ignore it. */
207 if (t != INVALID_TILE && t != ob->tile) continue;
208
209 if (from_gui) {
210 /* We need to circumvent the "prevention" from this command being executed
211 * while the game is paused, so use the internal method. Nor do we want
212 * this command to get its cost estimated when shift is pressed. */
213 DoCommandPInternal(ob->tile, 0, user, CMD_CLEAR_ORDER_BACKUP, NULL, NULL, true, false);
214 } else {
215 /* The command came from the game logic, i.e. the clearing of a tile.
216 * In that case we have no need to actually sync this, just do it. */
217 delete ob;
218 }
219 }
220 }
221
226 /* static */ void OrderBackup::ClearGroup(GroupID group)
227 {
228 OrderBackup *ob;
229 FOR_ALL_ORDER_BACKUPS(ob) {
230 if (ob->group == group) ob->group = DEFAULT_GROUP;
231 }
232 }
233
241 /* static */ void OrderBackup::ClearVehicle(const Vehicle *v)
242 {
243 assert(v != NULL);
244 OrderBackup *ob;
245 FOR_ALL_ORDER_BACKUPS(ob) {
246 if (ob->clone == v) {
247 /* Get another item in the shared list. */
248 ob->clone = (v->FirstShared() == v) ? v->NextShared() : v->FirstShared();
249 /* But if that isn't there, remove it. */
250 if (ob->clone == NULL) delete ob;
251 }
252 }
253 }
254
260 /* static */ void OrderBackup::RemoveOrder(OrderType type, DestinationID destination)
261 {
262 OrderBackup *ob;
263 FOR_ALL_ORDER_BACKUPS(ob) {
264 for (Order *order = ob->orders; order != NULL; order = order->next) {
265 OrderType ot = order->GetType();
266 if (ot == OT_GOTO_DEPOT && (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) continue;
267 if (ot == OT_IMPLICIT || (IsHangarTile(ob->tile) && ot == OT_GOTO_DEPOT)) ot = OT_GOTO_STATION;
268 if (ot == type && order->GetDestination() == destination) {
269 /* Remove the order backup! If a station/depot gets removed, we can't/shouldn't restore those broken orders. */
270 delete ob;
271 break;
272 }
273 }
274 }
275 }