Find buildings
Every building of a given type
private static readonly BuildingDefinitionId CutterId = new BuildingDefinitionId("Cutter");
private static void FindAllCutters(IMapModel map, List<BuildingModel> results)
{
results.Clear();
foreach (BuildingModel building in map.Buildings)
{
if (building.Definition.Id == CutterId)
{
results.Add(building);
}
}
}
To get the real ids, dump them once rather than guessing:
foreach (BuildingModel building in map.Buildings)
{
Logger.Info?.Log(building.Definition.Id.ToString());
}
Finding definition ids
Two ways, and the first is easier:
debug.export-game-data — press F1 in game and run it. The game writes its
content out as JSON, definition ids included. This is also where milestone ids and
scenario data come from.
Log them at runtime — useful when you want only what is actually placed:
foreach (BuildingModel building in map.Buildings)
{
Logger.Info?.Log(building.Definition.Id.ToString());
}
Per island instead of the whole map
Usually what you actually want — it keeps the working set small and gives you somewhere to attribute results:
List<BuildingModel> buildings = new List<BuildingModel>();
foreach (IslandModel island in map.Islands)
{
buildings.Clear();
island.GetBuildings(buildings); // reuses your list — no allocation
foreach (BuildingModel building in buildings)
{
// …
}
}
Prefer island.GetBuildings(list) over the island.Buildings property in any loop that
runs repeatedly: the property is an iterator that rents a scoped list on every call.
The building at a tile
if (map.TryGetBuilding(tile_G, out BuildingModel building))
{
// …
}
Or island-relative, when you already have the island:
if (island.TryGetBuilding(in tile_I, out BuildingModel building))
{
// …
}
Use the TryGet… forms. The Get… forms throw when nothing is there.
Buildings in a region
foreach (BuildingId id in map.GetChunkBuildings(chunk_GC))
{
if (map.TryGetBuilding(id, out BuildingModel building))
{
// …
}
}
GetChunkBuildings yields ids, not models — a multi-tile building spanning two chunks
appears in both, so de-duplicate by BuildingId if that matters to you.
Reacting to buildings appearing and disappearing
Instead of rescanning, subscribe:
map.OnBuildingAdded.Register(OnBuildingAdded);
map.OnBeforeBuildingRemoved.Register(OnBuildingRemoved);
// and the island equivalents:
map.OnIslandAdded.Register(OnIslandAdded);
map.OnBeforeIslandRemoved.Register(OnIslandRemoved);
Note the asymmetry: added fires after, removed fires before. In the remove handler the building is still valid, so you can read it one last time — which is your only chance to clean up anything keyed by it.
Unregister these when the map goes away (Run code when a game loads).
Gotchas
- Do not cache
BuildingModellong-term. It is a struct handle; when the building is deleted it goes stale rather than null. CacheBuildingIdand look it up again. BuildingModel.IsValiddoes a full map lookup on every read. Use it once to check a stored handle, never inside a loop.map.Buildingson a large save is tens of thousands of entries. Pace the scan — see Run code when a game loads.