add flood swe module and 2km building bundles

This commit is contained in:
2026-02-04 01:05:20 +01:00
parent 2c77c0d215
commit ff5af7a63a
57 changed files with 5369 additions and 44 deletions

View File

@@ -12,10 +12,15 @@ using UnityEngine;
public static class GeoTileAddressablesBuilder
{
private const string TilePrefabsDir = "Assets/TilePrefabs";
private const string BuildingPrefabsDir = "Assets/TilePrefabs_Buildings";
private const string TileIndexCsvPath = "Assets/GeoData/tile_index.csv";
private const string GroupName = "TilePrefabs";
private const string BuildingGroupName = "TileBuildings";
private const string TileLabel = "tile";
private const string BuildingLabel = "tile_building";
private const string ManifestFileName = "TileManifest.json";
private const string BuildingManifestFileName = "TileBuildingsManifest.json";
private const string BuildingAddressSuffix = "_bldg";
private const float DefaultTileSizeMeters = 1000f;
private const float DefaultTileSizeX = 1000f;
private const float DefaultTileSizeY = 1000f;
@@ -61,6 +66,7 @@ public static class GeoTileAddressablesBuilder
{
public string TileIndexCsvPath;
public string TilePrefabsDir;
public string BuildingPrefabsDir;
public string OutputRoot;
public BuildTarget Target;
public BuildTargetGroup TargetGroup;
@@ -69,6 +75,8 @@ public static class GeoTileAddressablesBuilder
public List<TileRecord> SelectedTiles;
public bool OverwriteExisting;
public bool Verbose;
public bool IncludeBuildingPrefabs;
public int BuildingBlockSizeInTiles;
}
[MenuItem("Tools/Geo Tiles/Build (Android)")]
@@ -91,6 +99,7 @@ public static class GeoTileAddressablesBuilder
{
TileIndexCsvPath = TileIndexCsvPath,
TilePrefabsDir = TilePrefabsDir,
BuildingPrefabsDir = BuildingPrefabsDir,
OutputRoot = "ServerData/TileBundles",
Target = target,
TargetGroup = group,
@@ -98,7 +107,9 @@ public static class GeoTileAddressablesBuilder
TileKeyConfig = TileKeyConfig.Default,
SelectedTiles = null,
OverwriteExisting = false,
Verbose = false
Verbose = false,
IncludeBuildingPrefabs = true,
BuildingBlockSizeInTiles = 2
});
}
@@ -106,8 +117,11 @@ public static class GeoTileAddressablesBuilder
{
var tileIndexCsvPath = string.IsNullOrWhiteSpace(request.TileIndexCsvPath) ? TileIndexCsvPath : request.TileIndexCsvPath;
var tilePrefabsDir = string.IsNullOrWhiteSpace(request.TilePrefabsDir) ? TilePrefabsDir : request.TilePrefabsDir;
var buildingPrefabsDir = string.IsNullOrWhiteSpace(request.BuildingPrefabsDir) ? BuildingPrefabsDir : request.BuildingPrefabsDir;
var outputRoot = string.IsNullOrWhiteSpace(request.OutputRoot) ? "ServerData/TileBundles" : request.OutputRoot;
var tileSizeMeters = request.TileSizeMeters > 0f ? request.TileSizeMeters : DefaultTileSizeMeters;
var includeBuildingPrefabs = request.IncludeBuildingPrefabs;
var buildingBlockSize = Math.Max(1, request.BuildingBlockSizeInTiles);
var tileKeyConfig = request.TileKeyConfig;
if (tileKeyConfig.TileSizeX <= 0f && tileKeyConfig.TileSizeY <= 0f &&
tileKeyConfig.OverlapX == 0f && tileKeyConfig.OverlapY == 0f)
@@ -120,6 +134,11 @@ public static class GeoTileAddressablesBuilder
Debug.LogError($"[GeoTileAddressablesBuilder] Prefab directory missing: {tilePrefabsDir}");
return false;
}
if (includeBuildingPrefabs && !Directory.Exists(buildingPrefabsDir))
{
Debug.LogWarning($"[GeoTileAddressablesBuilder] Building prefab directory missing: {buildingPrefabsDir}. Skipping building bundles.");
includeBuildingPrefabs = false;
}
if (!File.Exists(tileIndexCsvPath))
{
Debug.LogError($"[GeoTileAddressablesBuilder] CSV missing: {tileIndexCsvPath}");
@@ -145,7 +164,7 @@ public static class GeoTileAddressablesBuilder
EnsureProfileVariable(settings, LoadPathVariable, LoadPathValue);
EnsureRemoteCatalogPaths(settings);
var groupAsset = GetOrCreateGroup(settings);
var groupAsset = GetOrCreateGroup(settings, GroupName);
ConfigureGroup(settings, groupAsset);
var assignedTileIds = AssignPrefabs(settings, groupAsset, tilePrefabsDir, tiles, true);
@@ -158,6 +177,18 @@ public static class GeoTileAddressablesBuilder
return false;
}
List<TileRecord> buildingTiles = null;
if (includeBuildingPrefabs)
{
var buildingGroup = GetOrCreateGroup(settings, BuildingGroupName);
ConfigureGroup(settings, buildingGroup);
var anchors = tiles.Where(tile => IsBuildingAnchor(tile, buildingBlockSize)).ToList();
var assignedBuildingIds = AssignBuildingPrefabs(settings, buildingGroup, buildingPrefabsDir, anchors, true);
buildingTiles = anchors
.Where(tile => !string.IsNullOrWhiteSpace(tile.TileId) && assignedBuildingIds.Contains(tile.TileId))
.ToList();
}
settings.SetDirty(AddressableAssetSettings.ModificationEvent.BatchModification, null, true);
AssetDatabase.SaveAssets();
@@ -191,14 +222,43 @@ public static class GeoTileAddressablesBuilder
return false;
}
var manifest = BuildManifest(request.Target.ToString(), catalogFile, catalogHashFile, filteredTiles, tileSizeMeters);
var (originX, originY) = ComputeOrigin(filteredTiles);
var manifest = BuildManifest(
request.Target.ToString(),
catalogFile,
catalogHashFile,
filteredTiles,
tileSizeMeters,
ResolveTileKey,
originX,
originY);
var manifestPath = Path.Combine(outputPath, ManifestFileName);
File.WriteAllText(manifestPath, JsonUtility.ToJson(manifest, true));
if (includeBuildingPrefabs && buildingTiles != null && buildingTiles.Count > 0)
{
var buildingManifest = BuildManifest(
request.Target.ToString(),
catalogFile,
catalogHashFile,
buildingTiles,
tileSizeMeters,
BuildBuildingAddress,
originX,
originY);
var buildingManifestPath = Path.Combine(outputPath, BuildingManifestFileName);
File.WriteAllText(buildingManifestPath, JsonUtility.ToJson(buildingManifest, true));
}
AssetDatabase.Refresh();
if (request.Verbose)
Debug.Log($"[GeoTileAddressablesBuilder] Built {filteredTiles.Count} tiles (from {tiles.Count} selected). Output={outputPath}");
{
var buildingInfo = includeBuildingPrefabs && buildingTiles != null
? $", Buildings={buildingTiles.Count}"
: "";
Debug.Log($"[GeoTileAddressablesBuilder] Built {filteredTiles.Count} tiles (from {tiles.Count} selected){buildingInfo}. Output={outputPath}");
}
return true;
}
@@ -227,7 +287,7 @@ public static class GeoTileAddressablesBuilder
continue;
var entry = settings.CreateOrMoveEntry(guid, group, false, false);
entry.address = tile.TileKey;
entry.address = ResolveTileKey(tile);
entry.SetLabel(TileLabel, true, true);
selectedGuids.Add(guid);
assignedTileIds.Add(tileId);
@@ -254,13 +314,64 @@ public static class GeoTileAddressablesBuilder
return assignedTileIds;
}
private static AddressableAssetGroup GetOrCreateGroup(AddressableAssetSettings settings)
private static HashSet<string> AssignBuildingPrefabs(AddressableAssetSettings settings, AddressableAssetGroup group, string prefabsDir, List<TileRecord> tiles, bool removeUnselected)
{
var group = settings.FindGroup(GroupName);
var tileById = new Dictionary<string, TileRecord>(StringComparer.OrdinalIgnoreCase);
foreach (var tile in tiles)
{
if (!string.IsNullOrWhiteSpace(tile.TileId))
tileById[tile.TileId] = tile;
}
var assignedTileIds = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
var selectedGuids = new HashSet<string>();
var prefabGuids = AssetDatabase.FindAssets("t:Prefab", new[] { prefabsDir });
foreach (var guid in prefabGuids)
{
var path = AssetDatabase.GUIDToAssetPath(guid).Replace("\\", "/");
var parentDir = Path.GetDirectoryName(path)?.Replace("\\", "/");
if (!string.Equals(parentDir, prefabsDir, StringComparison.OrdinalIgnoreCase))
continue;
var tileId = Path.GetFileNameWithoutExtension(path);
if (!tileById.TryGetValue(tileId, out var tile))
continue;
var entry = settings.CreateOrMoveEntry(guid, group, false, false);
entry.address = BuildBuildingAddress(tile);
entry.SetLabel(BuildingLabel, true, true);
selectedGuids.Add(guid);
assignedTileIds.Add(tileId);
}
if (!removeUnselected)
return assignedTileIds;
var entries = group.entries.ToList();
foreach (var entry in entries)
{
if (entry == null || string.IsNullOrWhiteSpace(entry.AssetPath))
continue;
var entryPath = entry.AssetPath.Replace("\\", "/");
var entryDir = Path.GetDirectoryName(entryPath)?.Replace("\\", "/");
if (!string.Equals(entryDir, prefabsDir, StringComparison.OrdinalIgnoreCase))
continue;
if (!selectedGuids.Contains(entry.guid))
group.RemoveAssetEntry(entry);
}
return assignedTileIds;
}
private static AddressableAssetGroup GetOrCreateGroup(AddressableAssetSettings settings, string groupName)
{
var group = settings.FindGroup(groupName);
if (group != null)
return group;
group = settings.CreateGroup(GroupName, false, false, false, new List<AddressableAssetGroupSchema>());
group = settings.CreateGroup(groupName, false, false, false, new List<AddressableAssetGroupSchema>());
group.AddSchema<BundledAssetGroupSchema>();
group.AddSchema<ContentUpdateGroupSchema>();
return group;
@@ -327,17 +438,37 @@ public static class GeoTileAddressablesBuilder
}
private static TileManifest BuildManifest(string buildTarget, string catalogFile, string catalogHashFile, List<TileRecord> tiles, float tileSizeMeters)
=> BuildManifest(buildTarget, catalogFile, catalogHashFile, tiles, tileSizeMeters, ResolveTileKey, null, null);
private static TileManifest BuildManifest(
string buildTarget,
string catalogFile,
string catalogHashFile,
List<TileRecord> tiles,
float tileSizeMeters,
Func<TileRecord, string> keyResolver,
double? originX,
double? originY)
{
if (tiles.Count == 0)
throw new InvalidOperationException("No tiles selected for TileManifest.");
double minX = double.PositiveInfinity;
double minY = double.PositiveInfinity;
foreach (var tile in tiles)
double minX;
double minY;
if (originX.HasValue && originY.HasValue)
{
minX = Math.Min(minX, tile.Xmin);
minY = Math.Min(minY, tile.Ymin);
minX = originX.Value;
minY = originY.Value;
}
else
{
minX = double.PositiveInfinity;
minY = double.PositiveInfinity;
foreach (var tile in tiles)
{
minX = Math.Min(minX, tile.Xmin);
minY = Math.Min(minY, tile.Ymin);
}
}
var entries = new TileEntry[tiles.Count];
@@ -346,7 +477,7 @@ public static class GeoTileAddressablesBuilder
var tile = tiles[i];
entries[i] = new TileEntry
{
tileKey = tile.TileKey,
tileKey = keyResolver(tile),
tileId = tile.TileId,
offsetX = (float)(tile.Xmin - minX),
offsetZ = (float)(tile.Ymin - minY),
@@ -366,6 +497,28 @@ public static class GeoTileAddressablesBuilder
};
}
private static (double originX, double originY) ComputeOrigin(List<TileRecord> tiles)
{
double minX = double.PositiveInfinity;
double minY = double.PositiveInfinity;
foreach (var tile in tiles)
{
minX = Math.Min(minX, tile.Xmin);
minY = Math.Min(minY, tile.Ymin);
}
return (minX, minY);
}
private static string ResolveTileKey(TileRecord tile)
=> string.IsNullOrWhiteSpace(tile.TileKey) ? tile.TileId : tile.TileKey;
private static string BuildBuildingAddress(TileRecord tile)
=> $"{ResolveTileKey(tile)}{BuildingAddressSuffix}";
private static bool IsBuildingAnchor(TileRecord tile, int blockSize)
=> (tile.XKey % blockSize == 0) && (tile.YKey % blockSize == 0);
private static string GetRemoteCatalogBuildPath(AddressableAssetSettings settings, BuildTarget target)
{
var rawPath = settings.RemoteCatalogBuildPath.GetValue(settings);