Adjust various water region types

This commit is contained in:
Jonathan G Rennison 2024-01-09 20:55:27 +00:00
parent 45205a4284
commit c2e1dfcfc1
3 changed files with 44 additions and 37 deletions

View File

@ -19,6 +19,8 @@
#include "follow_track.hpp"
#include "ship.h"
#include <array>
using TWaterRegionTraversabilityBits = uint16_t;
constexpr TWaterRegionPatchLabel FIRST_REGION_LABEL = 1;
constexpr TWaterRegionPatchLabel INVALID_WATER_REGION_PATCH = 0;
@ -28,13 +30,13 @@ static_assert(sizeof(TWaterRegionTraversabilityBits) * 8 == WATER_REGION_EDGE_LE
static inline TrackBits GetWaterTracks(TileIndex tile) { return TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_WATER, 0)); }
static inline bool IsAqueductTile(TileIndex tile) { return IsBridgeTile(tile) && GetTunnelBridgeTransportType(tile) == TRANSPORT_WATER; }
static inline int GetWaterRegionX(TileIndex tile) { return TileX(tile) / WATER_REGION_EDGE_LENGTH; }
static inline int GetWaterRegionY(TileIndex tile) { return TileY(tile) / WATER_REGION_EDGE_LENGTH; }
static inline uint32_t GetWaterRegionX(TileIndex tile) { return TileX(tile) / WATER_REGION_EDGE_LENGTH; }
static inline uint32_t GetWaterRegionY(TileIndex tile) { return TileY(tile) / WATER_REGION_EDGE_LENGTH; }
static inline int GetWaterRegionMapSizeX() { return MapSizeX() / WATER_REGION_EDGE_LENGTH; }
static inline int GetWaterRegionMapSizeY() { return MapSizeY() / WATER_REGION_EDGE_LENGTH; }
static inline uint32_t GetWaterRegionMapSizeX() { return MapSizeX() / WATER_REGION_EDGE_LENGTH; }
static inline uint32_t GetWaterRegionMapSizeY() { return MapSizeY() / WATER_REGION_EDGE_LENGTH; }
static inline TWaterRegionIndex GetWaterRegionIndex(int region_x, int region_y) { return GetWaterRegionMapSizeX() * region_y + region_x; }
static inline TWaterRegionIndex GetWaterRegionIndex(uint32_t region_x, uint32_t region_y) { return GetWaterRegionMapSizeX() * region_y + region_x; }
static inline TWaterRegionIndex GetWaterRegionIndex(TileIndex tile) { return GetWaterRegionIndex(GetWaterRegionX(tile), GetWaterRegionY(tile)); }
/**
@ -66,7 +68,7 @@ private:
}
public:
WaterRegion(int region_x, int region_y)
WaterRegion(uint32_t region_x, uint32_t region_y)
: tile_area(TileXY(region_x * WATER_REGION_EDGE_LENGTH, region_y * WATER_REGION_EDGE_LENGTH), WATER_REGION_EDGE_LENGTH, WATER_REGION_EDGE_LENGTH)
{}
@ -168,9 +170,9 @@ public:
/* Calculate the traversability (whether the tile can be entered / exited) for all edges. Note that
* we always follow the same X and Y scanning direction, this is important for comparisons later on! */
this->edge_traversability_bits.fill(0);
const int top_x = TileX(tile_area.tile);
const int top_y = TileY(tile_area.tile);
for (int i = 0; i < WATER_REGION_EDGE_LENGTH; ++i) {
const uint32_t top_x = TileX(tile_area.tile);
const uint32_t top_y = TileY(tile_area.tile);
for (uint32_t i = 0; i < WATER_REGION_EDGE_LENGTH; ++i) {
if (GetWaterTracks(TileXY(top_x + i, top_y)) & TRACK_BIT_3WAY_NW) SetBit(this->edge_traversability_bits[DIAGDIR_NW], i); // NW edge
if (GetWaterTracks(TileXY(top_x + i, top_y + WATER_REGION_EDGE_LENGTH - 1)) & TRACK_BIT_3WAY_SE) SetBit(this->edge_traversability_bits[DIAGDIR_SE], i); // SE edge
if (GetWaterTracks(TileXY(top_x, top_y + i)) & TRACK_BIT_3WAY_NE) SetBit(this->edge_traversability_bits[DIAGDIR_NE], i); // NE edge
@ -189,16 +191,16 @@ public:
std::vector<WaterRegion> _water_regions;
TileIndex GetTileIndexFromLocalCoordinate(int region_x, int region_y, int local_x, int local_y)
TileIndex GetTileIndexFromLocalCoordinate(uint32_t region_x, uint32_t region_y, uint32_t local_x, uint32_t local_y)
{
assert(local_x >= 0 && local_y < WATER_REGION_EDGE_LENGTH);
assert(local_y >= 0 && local_y < WATER_REGION_EDGE_LENGTH);
assert(local_x < WATER_REGION_EDGE_LENGTH);
assert(local_y < WATER_REGION_EDGE_LENGTH);
return TileXY(WATER_REGION_EDGE_LENGTH * region_x + local_x, WATER_REGION_EDGE_LENGTH * region_y + local_y);
}
TileIndex GetEdgeTileCoordinate(int region_x, int region_y, DiagDirection side, int x_or_y)
TileIndex GetEdgeTileCoordinate(uint32_t region_x, uint32_t region_y, DiagDirection side, uint32_t x_or_y)
{
assert(x_or_y >= 0 && x_or_y < WATER_REGION_EDGE_LENGTH);
assert(x_or_y < WATER_REGION_EDGE_LENGTH);
switch (side) {
case DIAGDIR_NE: return GetTileIndexFromLocalCoordinate(region_x, region_y, 0, x_or_y);
case DIAGDIR_SW: return GetTileIndexFromLocalCoordinate(region_x, region_y, WATER_REGION_EDGE_LENGTH - 1, x_or_y);
@ -208,7 +210,7 @@ TileIndex GetEdgeTileCoordinate(int region_x, int region_y, DiagDirection side,
}
}
WaterRegion &GetUpdatedWaterRegion(uint16_t region_x, uint16_t region_y)
WaterRegion &GetUpdatedWaterRegion(uint32_t region_x, uint32_t region_y)
{
WaterRegion &result = _water_regions[GetWaterRegionIndex(region_x, region_y)];
result.UpdateIfNotInitialized();
@ -266,8 +268,8 @@ WaterRegionPatchDesc GetWaterRegionPatchInfo(TileIndex tile)
*/
void InvalidateWaterRegion(TileIndex tile)
{
const int index = GetWaterRegionIndex(tile);
if (index > static_cast<int>(_water_regions.size())) return;
const uint32_t index = GetWaterRegionIndex(tile);
if (index > static_cast<uint32_t>(_water_regions.size())) return;
_water_regions[index].Invalidate();
}
@ -283,10 +285,11 @@ static inline void VisitAdjacentWaterRegionPatchNeighbors(const WaterRegionPatch
const WaterRegion &current_region = GetUpdatedWaterRegion(water_region_patch.x, water_region_patch.y);
const TileIndexDiffC offset = TileIndexDiffCByDiagDir(side);
const int nx = water_region_patch.x + offset.x;
const int ny = water_region_patch.y + offset.y;
/* Unsigned underflow is allowed here, not UB */
const uint32_t nx = water_region_patch.x + (uint32_t)offset.x;
const uint32_t ny = water_region_patch.y + (uint32_t)offset.y;
if (nx < 0 || ny < 0 || nx >= GetWaterRegionMapSizeX() || ny >= GetWaterRegionMapSizeY()) return;
if (nx >= GetWaterRegionMapSizeX() || ny >= GetWaterRegionMapSizeY()) return;
const WaterRegion &neighboring_region = GetUpdatedWaterRegion(nx, ny);
const DiagDirection opposite_side = ReverseDiagDir(side);
@ -304,7 +307,7 @@ static inline void VisitAdjacentWaterRegionPatchNeighbors(const WaterRegionPatch
/* Multiple water patches can be reached from the current patch. Check each edge tile individually. */
static std::vector<TWaterRegionPatchLabel> unique_labels; // static and vector-instead-of-map for performance reasons
unique_labels.clear();
for (int x_or_y = 0; x_or_y < WATER_REGION_EDGE_LENGTH; ++x_or_y) {
for (uint32_t x_or_y = 0; x_or_y < WATER_REGION_EDGE_LENGTH; ++x_or_y) {
if (!HasBit(traversability_bits, x_or_y)) continue;
const TileIndex current_edge_tile = GetEdgeTileCoordinate(water_region_patch.x, water_region_patch.y, side, x_or_y);
@ -355,8 +358,8 @@ void LoadWaterRegions(const std::vector<WaterRegionSaveLoadInfo> &save_load_info
_water_regions.reserve(save_load_info.size());
TWaterRegionIndex index = 0;
for (const auto &loaded_region_info : save_load_info) {
const int region_x = index % GetWaterRegionMapSizeX();
const int region_y = index / GetWaterRegionMapSizeX();
const uint32_t region_x = index % GetWaterRegionMapSizeX();
const uint32_t region_y = index / GetWaterRegionMapSizeX();
WaterRegion &region = _water_regions.emplace_back(region_x, region_y);
if (loaded_region_info.initialized) region.ForceUpdate();
index++;
@ -371,8 +374,8 @@ void InitializeWaterRegions()
_water_regions.clear();
_water_regions.reserve(static_cast<size_t>(GetWaterRegionMapSizeX()) * GetWaterRegionMapSizeY());
for (int region_y = 0; region_y < GetWaterRegionMapSizeY(); region_y++) {
for (int region_x = 0; region_x < GetWaterRegionMapSizeX(); region_x++) {
for (uint32_t region_y = 0; region_y < GetWaterRegionMapSizeY(); region_y++) {
for (uint32_t region_x = 0; region_x < GetWaterRegionMapSizeX(); region_x++) {
_water_regions.emplace_back(region_x, region_y).ForceUpdate();
}
}

View File

@ -13,19 +13,22 @@
#include "tile_type.h"
#include "map_func.h"
using TWaterRegionPatchLabel = uint8_t;
using TWaterRegionIndex = uint;
#include <vector>
#include <functional>
constexpr int WATER_REGION_EDGE_LENGTH = 16;
constexpr int WATER_REGION_NUMBER_OF_TILES = WATER_REGION_EDGE_LENGTH * WATER_REGION_EDGE_LENGTH;
using TWaterRegionPatchLabel = uint8_t;
using TWaterRegionIndex = uint32_t;
constexpr uint32_t WATER_REGION_EDGE_LENGTH = 16;
constexpr uint32_t WATER_REGION_NUMBER_OF_TILES = WATER_REGION_EDGE_LENGTH * WATER_REGION_EDGE_LENGTH;
/**
* Describes a single interconnected patch of water within a particular water region.
*/
struct WaterRegionPatchDesc
{
int x; ///< The X coordinate of the water region, i.e. X=2 is the 3rd water region along the X-axis
int y; ///< The Y coordinate of the water region, i.e. Y=2 is the 3rd water region along the Y-axis
uint32_t x; ///< The X coordinate of the water region, i.e. X=2 is the 3rd water region along the X-axis
uint32_t y; ///< The Y coordinate of the water region, i.e. Y=2 is the 3rd water region along the Y-axis
TWaterRegionPatchLabel label; ///< Unique label identifying the patch within the region
bool operator==(const WaterRegionPatchDesc &other) const { return x == other.x && y == other.y && label == other.label; }
@ -38,10 +41,10 @@ struct WaterRegionPatchDesc
*/
struct WaterRegionDesc
{
int x; ///< The X coordinate of the water region, i.e. X=2 is the 3rd water region along the X-axis
int y; ///< The Y coordinate of the water region, i.e. Y=2 is the 3rd water region along the Y-axis
uint32_t x; ///< The X coordinate of the water region, i.e. X=2 is the 3rd water region along the X-axis
uint32_t y; ///< The Y coordinate of the water region, i.e. Y=2 is the 3rd water region along the Y-axis
WaterRegionDesc(const int x, const int y) : x(x), y(y) {}
WaterRegionDesc(const uint32_t x, const uint32_t y) : x(x), y(y) {}
WaterRegionDesc(const WaterRegionPatchDesc &water_region_patch) : x(water_region_patch.x), y(water_region_patch.y) {}
bool operator==(const WaterRegionDesc &other) const { return x == other.x && y == other.y; }

View File

@ -9,6 +9,7 @@
#include "../../stdafx.h"
#include "../../ship.h"
#include "../../core/math_func.hpp"
#include "yapf.hpp"
#include "yapf_ship_regions.h"
@ -18,7 +19,7 @@
constexpr int DIRECT_NEIGHBOR_COST = 100;
constexpr int NODES_PER_REGION = 4;
constexpr int MAX_NUMBER_OF_NODES = 65536;
constexpr uint32_t MAX_NUMBER_OF_NODES = 65536;
/** Yapf Node Key that represents a single patch of interconnected water within a water region. */
struct CYapfRegionPatchNodeKey {
@ -37,7 +38,7 @@ struct CYapfRegionPatchNodeKey {
inline uint ManhattanDistance(const CYapfRegionPatchNodeKey &a, const CYapfRegionPatchNodeKey &b)
{
return (std::abs(a.m_water_region_patch.x - b.m_water_region_patch.x) + std::abs(a.m_water_region_patch.y - b.m_water_region_patch.y)) * DIRECT_NEIGHBOR_COST;
return (Delta(a.m_water_region_patch.x, b.m_water_region_patch.x) + Delta(a.m_water_region_patch.y, b.m_water_region_patch.y)) * DIRECT_NEIGHBOR_COST;
}
/** Yapf Node for water regions. */
@ -195,7 +196,7 @@ public:
/* We reserve 4 nodes (patches) per water region. The vast majority of water regions have 1 or 2 regions so this should be a pretty
* safe limit. We cap the limit at 65536 which is at a region size of 16x16 is equivalent to one node per region for a 4096x4096 map. */
Tpf pf(std::min(static_cast<int>(MapSize() * NODES_PER_REGION) / WATER_REGION_NUMBER_OF_TILES, MAX_NUMBER_OF_NODES));
Tpf pf(std::min(static_cast<uint32_t>(MapSize() * NODES_PER_REGION) / WATER_REGION_NUMBER_OF_TILES, MAX_NUMBER_OF_NODES));
pf.SetDestination(start_water_region_patch);
if (v->current_order.IsType(OT_GOTO_STATION)) {