Files
DTrierFlood_New/Assets/Scripts/Networking/Shared/SweBoundaryManifest.cs

356 lines
12 KiB
C#

using System;
using System.Collections.Generic;
using UnityEngine;
namespace FloodSWE.Networking
{
[Serializable]
public sealed class SweBoundaryManifest
{
public int schema_version;
public string boundary_inflow_mask_dir;
public string source_area_mask_dir;
public string sink_mask_dir;
public string boundary_inflow_params_toml;
public string source_area_params_toml;
public string sink_params_toml;
public SweBoundarySource[] sources;
public SweBoundarySink[] sinks;
public SweBoundaryDefinition[] boundaries;
public SweBoundaryTile[] tiles;
[NonSerialized] private Dictionary<string, SweBoundaryTile> tileLookup;
[NonSerialized] private Dictionary<string, SweBoundaryDefinition> boundaryLookup;
[NonSerialized] private Dictionary<int, SweBoundarySource> sourceLookup;
[NonSerialized] private Dictionary<int, SweBoundarySink> sinkLookup;
public static bool TryLoad(string json, out SweBoundaryManifest manifest)
{
manifest = null;
if (string.IsNullOrWhiteSpace(json))
{
return false;
}
try
{
manifest = JsonUtility.FromJson<SweBoundaryManifest>(json);
if (manifest == null)
{
return false;
}
manifest.BuildLookup();
return true;
}
catch (Exception ex)
{
Debug.LogWarning($"SweBoundaryManifest: failed to parse manifest. {ex.Message}");
return false;
}
}
public bool TryGetTile(string lod, int tileX, int tileY, out SweBoundaryTile tile)
{
tile = null;
if (tileLookup == null)
{
BuildLookup();
}
return tileLookup != null && tileLookup.TryGetValue(MakeTileKey(lod, tileX, tileY), out tile);
}
public bool TryGetSource(int id, out SweBoundarySource source)
{
source = null;
if (sourceLookup == null)
{
BuildLookup();
}
return sourceLookup != null && sourceLookup.TryGetValue(id, out source);
}
public bool TryGetBoundary(string kind, int id, out SweBoundaryDefinition boundary)
{
boundary = null;
if (boundaryLookup == null)
{
BuildLookup();
}
return boundaryLookup != null && boundaryLookup.TryGetValue(MakeBoundaryKey(kind, id), out boundary);
}
public bool TryGetSink(int id, out SweBoundarySink sink)
{
sink = null;
if (sinkLookup == null)
{
BuildLookup();
}
return sinkLookup != null && sinkLookup.TryGetValue(id, out sink);
}
public static int ParseLod(string lod)
{
if (string.IsNullOrWhiteSpace(lod))
{
return 0;
}
string value = lod.Trim().ToLowerInvariant();
if (value.StartsWith("lod", StringComparison.Ordinal))
{
value = value.Substring(3);
}
return int.TryParse(value, out int parsed) ? parsed : 0;
}
private void BuildLookup()
{
tileLookup = new Dictionary<string, SweBoundaryTile>(StringComparer.OrdinalIgnoreCase);
boundaryLookup = new Dictionary<string, SweBoundaryDefinition>(StringComparer.OrdinalIgnoreCase);
sourceLookup = new Dictionary<int, SweBoundarySource>();
sinkLookup = new Dictionary<int, SweBoundarySink>();
if (tiles == null)
{
tileLookup = tileLookup ?? new Dictionary<string, SweBoundaryTile>(StringComparer.OrdinalIgnoreCase);
}
if (tiles != null)
{
for (int i = 0; i < tiles.Length; i++)
{
SweBoundaryTile tile = tiles[i];
if (tile == null)
{
continue;
}
tileLookup[MakeTileKey(tile.lod, tile.tile_x, tile.tile_y)] = tile;
}
}
if (boundaries != null && boundaries.Length > 0)
{
for (int i = 0; i < boundaries.Length; i++)
{
SweBoundaryDefinition boundary = boundaries[i];
if (boundary == null || boundary.id <= 0)
{
continue;
}
if (boundary.default_state == null)
{
boundary.default_state = SweBoundaryDefaultState.DefaultFor(boundary.kind, boundary.@params);
}
boundaryLookup[MakeBoundaryKey(boundary.kind, boundary.id)] = boundary;
}
}
if (sources != null)
{
for (int i = 0; i < sources.Length; i++)
{
SweBoundarySource source = sources[i];
if (source != null)
{
sourceLookup[source.id] = source;
string key = MakeBoundaryKey("boundary_inflow", source.id);
if (!boundaryLookup.ContainsKey(key))
{
boundaryLookup[key] = new SweBoundaryDefinition
{
kind = "boundary_inflow",
id = source.id,
tile_count = source.tile_count,
total_pixels = source.total_pixels,
@params = source.@params,
default_state = SweBoundaryDefaultState.DefaultFor("boundary_inflow", source.@params),
};
}
}
}
}
if (sinks != null)
{
for (int i = 0; i < sinks.Length; i++)
{
SweBoundarySink sink = sinks[i];
if (sink != null)
{
sinkLookup[sink.id] = sink;
string key = MakeBoundaryKey("sink", sink.id);
if (!boundaryLookup.ContainsKey(key))
{
boundaryLookup[key] = new SweBoundaryDefinition
{
kind = "sink",
id = sink.id,
tile_count = sink.tile_count,
total_pixels = sink.total_pixels,
@params = sink.@params,
default_state = SweBoundaryDefaultState.DefaultFor("sink", sink.@params),
};
}
}
}
}
}
private static string MakeTileKey(string lod, int tileX, int tileY)
{
return $"{lod}|{tileX}|{tileY}";
}
private static string MakeBoundaryKey(string kind, int id)
{
string normalized = string.IsNullOrWhiteSpace(kind) ? "boundary_inflow" : kind.Trim().ToLowerInvariant();
if (normalized == "source")
{
normalized = "boundary_inflow";
}
return $"{normalized}:{id}";
}
}
[Serializable]
public sealed class SweBoundarySource
{
public int id;
public int tile_count;
public int total_pixels;
public SweBoundaryParams @params;
}
[Serializable]
public sealed class SweBoundarySink
{
public int id;
public int tile_count;
public int total_pixels;
public SweBoundaryParams @params;
}
[Serializable]
public sealed class SweBoundaryTile
{
public string lod;
public int tile_x;
public int tile_y;
public float tile_size_m;
public int resolution;
public float[] bounds;
public SweBoundaryTileIdRef[] source_ids;
public SweBoundaryTileIdRef[] sink_ids;
public SweBoundaryTileIdRef[] boundary_inflow_ids;
public SweBoundaryTileIdRef[] source_area_ids;
public SweBoundaryTileCellGroup[] boundary_cells;
public SweBoundaryTileCellGroup[] boundary_sink_cells;
public SweBoundaryTileCellGroup[] source_area_cells;
public SweBoundaryTileCellGroup[] sink_cells;
public string source_id_path;
public string sink_id_path;
public string boundary_inflow_id_path;
public string source_area_id_path;
public bool HasCellGroups
{
get
{
return (boundary_cells != null && boundary_cells.Length > 0) ||
(boundary_sink_cells != null && boundary_sink_cells.Length > 0) ||
(source_area_cells != null && source_area_cells.Length > 0) ||
(sink_cells != null && sink_cells.Length > 0);
}
}
}
[Serializable]
public sealed class SweBoundaryParams
{
public string name;
public string mode;
public float trigger_level_m;
public float max_outflow_m3s;
public bool IsMode(string value)
{
return !string.IsNullOrWhiteSpace(mode) &&
string.Equals(mode.Trim(), value, StringComparison.OrdinalIgnoreCase);
}
}
[Serializable]
public sealed class SweBoundaryTileIdRef
{
public int id;
public int pixels;
}
[Serializable]
public sealed class SweBoundaryTileCellGroup
{
public int id;
public int count;
public int[] cells;
}
[Serializable]
public sealed class SweBoundaryDefinition
{
public string kind;
public int id;
public int tile_count;
public int total_pixels;
public SweBoundaryParams @params;
public SweBoundaryDefaultState default_state;
}
[Serializable]
public sealed class SweBoundaryDefaultState
{
public bool enabled;
public float water_level_m;
public float velocity_u_mps;
public float velocity_v_mps;
public float depth_rate_mps;
public static SweBoundaryDefaultState DefaultFor(string kind, SweBoundaryParams parameters)
{
bool sinkFreeOutflow = string.Equals(kind, "sink", StringComparison.OrdinalIgnoreCase) &&
parameters != null &&
parameters.IsMode("free_outflow");
return new SweBoundaryDefaultState
{
enabled = sinkFreeOutflow,
water_level_m = 0.0f,
velocity_u_mps = 0.0f,
velocity_v_mps = 0.0f,
depth_rate_mps = 0.0f,
};
}
public SweBoundaryProfile ToProfile(string kind, int id)
{
return new SweBoundaryProfile
{
boundaryKind = kind,
boundaryId = id,
enabled = enabled,
waterLevelM = water_level_m,
velocityUMps = velocity_u_mps,
velocityVMps = velocity_v_mps,
depthRateMps = depth_rate_mps,
};
}
}
}