mirror of
https://github.com/OpenTTD/OpenTTD
synced 2026-01-17 09:22:42 +01:00
Codechange: Use vector for airport tile layouts. (#12607)
Simplify AirportSpec data by storing layout information together in a vector, instead of separate arrays. This removes manual memory management and separate count members. The default layouts will be copied instead of always referring to the originals.
This commit is contained in:
161
src/newgrf.cpp
161
src/newgrf.cpp
@@ -3861,32 +3861,6 @@ static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of the tile table so it can be freed later
|
||||
* without problems.
|
||||
* @param as The AirportSpec to copy the arrays of.
|
||||
*/
|
||||
static void DuplicateTileTable(AirportSpec *as)
|
||||
{
|
||||
AirportTileTable **table_list = MallocT<AirportTileTable*>(as->num_table);
|
||||
for (int i = 0; i < as->num_table; i++) {
|
||||
uint num_tiles = 1;
|
||||
const AirportTileTable *it = as->table[0];
|
||||
do {
|
||||
num_tiles++;
|
||||
} while ((++it)->ti.x != -0x80);
|
||||
table_list[i] = MallocT<AirportTileTable>(num_tiles);
|
||||
MemCpyT(table_list[i], as->table[i], num_tiles);
|
||||
}
|
||||
as->table = table_list;
|
||||
HangarTileTable *depot_table = MallocT<HangarTileTable>(as->nof_depots);
|
||||
MemCpyT(depot_table, as->depot_table, as->nof_depots);
|
||||
as->depot_table = depot_table;
|
||||
Direction *rotation = MallocT<Direction>(as->num_table);
|
||||
MemCpyT(rotation, as->rotation, as->num_table);
|
||||
as->rotation = rotation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define properties for airports
|
||||
* @param airport Local ID of the airport.
|
||||
@@ -3942,89 +3916,68 @@ static ChangeInfoResult AirportChangeInfo(uint airport, int numinfo, int prop, B
|
||||
as->grf_prop.grffile = _cur.grffile;
|
||||
/* override the default airport */
|
||||
_airport_mngr.Add(airport + i, _cur.grffile->grfid, subs_id);
|
||||
/* Create a copy of the original tiletable so it can be freed later. */
|
||||
DuplicateTileTable(as);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x0A: { // Set airport layout
|
||||
uint8_t old_num_table = as->num_table;
|
||||
free(as->rotation);
|
||||
as->num_table = buf->ReadByte(); // Number of layaouts
|
||||
as->rotation = MallocT<Direction>(as->num_table);
|
||||
uint32_t defsize = buf->ReadDWord(); // Total size of the definition
|
||||
AirportTileTable **tile_table = CallocT<AirportTileTable*>(as->num_table); // Table with tiles to compose the airport
|
||||
AirportTileTable *att = CallocT<AirportTileTable>(defsize); // Temporary array to read the tile layouts from the GRF
|
||||
int size;
|
||||
const AirportTileTable *copy_from;
|
||||
try {
|
||||
for (uint8_t j = 0; j < as->num_table; j++) {
|
||||
const_cast<Direction&>(as->rotation[j]) = (Direction)buf->ReadByte();
|
||||
for (int k = 0;; k++) {
|
||||
att[k].ti.x = buf->ReadByte(); // Offsets from northermost tile
|
||||
att[k].ti.y = buf->ReadByte();
|
||||
uint8_t num_layouts = buf->ReadByte();
|
||||
buf->ReadDWord(); // Total size of definition, unneeded.
|
||||
uint8_t size_x = 0;
|
||||
uint8_t size_y = 0;
|
||||
|
||||
if (att[k].ti.x == 0 && att[k].ti.y == 0x80) {
|
||||
/* Not the same terminator. The one we are using is rather
|
||||
* x = -80, y = 0 . So, adjust it. */
|
||||
att[k].ti.x = -0x80;
|
||||
att[k].ti.y = 0;
|
||||
att[k].gfx = 0;
|
||||
std::vector<AirportTileLayout> layouts;
|
||||
layouts.reserve(num_layouts);
|
||||
|
||||
size = k + 1;
|
||||
copy_from = att;
|
||||
break;
|
||||
}
|
||||
for (uint8_t j = 0; j != num_layouts; ++j) {
|
||||
auto &layout = layouts.emplace_back();
|
||||
layout.rotation = static_cast<Direction>(buf->ReadByte() & 6); // Rotation can only be DIR_NORTH, DIR_EAST, DIR_SOUTH or DIR_WEST.
|
||||
|
||||
att[k].gfx = buf->ReadByte();
|
||||
|
||||
if (att[k].gfx == 0xFE) {
|
||||
/* Use a new tile from this GRF */
|
||||
int local_tile_id = buf->ReadWord();
|
||||
|
||||
/* Read the ID from the _airporttile_mngr. */
|
||||
uint16_t tempid = _airporttile_mngr.GetID(local_tile_id, _cur.grffile->grfid);
|
||||
|
||||
if (tempid == INVALID_AIRPORTTILE) {
|
||||
GrfMsg(2, "AirportChangeInfo: Attempt to use airport tile {} with airport id {}, not yet defined. Ignoring.", local_tile_id, airport + i);
|
||||
} else {
|
||||
/* Declared as been valid, can be used */
|
||||
att[k].gfx = tempid;
|
||||
}
|
||||
} else if (att[k].gfx == 0xFF) {
|
||||
att[k].ti.x = (int8_t)GB(att[k].ti.x, 0, 8);
|
||||
att[k].ti.y = (int8_t)GB(att[k].ti.y, 0, 8);
|
||||
}
|
||||
|
||||
if (as->rotation[j] == DIR_E || as->rotation[j] == DIR_W) {
|
||||
as->size_x = std::max<uint8_t>(as->size_x, att[k].ti.y + 1);
|
||||
as->size_y = std::max<uint8_t>(as->size_y, att[k].ti.x + 1);
|
||||
} else {
|
||||
as->size_x = std::max<uint8_t>(as->size_x, att[k].ti.x + 1);
|
||||
as->size_y = std::max<uint8_t>(as->size_y, att[k].ti.y + 1);
|
||||
}
|
||||
for (;;) {
|
||||
auto &tile = layout.tiles.emplace_back();
|
||||
tile.ti.x = buf->ReadByte();
|
||||
tile.ti.y = buf->ReadByte();
|
||||
if (tile.ti.x == 0 && tile.ti.y == 0x80) {
|
||||
/* Convert terminator to our own. */
|
||||
tile.ti.x = -0x80;
|
||||
tile.ti.y = 0;
|
||||
tile.gfx = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
tile.gfx = buf->ReadByte();
|
||||
|
||||
if (tile.gfx == 0xFE) {
|
||||
/* Use a new tile from this GRF */
|
||||
int local_tile_id = buf->ReadWord();
|
||||
|
||||
/* Read the ID from the _airporttile_mngr. */
|
||||
uint16_t tempid = _airporttile_mngr.GetID(local_tile_id, _cur.grffile->grfid);
|
||||
|
||||
if (tempid == INVALID_AIRPORTTILE) {
|
||||
GrfMsg(2, "AirportChangeInfo: Attempt to use airport tile {} with airport id {}, not yet defined. Ignoring.", local_tile_id, airport + i);
|
||||
} else {
|
||||
/* Declared as been valid, can be used */
|
||||
tile.gfx = tempid;
|
||||
}
|
||||
} else if (tile.gfx == 0xFF) {
|
||||
tile.ti.x = static_cast<int8_t>(GB(tile.ti.x, 0, 8));
|
||||
tile.ti.y = static_cast<int8_t>(GB(tile.ti.y, 0, 8));
|
||||
}
|
||||
|
||||
/* Determine largest size. */
|
||||
if (layout.rotation == DIR_E || layout.rotation == DIR_W) {
|
||||
size_x = std::max<uint8_t>(size_x, tile.ti.y + 1);
|
||||
size_y = std::max<uint8_t>(size_y, tile.ti.x + 1);
|
||||
} else {
|
||||
size_x = std::max<uint8_t>(size_x, tile.ti.x + 1);
|
||||
size_y = std::max<uint8_t>(size_y, tile.ti.y + 1);
|
||||
}
|
||||
tile_table[j] = CallocT<AirportTileTable>(size);
|
||||
memcpy(tile_table[j], copy_from, sizeof(*copy_from) * size);
|
||||
}
|
||||
/* Free old layouts in the airport spec */
|
||||
for (int j = 0; j < old_num_table; j++) {
|
||||
/* remove the individual layouts */
|
||||
free(as->table[j]);
|
||||
}
|
||||
free(as->table);
|
||||
/* Install final layout construction in the airport spec */
|
||||
as->table = tile_table;
|
||||
free(att);
|
||||
} catch (...) {
|
||||
for (int i = 0; i < as->num_table; i++) {
|
||||
free(tile_table[i]);
|
||||
}
|
||||
free(tile_table);
|
||||
free(att);
|
||||
throw;
|
||||
}
|
||||
as->layouts = std::move(layouts);
|
||||
as->size_x = size_x;
|
||||
as->size_y = size_y;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -8726,18 +8679,6 @@ static void ResetCustomHouses()
|
||||
static void ResetCustomAirports()
|
||||
{
|
||||
for (GRFFile * const file : _grf_files) {
|
||||
for (auto &as : file->airportspec) {
|
||||
if (as != nullptr) {
|
||||
/* We need to remove the tiles layouts */
|
||||
for (int j = 0; j < as->num_table; j++) {
|
||||
/* remove the individual layouts */
|
||||
free(as->table[j]);
|
||||
}
|
||||
free(as->table);
|
||||
free(as->depot_table);
|
||||
free(as->rotation);
|
||||
}
|
||||
}
|
||||
file->airportspec.clear();
|
||||
file->airtspec.clear();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user