diff --git a/misc.c b/misc.c index bb7eb4f0e8..9eaa4ab204 100644 --- a/misc.c +++ b/misc.c @@ -604,7 +604,7 @@ void IncreaseDate(void) */ ctr = _vehicle_id_ctr_day; - for (i = 0; i != (_vehicles_size / vehicles_per_day) + 1 && ctr != _vehicles_size; i++) { + for (i = 0; i != ((uint)GetVehiclePoolSize() / vehicles_per_day) + 1 && ctr != GetVehiclePoolSize(); i++) { Vehicle *v = GetVehicle(ctr++); if ((t = v->type) != 0) _on_new_vehicle_day_proc[t - 0x10](v); diff --git a/oldloader.c b/oldloader.c index 4ad72a72f5..ad7455c4eb 100644 --- a/oldloader.c +++ b/oldloader.c @@ -797,6 +797,9 @@ static void FixVehicle(OldVehicle *o, int num) if (o->type == 0) continue; + if (!AddBlockIfNeeded(&_vehicle_pool, i)) + error("Vehicles: failed loading savegame: too many vehicles"); + n = GetVehicle(i); n->type = o->type; diff --git a/saveload.c b/saveload.c index 174d657033..66ac65af70 100644 --- a/saveload.c +++ b/saveload.c @@ -942,7 +942,11 @@ static void *IntToReference(uint r, uint t) switch (t) { case REF_ORDER: return GetOrder(r - 1); - case REF_VEHICLE: return GetVehicle(r - 1); + case REF_VEHICLE: { + if (!AddBlockIfNeeded(&_vehicle_pool, r - 1)) + error("Vehicles: failed loading savegame: too many vehicles"); + return GetVehicle(r - 1); + } case REF_STATION: { if (!AddBlockIfNeeded(&_station_pool, r - 1)) error("Stations: failed loading savegame: too many stations"); @@ -962,6 +966,9 @@ static void *IntToReference(uint r, uint t) and the index was not - 1.. correct for this */ if (r == INVALID_VEHICLE) return NULL; + + if (!AddBlockIfNeeded(&_vehicle_pool, r)) + error("Vehicles: failed loading savegame: too many vehicles"); return GetVehicle(r); } default: diff --git a/ttd.c b/ttd.c index 342b84d5c1..1f951b19d0 100644 --- a/ttd.c +++ b/ttd.c @@ -496,7 +496,6 @@ static void InitializeDynamicVariables(void) { /* Dynamic stuff needs to be initialized somewhere... */ _roadstops_size = lengthof(_roadstops); - _vehicles_size = lengthof(_vehicles); _sign_size = lengthof(_sign_list); _orders_size = lengthof(_orders); @@ -512,6 +511,7 @@ static void UnInitializeDynamicVariables(void) CleanPool(&_town_pool); CleanPool(&_industry_pool); CleanPool(&_station_pool); + CleanPool(&_vehicle_pool); free(_station_sort); free(_vehicle_sort); diff --git a/vehicle.c b/vehicle.c index 01cffe049d..4a0048267c 100644 --- a/vehicle.c +++ b/vehicle.c @@ -17,9 +17,27 @@ #define GEN_HASH(x,y) (((x & 0x1F80)>>7) + ((y & 0xFC0))) enum { - VEHICLES_MIN_FREE_FOR_AI = 90 + /* Max vehicles: 64000 (512 * 125) */ + VEHICLES_POOL_BLOCK_SIZE_BITS = 9, /* In bits, so (1 << 9) == 512 */ + VEHICLES_POOL_MAX_BLOCKS = 125, + + BLOCKS_FOR_SPECIAL_VEHICLES = 2, //! Blocks needed for special vehicles }; +/** + * Called if a new block is added to the vehicle-pool + */ +static void VehiclePoolNewBlock(uint start_item) +{ + Vehicle *v; + + FOR_ALL_VEHICLES_FROM(v, start_item) + v->index = start_item++; +} + +/* Initialize the vehicle-pool */ +MemoryPool _vehicle_pool = { "Vehicle", VEHICLES_POOL_MAX_BLOCKS, VEHICLES_POOL_BLOCK_SIZE_BITS, sizeof(Vehicle), &VehiclePoolNewBlock, 0, 0, NULL }; + void VehicleServiceInDepot(Vehicle *v) { v->date_of_last_service = _date; @@ -205,49 +223,42 @@ static Vehicle *InitializeVehicle(Vehicle *v) Vehicle *ForceAllocateSpecialVehicle(void) { - Vehicle *v; - FOR_ALL_VEHICLES_FROM(v, NUM_NORMAL_VEHICLES) { - if (v->type == 0) - return InitializeVehicle(v); - } - return NULL; + /* This stays a strange story.. there should always be room for special + * vehicles (special effects all over the map), but with 65k of vehicles + * is this realistic to double-check for that? For now we just reserve + * BLOCKS_FOR_SPECIAL_VEHICLES times block_size vehicles that may only + * be used for special vehicles.. should work nicely :) */ -} - -Vehicle *ForceAllocateVehicle(void) -{ Vehicle *v; + FOR_ALL_VEHICLES(v) { - if (v->index >= NUM_NORMAL_VEHICLES) + /* No more room for the special vehicles, return NULL */ + if (v->index >= (1 << _vehicle_pool.block_size_bits) * BLOCKS_FOR_SPECIAL_VEHICLES) return NULL; if (v->type == 0) return InitializeVehicle(v); } + return NULL; } Vehicle *AllocateVehicle(void) { + /* See note by ForceAllocateSpecialVehicle() why we skip the + * first blocks */ Vehicle *v; - int num; - if (IS_HUMAN_PLAYER(_current_player)) { - num = 0; - - FOR_ALL_VEHICLES(v) { - if (v->index >= NUM_NORMAL_VEHICLES) - break; - - if (v->type == 0) - num++; - } - - if (num <= VEHICLES_MIN_FREE_FOR_AI) - return NULL; + FOR_ALL_VEHICLES_FROM(v, (1 << _vehicle_pool.block_size_bits) * BLOCKS_FOR_SPECIAL_VEHICLES) { + if (v->type == 0) + return InitializeVehicle(v); } - return ForceAllocateVehicle(); + /* Check if we can add a block to the pool */ + if (AddBlockToPool(&_vehicle_pool)) + return AllocateVehicle(); + + return NULL; } void *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *proc) @@ -330,19 +341,20 @@ void UpdateVehiclePosHash(Vehicle *v, int x, int y) void InitializeVehicles(void) { - Vehicle *v; int i; + /* Clean the vehicle pool, and reserve enough blocks + * for the special vehicles, plus one for all the other + * vehicles (which is increased on-the-fly) */ + CleanPool(&_vehicle_pool); + AddBlockToPool(&_vehicle_pool); + for (i = 0; i < BLOCKS_FOR_SPECIAL_VEHICLES; i++) + AddBlockToPool(&_vehicle_pool); + // clear it... - memset(&_vehicles, 0, sizeof(_vehicles[0]) * _vehicles_size); memset(&_waypoints, 0, sizeof(_waypoints)); memset(&_depots, 0, sizeof(_depots)); - // setup indexes.. - i = 0; - FOR_ALL_VEHICLES(v) - v->index = i++; - memset(_vehicle_position_hash, -1, sizeof(_vehicle_position_hash)); } @@ -2034,9 +2046,14 @@ static void Load_VEHS(void) Vehicle *v; while ((index = SlIterateArray()) != -1) { - Vehicle *v = GetVehicle(index); + Vehicle *v; + if (!AddBlockIfNeeded(&_vehicle_pool, index)) + error("Vehicles: failed loading savegame: too many vehicles"); + + v = GetVehicle(index); SlObject(v, _veh_descs[SlReadByte()]); + if (v->type == VEH_Train) v->u.rail.first_engine = 0xffff; @@ -2088,7 +2105,7 @@ static void Load_VEHS(void) /* This is to ensure all pointers are within the limits of _vehicles_size */ - if (_vehicle_id_ctr_day >= _vehicles_size) + if (_vehicle_id_ctr_day >= GetVehiclePoolSize()) _vehicle_id_ctr_day = 0; } diff --git a/vehicle.h b/vehicle.h index a180036d9e..716aad77d9 100644 --- a/vehicle.h +++ b/vehicle.h @@ -1,6 +1,7 @@ #ifndef VEHICLE_H #define VEHICLE_H +#include "pool.h" #include "vehicle_gui.h" #include "order.h" @@ -359,33 +360,41 @@ byte GetDirectionTowards(Vehicle *v, int x, int y); #define END_ENUM_WAGONS(v) } while ( (v=v->next) != NULL); /* vehicle.c */ -enum { - NUM_NORMAL_VEHICLES = 2048, - NUM_SPECIAL_VEHICLES = 512, - NUM_VEHICLES = NUM_NORMAL_VEHICLES + NUM_SPECIAL_VEHICLES -}; - -VARDEF Vehicle _vehicles[NUM_VEHICLES]; -VARDEF uint _vehicles_size; - VARDEF SortStruct *_vehicle_sort; -static inline Vehicle *GetVehicle(uint index) +extern MemoryPool _vehicle_pool; + +/** + * Get the pointer to the vehicle with index 'index' + */ +static inline Vehicle *GetVehicle(VehicleID index) { - assert(index < _vehicles_size); - return &_vehicles[index]; + return (Vehicle*)GetItemFromPool(&_vehicle_pool, index); } +/** + * Get the current size of the VehiclePool + */ +static inline uint16 GetVehiclePoolSize(void) +{ + return _vehicle_pool.total_items; +} + +#define FOR_ALL_VEHICLES_FROM(v, start) for (v = GetVehicle(start); v != NULL; v = (v->index + 1 < GetVehiclePoolSize()) ? GetVehicle(v->index + 1) : NULL) +#define FOR_ALL_VEHICLES(v) FOR_ALL_VEHICLES_FROM(v, 0) + +/** + * Check if an index is a vehicle-index (so between 0 and max-vehicles) + * + * @return Returns true if the vehicle-id is in range + */ static inline bool IsVehicleIndex(uint index) { - if (index < _vehicles_size) + if (index < GetVehiclePoolSize()) return true; - else - return false; -} -#define FOR_ALL_VEHICLES(v) for(v = _vehicles; v != &_vehicles[_vehicles_size]; v++) -#define FOR_ALL_VEHICLES_FROM(v, from) for(v = GetVehicle(from); v != &_vehicles[_vehicles_size]; v++) + return false; +} /* Returns order 'index' of a vehicle or NULL when it doesn't exists */ static inline Order *GetVehicleOrder(const Vehicle *v, int index) diff --git a/vehicle_gui.c b/vehicle_gui.c index 830a6bb464..62d7200610 100644 --- a/vehicle_gui.c +++ b/vehicle_gui.c @@ -79,7 +79,7 @@ void BuildVehicleList(vehiclelist_d *vl, int type, int owner, int station) if (!(vl->flags & VL_REBUILD)) return; /* Create array for sorting */ - _vehicle_sort = realloc(_vehicle_sort, _vehicles_size * sizeof(_vehicle_sort[0])); + _vehicle_sort = realloc(_vehicle_sort, GetVehiclePoolSize() * sizeof(_vehicle_sort[0])); if (_vehicle_sort == NULL) error("Could not allocate memory for the vehicle-sorting-list");