order_backup.cpp

Go to the documentation of this file.
00001 /* $Id: order_backup.cpp 24446 2012-07-29 16:48:00Z frosch $ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * 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.
00006  * 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.
00007  * 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/>.
00008  */
00009 
00012 #include "stdafx.h"
00013 #include "command_func.h"
00014 #include "core/pool_func.hpp"
00015 #include "network/network.h"
00016 #include "network/network_func.h"
00017 #include "order_backup.h"
00018 #include "vehicle_base.h"
00019 #include "window_func.h"
00020 #include "station_map.h"
00021 
00022 OrderBackupPool _order_backup_pool("BackupOrder");
00023 INSTANTIATE_POOL_METHODS(OrderBackup)
00024 
00025 
00026 OrderBackup::~OrderBackup()
00027 {
00028   if (CleaningPool()) return;
00029 
00030   Order *o = this->orders;
00031   while (o != NULL) {
00032     Order *next = o->next;
00033     delete o;
00034     o = next;
00035   }
00036 }
00037 
00043 OrderBackup::OrderBackup(const Vehicle *v, uint32 user)
00044 {
00045   this->user             = user;
00046   this->tile             = v->tile;
00047   this->group            = v->group_id;
00048 
00049   this->CopyConsistPropertiesFrom(v);
00050 
00051   /* If we have shared orders, store the vehicle we share the order with. */
00052   if (v->IsOrderListShared()) {
00053     this->clone = (v->FirstShared() == v) ? v->NextShared() : v->FirstShared();
00054   } else {
00055     /* Else copy the orders */
00056     Order **tail = &this->orders;
00057 
00058     /* Count the number of orders */
00059     const Order *order;
00060     FOR_VEHICLE_ORDERS(v, order) {
00061       Order *copy = new Order();
00062       copy->AssignOrder(*order);
00063       *tail = copy;
00064       tail = &copy->next;
00065     }
00066   }
00067 }
00068 
00073 void OrderBackup::DoRestore(Vehicle *v)
00074 {
00075   /* If we had shared orders, recover that */
00076   if (this->clone != NULL) {
00077     DoCommand(0, v->index | CO_SHARE << 30, this->clone->index, DC_EXEC, CMD_CLONE_ORDER);
00078   } else if (this->orders != NULL && OrderList::CanAllocateItem()) {
00079     v->orders.list = new OrderList(this->orders, v);
00080     this->orders = NULL;
00081     /* Make sure buoys/oil rigs are updated in the station list. */
00082     InvalidateWindowClassesData(WC_STATION_LIST, 0);
00083   }
00084 
00085   v->CopyConsistPropertiesFrom(this);
00086 
00087   /* Make sure orders are in range */
00088   v->UpdateRealOrderIndex();
00089   if (v->cur_implicit_order_index >= v->GetNumOrders()) v->cur_implicit_order_index = v->cur_real_order_index;
00090 
00091   /* Restore vehicle group */
00092   DoCommand(0, this->group, v->index, DC_EXEC, CMD_ADD_VEHICLE_GROUP);
00093 }
00094 
00101 /* static */ void OrderBackup::Backup(const Vehicle *v, uint32 user)
00102 {
00103   /* Don't use reset as that broadcasts over the network to reset the variable,
00104    * which is what we are doing at the moment. */
00105   OrderBackup *ob;
00106   FOR_ALL_ORDER_BACKUPS(ob) {
00107     if (ob->user == user) delete ob;
00108   }
00109   if (OrderBackup::CanAllocateItem()) {
00110     new OrderBackup(v, user);
00111   }
00112 }
00113 
00120 /* static */ void OrderBackup::Restore(Vehicle *v, uint32 user)
00121 {
00122   OrderBackup *ob;
00123   FOR_ALL_ORDER_BACKUPS(ob) {
00124     if (v->tile != ob->tile || ob->user != user) continue;
00125 
00126     ob->DoRestore(v);
00127     delete ob;
00128   }
00129 }
00130 
00137 /* static */ void OrderBackup::ResetOfUser(TileIndex tile, uint32 user)
00138 {
00139   OrderBackup *ob;
00140   FOR_ALL_ORDER_BACKUPS(ob) {
00141     if (ob->user == user && (ob->tile == tile || tile == INVALID_TILE)) delete ob;
00142   }
00143 }
00144 
00154 CommandCost CmdClearOrderBackup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00155 {
00156   /* No need to check anything. If the tile or user don't exist we just ignore it. */
00157   if (flags & DC_EXEC) OrderBackup::ResetOfUser(tile == 0 ? INVALID_TILE : tile, p2);
00158 
00159   return CommandCost();
00160 }
00161 
00168 /* static */ void OrderBackup::ResetUser(uint32 user)
00169 {
00170   assert(_network_server);
00171 
00172   OrderBackup *ob;
00173   FOR_ALL_ORDER_BACKUPS(ob) {
00174     /* If it's not an backup of us, so ignore it. */
00175     if (ob->user != user) continue;
00176 
00177     DoCommandP(0, 0, user, CMD_CLEAR_ORDER_BACKUP);
00178     return;
00179   }
00180 }
00181 
00188 /* static */ void OrderBackup::Reset(TileIndex t, bool from_gui)
00189 {
00190   /* The user has CLIENT_ID_SERVER as default when network play is not active,
00191    * but compiled it. A network client has its own variable for the unique
00192    * client/user identifier. Finally if networking isn't compiled in the
00193    * default is just plain and simple: 0. */
00194 #ifdef ENABLE_NETWORK
00195   uint32 user = _networking && !_network_server ? _network_own_client_id : CLIENT_ID_SERVER;
00196 #else
00197   uint32 user = 0;
00198 #endif
00199 
00200   OrderBackup *ob;
00201   FOR_ALL_ORDER_BACKUPS(ob) {
00202     /* If it's not an backup of us, so ignore it. */
00203     if (ob->user != user) continue;
00204     /* If it's not for our chosen tile either, ignore it. */
00205     if (t != INVALID_TILE && t != ob->tile) continue;
00206 
00207     if (from_gui) {
00208       /* We need to circumvent the "prevention" from this command being executed
00209        * while the game is paused, so use the internal method. Nor do we want
00210        * this command to get its cost estimated when shift is pressed. */
00211       DoCommandPInternal(ob->tile, 0, user, CMD_CLEAR_ORDER_BACKUP, NULL, NULL, true, false);
00212     } else {
00213       /* The command came from the game logic, i.e. the clearing of a tile.
00214        * In that case we have no need to actually sync this, just do it. */
00215       delete ob;
00216     }
00217   }
00218 }
00219 
00224 /* static */ void OrderBackup::ClearGroup(GroupID group)
00225 {
00226   OrderBackup *ob;
00227   FOR_ALL_ORDER_BACKUPS(ob) {
00228     if (ob->group == group) ob->group = DEFAULT_GROUP;
00229   }
00230 }
00231 
00239 /* static */ void OrderBackup::ClearVehicle(const Vehicle *v)
00240 {
00241   assert(v != NULL);
00242   OrderBackup *ob;
00243   FOR_ALL_ORDER_BACKUPS(ob) {
00244     if (ob->clone == v) {
00245       /* Get another item in the shared list. */
00246       ob->clone = (v->FirstShared() == v) ? v->NextShared() : v->FirstShared();
00247       /* But if that isn't there, remove it. */
00248       if (ob->clone == NULL) delete ob;
00249     }
00250   }
00251 }
00252 
00258 /* static */ void OrderBackup::RemoveOrder(OrderType type, DestinationID destination)
00259 {
00260   OrderBackup *ob;
00261   FOR_ALL_ORDER_BACKUPS(ob) {
00262     for (Order *order = ob->orders; order != NULL; order = order->next) {
00263       OrderType ot = order->GetType();
00264       if (ot == OT_GOTO_DEPOT && (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) continue;
00265       if (ot == OT_IMPLICIT || (IsHangarTile(ob->tile) && ot == OT_GOTO_DEPOT)) ot = OT_GOTO_STATION;
00266       if (ot == type && order->GetDestination() == destination) {
00267         /* Remove the order backup! If a station/depot gets removed, we can't/shouldn't restore those broken orders. */
00268         delete ob;
00269         break;
00270       }
00271     }
00272   }
00273 }