# order_backup.cpp

Go to the documentation of this file.

    00001 /* $Id$ */
    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
    00020 OrderBackupPool _order_backup_pool("BackupOrder");
    00021 INSTANTIATE_POOL_METHODS(OrderBackup)
    00022
    00023
    00024 OrderBackup::~OrderBackup()
    00025 {
    00026   free(this->name);
    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->orderindex       = v->cur_auto_order_index;
    00048   this->group            = v->group_id;
    00049   this->service_interval = v->service_interval;
    00050
    00051   if (v->name != NULL) this->name = strdup(v->name);
    00052
    00053   /* If we have shared orders, store the vehicle we share the order with. */
    00054   if (v->IsOrderListShared()) {
    00055     this->clone = (v->FirstShared() == v) ? v->NextShared() : v->FirstShared();
    00056   } else {
    00057     /* Else copy the orders */
    00058     Order **tail = &this->orders;
    00059
    00060     /* Count the number of orders */
    00061     const Order *order;
    00062     FOR_VEHICLE_ORDERS(v, order) {
    00063       Order *copy = new Order();
    00064       copy->AssignOrder(*order);
    00065       *tail = copy;
    00066       tail = &copy->next;
    00067     }
    00068   }
    00069 }
    00070
    00075 void OrderBackup::DoRestore(Vehicle *v)
    00076 {
    00077   /* If we have a custom name, process that */
    00078   v->name = this->name;
    00079   this->name = NULL;
    00080
    00081   /* If we had shared orders, recover that */
    00082   if (this->clone != NULL) {
    00083     DoCommand(0, v->index | CO_SHARE << 30, this->clone->index, DC_EXEC, CMD_CLONE_ORDER);
    00084   } else if (this->orders != NULL && OrderList::CanAllocateItem()) {
    00085     v->orders.list = new OrderList(this->orders, v);
    00086     this->orders = NULL;
    00087   }
    00088
    00089   uint num_orders = v->GetNumOrders();
    00090   if (num_orders != 0) {
    00091     v->cur_real_order_index = v->cur_auto_order_index = this->orderindex % num_orders;
    00092     v->UpdateRealOrderIndex();
    00093   }
    00094   v->service_interval = this->service_interval;
    00095
    00096   /* Restore vehicle group */
    00097   DoCommand(0, this->group, v->index, DC_EXEC, CMD_ADD_VEHICLE_GROUP);
    00098 }
    00099
    00106 /* static */ void OrderBackup::Backup(const Vehicle *v, uint32 user)
    00107 {
    00108   /* Don't use reset as that broadcasts over the network to reset the variable,
    00109    * which is what we are doing at the moment. */
    00110   OrderBackup *ob;
    00111   FOR_ALL_ORDER_BACKUPS(ob) {
    00112     if (ob->user == user) delete ob;
    00113   }
    00114   if (OrderBackup::CanAllocateItem()) {
    00115     new OrderBackup(v, user);
    00116   }
    00117 }
    00118
    00125 /* static */ void OrderBackup::Restore(Vehicle *v, uint32 user)
    00126 {
    00127   OrderBackup *ob;
    00128   FOR_ALL_ORDER_BACKUPS(ob) {
    00129     if (v->tile != ob->tile || ob->user != user) continue;
    00130
    00131     ob->DoRestore(v);
    00132     delete ob;
    00133   }
    00134 }
    00135
    00142 /* static */ void OrderBackup::ResetOfUser(TileIndex tile, uint32 user)
    00143 {
    00144   OrderBackup *ob;
    00145   FOR_ALL_ORDER_BACKUPS(ob) {
    00146     if (ob->user == user && (ob->tile == tile || tile == INVALID_TILE)) delete ob;
    00147   }
    00148 }
    00149
    00159 CommandCost CmdClearOrderBackup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00160 {
    00161   /* No need to check anything. If the tile or user don't exist we just ignore it. */
    00162   if (flags & DC_EXEC) OrderBackup::ResetOfUser(tile == 0 ? INVALID_TILE : tile, p2);
    00163
    00164   return CommandCost();
    00165 }
    00166
    00173 /* static */ void OrderBackup::ResetUser(uint32 user)
    00174 {
    00175   assert(_network_server);
    00176
    00177   OrderBackup *ob;
    00178   FOR_ALL_ORDER_BACKUPS(ob) {
    00179     /* If it's not an backup of us, so ignore it. */
    00180     if (ob->user != user) continue;
    00181
    00182     DoCommandP(0, 0, user, CMD_CLEAR_ORDER_BACKUP);
    00183     return;
    00184   }
    00185 }
    00186
    00193 /* static */ void OrderBackup::Reset(TileIndex t, bool from_gui)
    00194 {
    00195   /* The user has CLIENT_ID_SERVER as default when network play is not active,
    00196    * but compiled it. A network client has its own variable for the unique
    00197    * client/user identifier. Finally if networking isn't compiled in the
    00198    * default is just plain and simple: 0. */
    00199 #ifdef ENABLE_NETWORK
    00200   uint32 user = _networking && !_network_server ? _network_own_client_id : CLIENT_ID_SERVER;
    00201 #else
    00202   uint32 user = 0;
    00203 #endif
    00204
    00205   OrderBackup *ob;
    00206   FOR_ALL_ORDER_BACKUPS(ob) {
    00207     /* If it's not an backup of us, so ignore it. */
    00208     if (ob->user != user) continue;
    00209     /* If it's not for our chosen tile either, ignore it. */
    00210     if (t != INVALID_TILE && t != ob->tile) continue;
    00211
    00212     if (from_gui) {
    00213       /* We need to circumvent the "prevention" from this command being executed
    00214        * while the game is paused, so use the internal method. Nor do we want
    00215        * this command to get its cost estimated when shift is pressed. */
    00216       DoCommandPInternal(ob->tile, 0, user, CMD_CLEAR_ORDER_BACKUP, NULL, NULL, true, false);
    00217     } else {
    00218       /* The command came from the game logic, i.e. the clearing of a tile.
    00219        * In that case we have no need to actually sync this, just do it. */
    00220       delete ob;
    00221     }
    00222   }
    00223 }
    00224
    00229 /* static */ void OrderBackup::ClearGroup(GroupID group)
    00230 {
    00231   OrderBackup *ob;
    00232   FOR_ALL_ORDER_BACKUPS(ob) {
    00233     if (ob->group == group) ob->group = DEFAULT_GROUP;
    00234   }
    00235 }
    00236
    00244 /* static */ void OrderBackup::ClearVehicle(const Vehicle *v)
    00245 {
    00246   assert(v != NULL);
    00247   OrderBackup *ob;
    00248   FOR_ALL_ORDER_BACKUPS(ob) {
    00249     if (ob->clone == v) {
    00250       /* Get another item in the shared list. */
    00251       ob->clone = (v->FirstShared() == v) ? v->NextShared() : v->FirstShared();
    00252       /* But if that isn't there, remove it. */
    00253       if (ob->clone == NULL) delete ob;
    00254     }
    00255   }
    00256 }
    00257
    00258 void InitializeOrderBackups()
    00259 {
    00260   _order_backup_pool.CleanPool();
    00261 }