/** * Assign items from other vector. */ inline void Assign(const SmallMatrix &other) { if (&other == this) return; this->height = other.Height(); this->width = other.Width(); uint num_items = this->width * this->height; if (num_items > this->capacity) { this->capacity = num_items; free(this->data); this->data = MallocT<T>(num_items); MemCpyT(this->data, other[0], num_items); } else if (num_items > 0) { MemCpyT(this->data, other[0], num_items); } }
/** Allocates space for a new tile in the matrix. * @param tile Tile to add. */ void AllocateStorage(TileIndex tile) { uint old_left = TileX(this->area.tile) / N; uint old_top = TileY(this->area.tile) / N; uint old_w = this->area.w / N; uint old_h = this->area.h / N; /* Add the square the tile is in to the tile area. We do this * by adding top-left and bottom-right of the square. */ uint grid_x = (TileX(tile) / N) * N; uint grid_y = (TileY(tile) / N) * N; this->area.Add(TileXY(grid_x, grid_y)); this->area.Add(TileXY(grid_x + N - 1, grid_y + N - 1)); /* Allocate new storage. */ T *new_data = CallocT<T>(this->area.w / N * this->area.h / N); if (old_w > 0) { /* Copy old data if present. */ uint offs_x = old_left - TileX(this->area.tile) / N; uint offs_y = old_top - TileY(this->area.tile) / N; for (uint row = 0; row < old_h; row++) { MemCpyT(&new_data[(row + offs_y) * this->area.w / N + offs_x], &this->data[row * old_w], old_w); } } free(this->data); this->data = new_data; }
/** * Add text to the output buffer. * @param text Text to store. * @param length Length of the text in bytes. * @return Number of bytes actually stored. */ int Add(const char *text, int length) { int store_size = min(length, OUTPUT_BLOCK_SIZE - this->size); assert(store_size >= 0); assert(store_size <= OUTPUT_BLOCK_SIZE); MemCpyT(this->data + this->size, text, store_size); this->size += store_size; return store_size; }
/** * Display an error message in a window. * @param summary_msg General error message showed in first line. Must be valid. * @param detailed_msg Detailed error message showed in second line. Can be INVALID_STRING_ID. * @param duration The amount of time to show this error message. * @param x World X position (TileVirtX) of the error location. Set both x and y to 0 to just center the message when there is no related error tile. * @param y World Y position (TileVirtY) of the error location. Set both x and y to 0 to just center the message when there is no related error tile. * @param textref_stack_size Number of uint32 values to put on the #TextRefStack for the error message; 0 if the #TextRefStack shall not be used. * @param textref_stack Values to put on the #TextRefStack. */ ErrorMessageData::ErrorMessageData(StringID summary_msg, StringID detailed_msg, uint duration, int x, int y, uint textref_stack_size, const uint32 *textref_stack) : duration(duration), textref_stack_size(textref_stack_size), summary_msg(summary_msg), detailed_msg(detailed_msg), face(INVALID_COMPANY) { this->position.x = x; this->position.y = y; memset(this->decode_params, 0, sizeof(this->decode_params)); memset(this->strings, 0, sizeof(this->strings)); if (textref_stack_size > 0) MemCpyT(this->textref_stack, textref_stack, textref_stack_size); assert(summary_msg != INVALID_STRING_ID); }
/** * Display an error message in a window. * @param summary_msg General error message showed in first line. Must be valid. * @param detailed_msg Detailed error message showed in second line. Can be INVALID_STRING_ID. * @param duration The amount of time to show this error message. * @param x World X position (TileVirtX) of the error location. Set both x and y to 0 to just center the message when there is no related error tile. * @param y World Y position (TileVirtY) of the error location. Set both x and y to 0 to just center the message when there is no related error tile. * @param textref_stack_size Number of uint32 values to put on the #TextRefStack for the error message; 0 if the #TextRefStack shall not be used. * @param textref_stack Values to put on the #TextRefStack. */ ErrorMessageData(StringID summary_msg, StringID detailed_msg, uint duration, int x, int y, uint textref_stack_size, const uint32 *textref_stack) : duration(duration), textref_stack_size(textref_stack_size), summary_msg(summary_msg), detailed_msg(detailed_msg) { this->position.x = x; this->position.y = y; if (textref_stack_size > 0) StartTextRefStackUsage(textref_stack_size, textref_stack); CopyOutDParam(this->decode_params, this->strings, detailed_msg == INVALID_STRING_ID ? summary_msg : detailed_msg, lengthof(this->decode_params)); if (textref_stack_size > 0) { StopTextRefStackUsage(); MemCpyT(this->textref_stack, textref_stack, textref_stack_size); } CompanyID company = (CompanyID)GetDParamX(this->decode_params, 2); this->face = (this->detailed_msg == STR_ERROR_OWNED_BY && company < MAX_COMPANIES) ? company : INVALID_COMPANY; assert(summary_msg != INVALID_STRING_ID); }
/** * Check the validity of some of the caches. * Especially in the sense of desyncs between * the cached value and what the value would * be when calculated from the 'base' data. */ static void CheckCaches() { /* Return here so it is easy to add checks that are run * always to aid testing of caches. */ if (_debug_desync_level <= 1) return; /* Check the town caches. */ SmallVector<TownCache, 4> old_town_caches; Town *t; FOR_ALL_TOWNS(t) { MemCpyT(old_town_caches.Append(), &t->cache); } extern void RebuildTownCaches(); RebuildTownCaches(); RebuildSubsidisedSourceAndDestinationCache(); uint i = 0; FOR_ALL_TOWNS(t) { if (MemCmpT(old_town_caches.Get(i), &t->cache) != 0) { DEBUG(desync, 2, "town cache mismatch: town %i", (int)t->index); } i++; } /* Check company infrastructure cache. */ SmallVector<CompanyInfrastructure, 4> old_infrastructure; Company *c; FOR_ALL_COMPANIES(c) MemCpyT(old_infrastructure.Append(), &c->infrastructure); extern void AfterLoadCompanyStats(); AfterLoadCompanyStats(); i = 0; FOR_ALL_COMPANIES(c) { if (MemCmpT(old_infrastructure.Get(i), &c->infrastructure) != 0) { DEBUG(desync, 2, "infrastructure cache mismatch: company %i", (int)c->index); } i++; } /* Strict checking of the road stop cache entries */ const RoadStop *rs; FOR_ALL_ROADSTOPS(rs) { if (IsStandardRoadStopTile(rs->xy)) continue; assert(rs->GetEntry(DIAGDIR_NE) != rs->GetEntry(DIAGDIR_NW)); rs->GetEntry(DIAGDIR_NE)->CheckIntegrity(rs); rs->GetEntry(DIAGDIR_NW)->CheckIntegrity(rs); } Vehicle *v; FOR_ALL_VEHICLES(v) { extern void FillNewGRFVehicleCache(const Vehicle *v); if (v != v->First() || v->vehstatus & VS_CRASHED || !v->IsPrimaryVehicle()) continue; uint length = 0; for (const Vehicle *u = v; u != NULL; u = u->Next()) length++; NewGRFCache *grf_cache = CallocT<NewGRFCache>(length); VehicleCache *veh_cache = CallocT<VehicleCache>(length); GroundVehicleCache *gro_cache = CallocT<GroundVehicleCache>(length); TrainCache *tra_cache = CallocT<TrainCache>(length); length = 0; for (const Vehicle *u = v; u != NULL; u = u->Next()) { FillNewGRFVehicleCache(u); grf_cache[length] = u->grf_cache; veh_cache[length] = u->vcache; switch (u->type) { case VEH_TRAIN: gro_cache[length] = Train::From(u)->gcache; tra_cache[length] = Train::From(u)->tcache; break; case VEH_ROAD: gro_cache[length] = RoadVehicle::From(u)->gcache; break; default: break; } length++; } switch (v->type) { case VEH_TRAIN: Train::From(v)->ConsistChanged(CCF_TRACK); break; case VEH_ROAD: RoadVehUpdateCache(RoadVehicle::From(v)); break; case VEH_AIRCRAFT: UpdateAircraftCache(Aircraft::From(v)); break; case VEH_SHIP: Ship::From(v)->UpdateCache(); break; default: break; } length = 0; for (const Vehicle *u = v; u != NULL; u = u->Next()) { FillNewGRFVehicleCache(u); if (memcmp(&grf_cache[length], &u->grf_cache, sizeof(NewGRFCache)) != 0) { DEBUG(desync, 2, "newgrf cache mismatch: type %i, vehicle %i, company %i, unit number %i, wagon %i", (int)v->type, v->index, (int)v->owner, v->unitnumber, length); } if (memcmp(&veh_cache[length], &u->vcache, sizeof(VehicleCache)) != 0) { DEBUG(desync, 2, "vehicle cache mismatch: type %i, vehicle %i, company %i, unit number %i, wagon %i", (int)v->type, v->index, (int)v->owner, v->unitnumber, length); } switch (u->type) { case VEH_TRAIN: if (memcmp(&gro_cache[length], &Train::From(u)->gcache, sizeof(GroundVehicleCache)) != 0) { DEBUG(desync, 2, "train ground vehicle cache mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); } if (memcmp(&tra_cache[length], &Train::From(u)->tcache, sizeof(TrainCache)) != 0) { DEBUG(desync, 2, "train cache mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); } break; case VEH_ROAD: if (memcmp(&gro_cache[length], &RoadVehicle::From(u)->gcache, sizeof(GroundVehicleCache)) != 0) { DEBUG(desync, 2, "road vehicle ground vehicle cache mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); } break; default: break; } length++; } free(grf_cache); free(veh_cache); free(gro_cache); free(tra_cache); } /* Check whether the caches are still valid */ FOR_ALL_VEHICLES(v) { byte buff[sizeof(VehicleCargoList)]; memcpy(buff, &v->cargo, sizeof(VehicleCargoList)); v->cargo.InvalidateCache(); assert(memcmp(&v->cargo, buff, sizeof(VehicleCargoList)) == 0); } Station *st; FOR_ALL_STATIONS(st) { for (CargoID c = 0; c < NUM_CARGO; c++) { byte buff[sizeof(StationCargoList)]; memcpy(buff, &st->goods[c].cargo, sizeof(StationCargoList)); st->goods[c].cargo.InvalidateCache(); assert(memcmp(&st->goods[c].cargo, buff, sizeof(StationCargoList)) == 0); } } }