18 Commits

Author SHA1 Message Date
a4f78b3a95 build: Update project version 2025-03-24 00:07:35 +08:00
074a58dabd perf: Optimize performance for status view 2025-03-24 00:06:51 +08:00
a2ef175a81 fix: Fix potentially bad formats in culture info 2025-03-24 00:06:29 +08:00
915ba55c2e fix: Correct lifecycle of event listeners 2025-03-24 00:05:35 +08:00
f154a2a468 fix: Fix history list view flashing hard on update 2025-03-24 00:04:29 +08:00
c52d438d40 ci: Update plugins 2025-03-24 00:03:33 +08:00
8d3f53ba13 perf: Improve performance for line renderer 2025-03-20 21:49:28 +08:00
1db25e62e7 fix: Fix wave circle shape when hypocenter is near antimeridian 2025-03-20 21:47:52 +08:00
18312176d9 refactor: Decouple grouping logic from core worker 2025-03-20 17:53:10 +08:00
5be6e32b03 refactor: Pull up map tile cache manager 2025-03-20 17:52:17 +08:00
b33e5ca223 build: Update project version 2025-02-26 15:58:15 +08:00
fe4430b1bf feat: Add new event sources 2025-02-26 15:58:02 +08:00
5a48073152 ci: Update plugins 2025-02-26 15:57:04 +08:00
41c1e6f9fd fix: Fix network events invalidating map view 2025-02-26 15:36:02 +08:00
0743fa45eb fix: Keep ongoing events if present on reported 2025-02-26 15:18:37 +08:00
7f2c0d2e23 fix: Keep ongoing events if present on reported 2025-02-26 15:05:34 +08:00
14202714cc fix: Fix error on polygon elements with holes 2025-02-26 01:20:18 +08:00
ce0c23805a refactor: Remove useless suppressions 2025-02-22 15:39:38 +08:00
106 changed files with 1015 additions and 312 deletions

View File

@@ -56,7 +56,7 @@ namespace Cryville.Common.Unity.UI {
const float _placeholderLength = 100;
int _firstIndex, _lastIndex;
readonly Stack<GameObject> _pool = new();
void Update() {
void LateUpdate() {
int axis = (int)m_direction;
int sign = m_direction == 0 ? 1 : -1;
float padding = axis == 0 ? m_padding.left : m_padding.top;

View File

@@ -1,3 +1,3 @@
using System.Reflection;
[assembly: AssemblyVersion("0.0.1")]
[assembly: AssemblyVersion("0.0.3")]

View File

@@ -34,20 +34,26 @@ namespace Cryville.EEW.Unity {
}
[JsonPolymorphic(TypeDiscriminatorPropertyName = "Type", UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)]
[JsonDerivedType(typeof(BMKGOpenDataEventSourceConfig), "BMKGOpenData")]
[JsonDerivedType(typeof(CWAOpenDataEventSourceConfig), "CWAOpenData")]
[JsonDerivedType(typeof(EMSCRealTimeEventSourceConfig), "EMSCRealTime")]
[JsonDerivedType(typeof(GlobalQuakeServerEventSourceConfig), "GlobalQuakeServer")]
[JsonDerivedType(typeof(GlobalQuakeServer15EventSourceConfig), "GlobalQuakeServer15")]
[JsonDerivedType(typeof(JMAAtomEventSourceConfig), "JMAAtom")]
[JsonDerivedType(typeof(NOAAEventSourceConfig), "NOAA")]
[JsonDerivedType(typeof(UpdateCheckerEventSourceConfig), "UpdateChecker")]
[JsonDerivedType(typeof(USGSQuakeMLEventSourceConfig), "USGSQuakeML")]
[JsonDerivedType(typeof(WolfxEventSourceConfig), "Wolfx")]
abstract record EventSourceConfig();
record BMKGOpenDataEventSourceConfig([property: JsonRequired] string[] Subtypes) : EventSourceConfig;
record CWAOpenDataEventSourceConfig([property: JsonRequired] string Subtype, [property: JsonRequired] string Token) : EventSourceConfig;
record EMSCRealTimeEventSourceConfig() : EventSourceConfig;
record GlobalQuakeServerEventSourceConfig([property: JsonRequired] string Host, int Port = 38000) : EventSourceConfig;
record GlobalQuakeServer15EventSourceConfig(string Host, int Port = 38000) : GlobalQuakeServerEventSourceConfig(Host, Port);
record JMAAtomEventSourceConfig(IReadOnlyCollection<string> Filter = null, bool IsFilterWhitelist = false) : EventSourceConfig;
record NOAAEventSourceConfig([property: JsonRequired] string Subtype) : EventSourceConfig;
record UpdateCheckerEventSourceConfig : EventSourceConfig;
record USGSQuakeMLEventSourceConfig([property: JsonRequired] string Subtype) : EventSourceConfig;
record WolfxEventSourceConfig(IReadOnlyCollection<string> Filter = null, bool IsFilterWhitelist = false) : EventSourceConfig;
[JsonSerializable(typeof(Config))]

View File

@@ -15,14 +15,18 @@ namespace Cryville.EEW.Unity.Map {
MapElementManager m_layerElementSub;
[SerializeField]
GameObject m_prefabTile;
[SerializeField]
GameObject m_prefabBitmapHolder;
readonly MapTileCacheManager _tiles = new();
float _elementLayerZ;
void Start() {
_camera = GetComponent<Camera>();
_tiles.ExtraCachedZoomLevel = 20;
_tiles.Parent = m_layerTile;
_tiles.PrefabTile = m_prefabTile;
_tiles.PrefabBitmapHolder = m_prefabBitmapHolder;
_tiles.CacheDir = Application.temporaryCachePath;
_camera.orthographicSize = 0.5f / MathF.Max(1, (float)_camera.pixelWidth / _camera.pixelHeight);
_elementLayerZ = m_layerElement.transform.position.z;

View File

@@ -98,24 +98,25 @@ namespace Cryville.EEW.Unity.Map.Element {
for (int d = 0; d < 360; d++) {
Quaternion q = Quaternion.AngleAxis(d, axis);
Vector3 p = q * rp;
Vector2 p2 = ToTilePos(p).ToVector2();
if (lp2 != null) {
float dx = p2.x - lp2.Value.x;
if (MathF.Abs(dx) >= 0.5) {
_vertexBuffer[d] = p2.x < 0.5 ? p2 + new Vector2(1, 0) : p2 - new Vector2(1, 0);
renderer.AddSegment(_vertexBuffer, segmentIndex, d - segmentIndex + 1);
segmentIndex = d;
}
}
_vertexBuffer[d] = p2;
lp2 = p2;
AddVertex(renderer, ref lp2, ref segmentIndex, d, p);
}
Vector2 rp2 = ToTilePos(rp).ToVector2();
_vertexBuffer[360] = rp2;
AddVertex(renderer, ref lp2, ref segmentIndex, 360, rp);
renderer.AddSegment(_vertexBuffer, segmentIndex, 361 - segmentIndex);
}
renderer.SetMaterial(isHistory ? m_historyMaterial : m_ongoingMaterial);
}
void AddVertex(MultiLineRenderer renderer, ref Vector2? lp2, ref int segmentIndex, int d, Vector3 p) {
Vector2 p2 = ToTilePos(p).ToVector2();
if (lp2 != null && MathF.Abs(p2.x - lp2.Value.x) >= 0.5) {
_vertexBuffer[d] = p2.x < 0.5 ? p2 + new Vector2(1, 0) : p2 - new Vector2(1, 0);
renderer.AddSegment(_vertexBuffer, segmentIndex, d - segmentIndex + 1);
segmentIndex = d;
}
_vertexBuffer[d] = p2;
lp2 = p2;
}
static PointF ToTilePos(Vector3 p) => MapTileUtils.WorldToTilePos(new(MathF.Atan2(p.z, p.x) / MathF.PI * 180f, MathF.Asin(p.y) / MathF.PI * 180f));
}
}

View File

@@ -150,12 +150,8 @@ namespace Cryville.EEW.Unity.Map {
_mesh.Clear();
if (_positions == null) return;
if (_positionCount <= 1) return;
float hw = m_width / 2;
int maxVertexCount = 4 * (_positionCount - 1);
var vbuf = ArrayPool<Vector3>.Shared.Rent(maxVertexCount);
var ubuf = ArrayPool<Vector2>.Shared.Rent(maxVertexCount);
var ibuf = ArrayPool<int>.Shared.Rent(3 * (2 + 4 * (_positionCount - 2)));
float hw = m_width / 2;
int i, vi = 0, ii = 0, li = 0, ri = 1;
float uvScale = 1 / (m_tilingScale * m_width);
Vector2 p0 = _positions[0], p1 = default;
@@ -163,6 +159,12 @@ namespace Cryville.EEW.Unity.Map {
if ((p1 = _positions[i]) != p0) break;
}
if (i >= _positionCount) return;
int maxVertexCount = 4 * (_positionCount - 1);
var vbuf = ArrayPool<Vector3>.Shared.Rent(maxVertexCount);
var ubuf = ArrayPool<Vector2>.Shared.Rent(maxVertexCount);
var ibuf = ArrayPool<int>.Shared.Rent(3 * (2 + 4 * (_positionCount - 2)));
Vector2 dp0 = NormalizeSmallVector(p1 - p0), np0 = GetNormal(dp0 * hw);
vbuf[vi] = p0 - np0; ubuf[vi++] = new(0, 0);
vbuf[vi] = p0 + np0; ubuf[vi++] = new(0, 1);

View File

@@ -1,9 +1,12 @@
using Cryville.EEW.BMKGOpenData.Map;
using Cryville.EEW.Core;
using Cryville.EEW.CWAOpenData.Map;
using Cryville.EEW.EMSC.Map;
using Cryville.EEW.GlobalQuake.Map;
using Cryville.EEW.JMAAtom.Map;
using Cryville.EEW.Map;
using Cryville.EEW.NOAA.Map;
using Cryville.EEW.QuakeML.Map;
using Cryville.EEW.Report;
using Cryville.EEW.Wolfx.Map;
using System.Collections.Generic;
@@ -23,6 +26,7 @@ namespace Cryville.EEW.Unity.Map {
readonly List<int> _displayingOrder = new();
public int Count => _displayingReports.Count;
public int OngoingCount => _displayingReports.Count - (_selected != null ? 1 : 0);
[SerializeField] MapElementManager m_subManager;
@@ -123,16 +127,19 @@ namespace Cryville.EEW.Unity.Map {
}
readonly ContextedGeneratorManager<IMapGeneratorContext, MapElement> _gen = new(new IContextedGenerator<IMapGeneratorContext, MapElement>[] {
new BMKGEarthquakeMapGenerator(),
new CENCEarthquakeMapGenerator(),
new CENCEEWMapGenerator(),
new CWAEarthquakeMapGenerator(),
new CWAEEWMapGenerator(),
new CWATsunamiMapGenerator(),
new EMSCRealTimeEventMapGenerator(),
new FujianEEWMapGenerator(),
new GlobalQuakeMapViewGenerator(),
new JMAAtomMapGenerator(),
new JMAEEWMapGenerator(),
new NOAAMapGenerator(),
new QuakeMLEventMapGenerator(),
new SichuanEEWMapGenerator(),
});
public UnityMapElement Build(object e, out CultureInfo culture, out int order) {

View File

@@ -1,44 +1,21 @@
using Cryville.EEW.Core.Map;
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;
namespace Cryville.EEW.Unity.Map {
[RequireComponent(typeof(SpriteRenderer))]
sealed class MapTile : MonoBehaviour {
static readonly SemaphoreSlim _semaphore = new(2);
static readonly HttpClient _httpClient = new() { Timeout = TimeSpan.FromSeconds(10) };
[SerializeField] Transform _idView;
public MapTileIndex Index { get; set; }
public bool IsEmpty { get; private set; }
Action<MapTile> _callback;
SpriteRenderer _renderer;
UnityWebRequest _req;
DownloadHandlerTexture _texHandler;
Texture2D _tex;
Sprite _sprite;
void Awake() {
_renderer = GetComponent<SpriteRenderer>();
}
FileInfo _localFile;
bool _downloadDone;
public void Load(MapTileIndex index, string cacheDir, Action<MapTile> onUpdated) {
public void Init(MapTileIndex index) {
Index = index;
_callback = onUpdated;
_localFile = new(Path.Combine(cacheDir, $"map/{Index.Z}/{Index.NX}/{Index.NY}"));
float z = 1 << index.Z;
transform.localPosition = new(index.X / z, -(index.Y + 1) / z, -index.Z / 100f);
transform.localScale = new Vector3(1 / z, 1 / z, 1);
@@ -46,71 +23,22 @@ namespace Cryville.EEW.Unity.Map {
byte e = SharedSettings.Instance.IdBytes[((index.X << 2) + index.Y) & 0x1f];
int ex = e >> 4, ey = e & 0xf;
_idView.localPosition = new(ex / 16f, 1 - ey / 16f, -1 / 200f);
if (_localFile.Exists) {
_downloadDone = true;
}
else {
Task.Run(() => RunAsync($"https://server.arcgisonline.com/ArcGIS/rest/services/Ocean/World_Ocean_Base/MapServer/tile/{Index.Z}/{Index.NY}/{Index.NX}"));
}
}
async Task RunAsync(string url) {
await _semaphore.WaitAsync().ConfigureAwait(true);
try {
Directory.CreateDirectory(_localFile.DirectoryName);
using var webStream = await _httpClient.GetStreamAsync(new Uri(url)).ConfigureAwait(true);
using var fileStream = new FileStream(_localFile.FullName, FileMode.Create, FileAccess.Write);
await webStream.CopyToAsync(fileStream).ConfigureAwait(true);
}
finally {
_semaphore.Release();
}
_downloadDone = true;
}
[SuppressMessage("CodeQuality", "IDE0051", Justification = "Unity message")]
public void Set(Sprite sprite) {
if (_renderer) {
_renderer.sprite = sprite;
}
}
bool _isDestroyed;
public void Destroy() {
_isDestroyed = true;
}
void Update() {
if (_downloadDone) {
try {
_texHandler = new DownloadHandlerTexture();
_req = new UnityWebRequest($"file:///{_localFile}") {
downloadHandler = _texHandler,
disposeDownloadHandlerOnDispose = true,
};
_req.SendWebRequest();
}
catch (Exception ex) {
Debug.LogException(ex);
}
_downloadDone = false;
if (_isDestroyed) {
Destroy(gameObject);
}
if (_req == null || !_req.isDone) return;
if (_texHandler.isDone) {
_tex = _texHandler.texture;
_tex.wrapMode = TextureWrapMode.Clamp;
_sprite = Sprite.Create(_tex, new Rect(0, 0, _tex.width, _tex.height), Vector2.zero, _tex.height, 0, SpriteMeshType.FullRect, Vector4.zero, false);
_renderer.sprite = _sprite;
}
else {
Debug.LogError(_req.error);
_localFile.Delete();
IsEmpty = true;
}
_req.Dispose();
_req = null;
_callback?.Invoke(this);
}
[SuppressMessage("CodeQuality", "IDE0051", Justification = "Unity message")]
void OnDestroy() {
if (_req != null) {
_req.Abort();
_req.Dispose();
_texHandler.Dispose();
}
if (_sprite) Destroy(_sprite);
if (_tex) Destroy(_tex);
IsEmpty = true;
_callback?.Invoke(this);
}
}
}

View File

@@ -0,0 +1,35 @@
using Cryville.EEW.Core.Map;
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
namespace Cryville.EEW.Unity.Map {
sealed class MapTileBitmapHolder : Core.Map.MapTileBitmapHolder {
MapTileBitmapHolderBehaviour _behaviour;
public MapTileBitmapHolder(MapTileIndex index, GameObject gameObject) : base(index) {
_behaviour = gameObject.GetComponent<MapTileBitmapHolderBehaviour>();
}
protected override void Dispose(bool disposing) {
base.Dispose(disposing);
if (disposing) {
if (_behaviour) _behaviour.Destroy();
}
}
protected override Uri GetUri() =>
new($"https://server.arcgisonline.com/ArcGIS/rest/services/Ocean/World_Ocean_Base/MapServer/tile/{Index.Z}/{Index.NY}/{Index.NX}");
protected override Task LoadBitmap(FileInfo file, CancellationToken cancellationToken) {
_behaviour.Load(file);
return Task.CompletedTask;
}
public void Bind(MapTile tile) {
_behaviour.Bind(tile);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f7ad3a3ac7d829249ba21987d585b07f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,79 @@
using System;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;
namespace Cryville.EEW.Unity.Map {
sealed class MapTileBitmapHolderBehaviour : MonoBehaviour {
Action<Sprite> _callback;
public void Bind(MapTile tile) {
if (_isDone)
tile.Set(_sprite);
else
_callback += tile.Set;
}
UnityWebRequest _req;
DownloadHandlerTexture _texHandler;
Texture2D _tex;
Sprite _sprite;
FileInfo _localFile;
bool _isReady;
bool _isDone;
public void Load(FileInfo file) {
_localFile = file;
_isReady = true;
}
void Update() {
if (_isDestroyed) {
Destroy(gameObject);
return;
}
if (_isReady) {
try {
_texHandler = new DownloadHandlerTexture();
_req = new UnityWebRequest($"file:///{_localFile}") {
downloadHandler = _texHandler,
disposeDownloadHandlerOnDispose = true,
};
_req.SendWebRequest();
}
catch (Exception ex) {
Debug.LogException(ex);
}
_isReady = false;
}
if (_req == null || !_req.isDone) return;
if (_texHandler.isDone) {
_tex = _texHandler.texture;
_tex.wrapMode = TextureWrapMode.Clamp;
_sprite = Sprite.Create(_tex, new Rect(0, 0, _tex.width, _tex.height), Vector2.zero, _tex.height, 0, SpriteMeshType.FullRect, Vector4.zero, false);
}
else {
Debug.LogError(_req.error);
_localFile.Delete();
}
_req.Dispose();
_texHandler.Dispose();
_req = null;
_callback?.Invoke(_sprite);
_isDone = true;
}
bool _isDestroyed;
public void Destroy() {
_isDestroyed = true;
}
void OnDestroy() {
if (_req != null) {
_req.Abort();
_req.Dispose();
_texHandler.Dispose();
}
if (_sprite) Destroy(_sprite);
if (_tex) Destroy(_tex);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c17f6b26e9a6bd74e8b2d071c6951c41
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,165 +1,36 @@
using Cryville.EEW.Core.Map;
using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
namespace Cryville.EEW.Unity.Map {
sealed class TileZOrderComparer : IComparer<MapTileIndex>, IComparer<MapTile> {
public static readonly TileZOrderComparer Instance = new();
public int Compare(MapTileIndex a, MapTileIndex b) {
var c = a.Z.CompareTo(b.Z);
if (c != 0) return c;
c = a.Y.CompareTo(b.Y);
if (c != 0) return c;
return a.X.CompareTo(b.X);
}
public int Compare(MapTile a, MapTile b) {
if (a == null) return b == null ? 0 : -1;
if (b == null) return 1;
return Compare(a.Index, b.Index);
}
}
sealed class MapTileCacheManager : IDisposable {
public int ExtraCachedZoomLevel { get; set; } = 20;
GameObject m_prefabTile;
public GameObject PrefabTile {
get => m_prefabTile;
set {
m_prefabTile = value;
if (_dummyTask) GameObject.Destroy(_dummyTask.gameObject);
_dummyTask = GameObject.Instantiate(m_prefabTile, Parent, false).GetComponent<MapTile>();
}
}
sealed class MapTileCacheManager : MapTileCacheManager<MapTileBitmapHolder> {
public GameObject PrefabTile { get; set; }
public GameObject PrefabBitmapHolder { get; set; }
public Transform Parent { get; set; }
public string CacheDir { get; set; }
public event Action Updated;
void OnUpdated(MapTile tile) {
if (tile.IsEmpty) {
lock (ActiveTiles) {
if (_cache.Remove(tile.Index)) {
ActiveTiles.RemoveAt(ActiveTiles.BinarySearch(tile, TileZOrderComparer.Instance));
}
}
}
Updated?.Invoke();
protected override MapTileBitmapHolder CreateBitmapHolder(MapTileIndex index) => new(index, GameObject.Instantiate(PrefabBitmapHolder, Parent, false));
protected override string GetCacheFilePath(MapTileIndex index) => Path.Combine(CacheDir, $"map/{index.Z}/{index.NX}/{index.NY}");
readonly Dictionary<MapTile<MapTileBitmapHolder>, MapTile> _map = new();
protected override void OnTileCreated(MapTile<MapTileBitmapHolder> tile) {
base.OnTileCreated(tile);
var gameObject = GameObject.Instantiate(PrefabTile, Parent, false);
var uTile = gameObject.GetComponent<MapTile>();
_map.Add(tile, uTile);
uTile.Init(tile.Index);
tile.BitmapHolder.Bind(uTile);
}
public void Dispose() {
MonoBehaviour.Destroy(_dummyTask);
lock (ActiveTiles) {
foreach (var task in ActiveTiles)
GameObject.Destroy(task.gameObject);
ActiveTiles.Clear();
_cache.Clear();
}
}
readonly Dictionary<MapTileIndex, MapTile> _cache = new();
public List<MapTile> ActiveTiles { get; } = new();
MapTileIndex _a, _b;
public void MoveTo(MapTileIndex a, MapTileIndex b) {
if (a.Z != b.Z) throw new ArgumentException("Mismatched Z index.");
if (a.X >= b.X || a.Y >= b.Y) throw new ArgumentException("Incorrect relative X/Y index.");
lock (ActiveTiles) {
UnloadTiles(a, b);
_a = a; _b = b;
LoadTiles(a, b);
}
}
void LoadTiles(MapTileIndex a, MapTileIndex b) {
for (int z = Math.Max(0, a.Z - ExtraCachedZoomLevel); z <= Math.Max(0, a.Z); z++) {
var ia = a.ZoomToLevel(z, Math.Floor);
var ib = b.ZoomToLevel(z, Math.Ceiling);
for (int x = ia.X; x < ib.X; x++) {
for (int y = ia.Y; y < ib.Y; y++) {
var index = new MapTileIndex(x, y, z);
if (_cache.ContainsKey(index)) continue;
var task = GameObject.Instantiate(PrefabTile, Parent, false).GetComponent<MapTile>();
task.Load(index, CacheDir, OnUpdated);
_cache.Add(index, task);
var i = ~ActiveTiles.BinarySearch(task, TileZOrderComparer.Instance);
ActiveTiles.Insert(i, task);
}
}
}
}
void UnloadTiles(MapTileIndex a, MapTileIndex b) {
if (a.Z != _a.Z) {
for (int z = _a.Z - ExtraCachedZoomLevel; z < a.Z - ExtraCachedZoomLevel; z++) UnloadTilesAtZoomLevel(z);
for (int z = a.Z + 1; z <= _a.Z; z++) UnloadTilesAtZoomLevel(z);
}
if (a.X > _a.X) {
for (int z = Math.Max(0, a.Z); z >= Math.Max(0, a.Z - ExtraCachedZoomLevel); --z) {
var ia0 = _a.ZoomToLevel(z, Math.Floor);
var ib0 = _b.ZoomToLevel(z, Math.Ceiling);
var ia1 = a.ZoomToLevel(z, Math.Floor);
if (ia0.X == ia1.X) break;
UnloadTilesInRegion(ia0.X, ia0.Y, ia1.X, ib0.Y, z);
}
}
if (b.X < _b.X) {
for (int z = Math.Max(0, a.Z); z >= Math.Max(0, a.Z - ExtraCachedZoomLevel); --z) {
var ia0 = _a.ZoomToLevel(z, Math.Floor);
var ib0 = _b.ZoomToLevel(z, Math.Ceiling);
var ib1 = b.ZoomToLevel(z, Math.Ceiling);
if (ib0.X == ib1.X) break;
UnloadTilesInRegion(ib1.X, ia0.Y, ib0.X, ib0.Y, z);
}
}
if (a.Y > _a.Y) {
for (int z = Math.Max(0, a.Z); z >= Math.Max(0, a.Z - ExtraCachedZoomLevel); --z) {
var ia0 = _a.ZoomToLevel(z, Math.Floor);
var ib0 = _b.ZoomToLevel(z, Math.Ceiling);
var ia1 = a.ZoomToLevel(z, Math.Floor);
if (ia0.Y == ia1.Y) break;
UnloadTilesInRegion(ia0.X, ia0.Y, ib0.X, ia1.Y, z);
}
}
if (b.Y < _b.Y) {
for (int z = Math.Max(0, a.Z); z >= Math.Max(0, a.Z - ExtraCachedZoomLevel); --z) {
var ia0 = _a.ZoomToLevel(z, Math.Floor);
var ib0 = _b.ZoomToLevel(z, Math.Ceiling);
var ib1 = b.ZoomToLevel(z, Math.Ceiling);
if (ib0.Y == ib1.Y) break;
UnloadTilesInRegion(ia0.X, ib1.Y, ib0.X, ib0.Y, z);
}
}
}
void UnloadTilesInRegion(int x1, int y1, int x2, int y2, int z) {
for (int x = x1; x < x2; x++) {
for (int y = y1; y < y2; y++) {
var index = new MapTileIndex(x, y, z);
if (!_cache.TryGetValue(index, out var task)) continue;
GameObject.Destroy(task.gameObject);
}
}
}
MapTile _dummyTask;
void UnloadTilesAtZoomLevel(int z) {
if (z < 0) return;
_dummyTask.Index = new(int.MinValue, int.MinValue, z);
var i0 = ActiveTiles.BinarySearch(_dummyTask, TileZOrderComparer.Instance);
if (i0 < 0) i0 = ~i0;
_dummyTask.Index = new(int.MinValue, int.MinValue, z + 1);
var i1 = ActiveTiles.BinarySearch(_dummyTask, TileZOrderComparer.Instance);
if (i1 < 0) i1 = ~i1;
for (var i = i1 - 1; i >= i0; --i) {
var index = ActiveTiles[i].Index;
if (!_cache.TryGetValue(index, out var task)) continue;
GameObject.Destroy(task.gameObject);
protected override void OnTileDestroyed(MapTile<MapTileBitmapHolder> tile) {
base.OnTileDestroyed(tile);
if (_map.TryGetValue(tile, out var uTile)) {
uTile.Destroy();
_map.Remove(tile);
}
}
}

View File

@@ -77,7 +77,13 @@ namespace Cryville.EEW.Unity.Map {
DTSweep.Triangulate(tcx);
var codeToIndex = new Dictionary<uint, int>();
var vertices = ArrayPool<Vector3>.Shared.Rent(convertedPolygon.Points.Count);
int vertexCount = convertedPolygon.Points.Count;
if (convertedPolygon.Holes != null) {
foreach (var hole in convertedPolygon.Holes) {
vertexCount += hole.Points.Count;
}
}
var vertices = ArrayPool<Vector3>.Shared.Rent(vertexCount);
var triangles = ArrayPool<int>.Shared.Rent(convertedPolygon.Triangles.Count * 3);
int vi = 0, ii = 0;
foreach (var tri in convertedPolygon.Triangles) {

View File

@@ -14,9 +14,12 @@ namespace Cryville.EEW.Unity.UI {
[SerializeField] GameObject m_listViewRail;
[SerializeField] GameObject m_expander;
void Start() {
void OnEnable() {
m_groupHeader.onClick.AddListener(OnGroupHeaderClicked);
}
void OnDisable() {
m_groupHeader.onClick.RemoveListener(OnGroupHeaderClicked);
}
void OnGroupHeaderClicked() {
SetExpanded(!m_listViewContainer.activeSelf);
}

View File

@@ -27,7 +27,7 @@ namespace Cryville.EEW.Unity.UI {
}
void SetView(float mainSeverity, string title, string location, CultureInfo culture) {
SetSeverity(mainSeverity);
SetText(m_textView, string.Format("{0} {1}", title, location), culture);
SetText(m_textView, string.Format(culture, "{0} {1}", title, location), culture);
}
static void SetText(TMPLocalizedText view, string text, CultureInfo culture) {
if (string.IsNullOrWhiteSpace(text)) {
@@ -47,9 +47,12 @@ namespace Cryville.EEW.Unity.UI {
void Awake() {
_dockRatioTweener = new(() => m_dockLayoutGroup.DockOccupiedRatio, v => m_dockLayoutGroup.DockOccupiedRatio = v, Tweeners.Single);
}
void Start() {
void OnEnable() {
m_button.onClick.AddListener(OnViewClicked);
}
void OnDisable() {
m_button.onClick.RemoveListener(OnViewClicked);
}
void OnViewClicked() {
EventOngoingListView.Instance.OnItemClicked(_viewModel);
}

View File

@@ -14,9 +14,12 @@ namespace Cryville.EEW.Unity.UI {
[SerializeField] TMPLocalizedText m_revisionView;
ReportViewModel _viewModel;
protected virtual void Start() {
protected virtual void OnEnable() {
if (m_reportViewButton != null) m_reportViewButton.onClick.AddListener(OnViewClicked);
}
protected virtual void OnDisable() {
if (m_reportViewButton != null) m_reportViewButton.onClick.RemoveListener(OnViewClicked);
}
void OnViewClicked() {
Worker.Instance.SetSelected(_viewModel);
}

View File

@@ -8,10 +8,14 @@ namespace Cryville.EEW.Unity.UI {
[SerializeField] Button m_revisionViewContainerButton;
protected override void Start() {
base.Start();
protected override void OnEnable() {
base.OnEnable();
m_revisionViewContainerButton.onClick.AddListener(OnRevisionViewClicked);
}
protected override void OnDisable() {
base.OnDisable();
m_revisionViewContainerButton.onClick.RemoveListener(OnRevisionViewClicked);
}
void OnRevisionViewClicked() {
m_listView.gameObject.SetActive(!m_listView.gameObject.activeSelf);
}

View File

@@ -1,4 +1,5 @@
using System.Globalization;
using System.Text;
using TMPro;
using UnityEngine;
@@ -11,17 +12,30 @@ namespace Cryville.EEW.Unity.UI {
_textView = GetComponent<TMP_Text>();
}
StringBuilder _sb = new();
char[] _buffer = new char[256];
void Update() {
_textView.text = string.Format(
_sb.Clear();
_sb.AppendFormat(
CultureInfo.InvariantCulture,
"FPS: i{0:0} / s{1:0}\nSMem: {2:N0} / {3:N0}\nIMem: {4:N0} / {5:N0}",
"FPS: i{0:0} / s{1:0}\n",
1 / Time.deltaTime,
1 / Time.smoothDeltaTime,
1 / Time.smoothDeltaTime
);
_sb.AppendFormat(
CultureInfo.InvariantCulture,
"SMem: {0:N0} / {1:N0}\n",
UnityEngine.Profiling.Profiler.GetMonoUsedSizeLong(),
UnityEngine.Profiling.Profiler.GetMonoHeapSizeLong(),
UnityEngine.Profiling.Profiler.GetMonoHeapSizeLong()
);
_sb.AppendFormat(
CultureInfo.InvariantCulture,
"IMem: {0:N0} / {1:N0}",
UnityEngine.Profiling.Profiler.GetTotalAllocatedMemoryLong(),
UnityEngine.Profiling.Profiler.GetTotalReservedMemoryLong()
);
_sb.CopyTo(0, _buffer, _sb.Length);
_textView.SetText(_buffer, 0, _sb.Length);
}
}
}

View File

@@ -1,5 +1,4 @@
using System;
using System.Globalization;
using TMPro;
using UnityEngine;
@@ -19,7 +18,7 @@ namespace Cryville.EEW.Unity.UI {
time = TimeZoneInfo.ConvertTime(time, timeZone, tTimeZone);
else
tTimeZone = timeZone;
_textView.text = SharedSettings.Instance.DoDisplayTimeZone ? string.Format(CultureInfo.CurrentCulture, "{0:G} ({1})", time, tTimeZone.ToTimeZoneString()) : time.ToString(CultureInfo.CurrentCulture);
_textView.text = SharedSettings.Instance.DoDisplayTimeZone ? string.Format(SharedCultures.CurrentCulture, "{0:G} ({1})", time, tTimeZone.ToTimeZoneString()) : time.ToString(SharedCultures.CurrentCulture);
}
}
}

View File

@@ -1,21 +1,27 @@
using Cryville.EEW.BMKGOpenData;
using Cryville.EEW.BMKGOpenData.TTS;
using Cryville.EEW.Core;
using Cryville.EEW.CWAOpenData;
using Cryville.EEW.CWAOpenData.Model;
using Cryville.EEW.CWAOpenData.TTS;
using Cryville.EEW.EMSC;
using Cryville.EEW.GlobalQuake;
using Cryville.EEW.JMAAtom;
using Cryville.EEW.JMAAtom.TTS;
using Cryville.EEW.NOAA;
using Cryville.EEW.NOAA.TTS;
using Cryville.EEW.QuakeML;
using Cryville.EEW.Report;
using Cryville.EEW.Unity.Map;
using Cryville.EEW.Unity.UI;
using Cryville.EEW.UpdateChecker;
using Cryville.EEW.USGS;
using Cryville.EEW.Wolfx;
using Cryville.EEW.Wolfx.Model;
using Cryville.EEW.Wolfx.TTS;
using System;
using System.Collections.Concurrent;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Http;
@@ -33,7 +39,8 @@ namespace Cryville.EEW.Unity {
[SerializeField] EventGroupListView m_historyEventGroupList;
[SerializeField] GameObject m_connectingHint;
GroupingCoreWorker _worker;
CoreWorker _worker;
ReportGrouper _grouper;
CancellationTokenSource _cancellationTokenSource;
void Awake() {
@@ -46,6 +53,7 @@ namespace Cryville.EEW.Unity {
App.Init();
_worker = new(new TTSWorker());
_grouper = new ReportGrouper();
_cancellationTokenSource = new();
}
@@ -58,8 +66,8 @@ namespace Cryville.EEW.Unity {
_worker.TTSMessageGeneratorContext = SharedSettings.Instance;
_ongoingReportManager.Changed += OnOngoingReported;
_worker.Reported += OnReported;
_worker.GroupUpdated += OnGroupUpdated;
_worker.GroupRemoved += OnGroupRemoved;
_grouper.GroupUpdated += OnGroupUpdated;
_grouper.GroupRemoved += OnGroupRemoved;
Task.Run(() => GatewayVerify(_cancellationTokenSource.Token)).ContinueWith(task => {
if (task.IsFaulted) {
OnReported(this, new() { Title = task.Exception.Message });
@@ -80,20 +88,24 @@ namespace Cryville.EEW.Unity {
}
static void RegisterViewModelGenerators(CoreWorker worker) {
worker.RegisterViewModelGenerator(new BMKGEarthquakeRVMGenerator());
worker.RegisterViewModelGenerator(new CENCEarthquakeRVMGenerator());
worker.RegisterViewModelGenerator(new CENCEEWRVMGenerator());
worker.RegisterViewModelGenerator(new CWAEarthquakeRVMGenerator());
worker.RegisterViewModelGenerator(new CWAEEWRVMGenerator());
worker.RegisterViewModelGenerator(new CWATsunamiRVMGenerator());
worker.RegisterViewModelGenerator(new EMSCRealTimeEventRVMGenerator());
worker.RegisterViewModelGenerator(new FujianEEWRVMGenerator());
worker.RegisterViewModelGenerator(new GlobalQuakeRVMGenerator());
worker.RegisterViewModelGenerator(new JMAAtomRVMGenerator());
worker.RegisterViewModelGenerator(new JMAEEWRVMGenerator());
worker.RegisterViewModelGenerator(new NOAAAtomRVMGenerator());
worker.RegisterViewModelGenerator(new QuakeMLEventRVMGenerator());
worker.RegisterViewModelGenerator(new SichuanEEWRVMGenerator());
worker.RegisterViewModelGenerator(new VersionRVMGenerator());
}
static void RegisterTTSMessageGenerators(CoreWorker worker) {
worker.RegisterTTSMessageGenerator(new BMKGEarthquakeTTSMessageGenerator());
worker.RegisterTTSMessageGenerator(new CENCEarthquakeTTSMessageGenerator());
worker.RegisterTTSMessageGenerator(new CENCEEWTTSMessageGenerator());
worker.RegisterTTSMessageGenerator(new CWAEarthquakeTTSMessageGenerator());
@@ -114,17 +126,22 @@ namespace Cryville.EEW.Unity {
_worker.AddWorker(new CWAReportWorker<Tsunami>(new Uri("http://localhost:9095/E-A0014-001.json"), "1"));
_worker.AddWorker(new CWAReportWorker<Earthquake>(new Uri("http://localhost:9095/E-A0015-001.json"), "1"));
_worker.AddWorker(new CWAReportWorker<Earthquake>(new Uri("http://localhost:9095/E-A0016-001.json"), "1"));
BMKGOpenDataWorker bmkgWorker = new(new Uri("http://localhost:9095/autogempa.json"));
bmkgWorker.SetDataUris(new Uri[] { new("http://localhost:9095/gempadirasakan.json") });
_worker.AddWorker(bmkgWorker);
_worker.AddWorker(new NOAAAtomWorker(new("http://localhost:9095/PAAQAtom.xml")));
_worker.AddWorker(new UpdateCheckerWorker(typeof(Worker).Assembly.GetName().Version?.ToString(3) ?? "", "unity"));
#else
foreach (var source in SharedSettings.Instance.EventSources) {
_worker.AddWorker(source switch {
BMKGOpenDataEventSourceConfig bmkgOpenData => BuildBMKGOpenDataWorkerUris(new BMKGOpenDataWorker(new("https://data.bmkg.go.id/DataMKG/TEWS/autogempa.json")), bmkgOpenData),
CWAOpenDataEventSourceConfig cwaOpenData => cwaOpenData.Subtype switch {
"E-A0014-001" => new CWAReportWorker<Tsunami>(new Uri("https://opendata.cwa.gov.tw/api/v1/rest/datastore/E-A0014-001"), cwaOpenData.Token, 1440, 17280),
"E-A0015-001" => new CWAReportWorker<Earthquake>(new Uri("https://opendata.cwa.gov.tw/api/v1/rest/datastore/E-A0015-001"), cwaOpenData.Token),
"E-A0016-001" => new CWAReportWorker<Earthquake>(new Uri("https://opendata.cwa.gov.tw/api/v1/rest/datastore/E-A0016-001"), cwaOpenData.Token),
_ => throw new InvalidOperationException("Unknown CWA open data sub-type."),
},
EMSCRealTimeEventSourceConfig => new EMSCRealTimeWorker(new("wss://www.seismicportal.eu/standing_order/websocket")),
GlobalQuakeServer15EventSourceConfig gq => new GlobalQuakeWorker15(gq.Host, gq.Port),
GlobalQuakeServerEventSourceConfig gq => new GlobalQuakeWorker(gq.Host, gq.Port),
JMAAtomEventSourceConfig jmaAtom => BuildJMAAtomWorkerFilter(new JMAAtomWorker(new("https://www.data.jma.go.jp/developer/xml/feed/eqvol.xml")), jmaAtom),
@@ -134,18 +151,19 @@ namespace Cryville.EEW.Unity {
_ => throw new InvalidOperationException("Unknown NOAA sub-type."),
},
UpdateCheckerEventSourceConfig => new UpdateCheckerWorker(typeof(Worker).Assembly.GetName().Version?.ToString(3) ?? "", "unity"),
USGSQuakeMLEventSourceConfig usgsQuakeML => BuildUSGSQuakeMLWorkerUri(new USGSQuakeMLWorker(new Uri("https://earthquake.usgs.gov/earthquakes/feed/v1.0/quakeml.php")), usgsQuakeML),
WolfxEventSourceConfig wolfx => BuildWolfxWorkerFilter(new WolfxWorker(new Uri("wss://ws-api.wolfx.jp/all_eew")), wolfx),
_ => throw new InvalidOperationException("Unknown event source type."),
});
}
#endif
}
JMAAtomWorker BuildJMAAtomWorkerFilter(JMAAtomWorker worker, JMAAtomEventSourceConfig config) {
static JMAAtomWorker BuildJMAAtomWorkerFilter(JMAAtomWorker worker, JMAAtomEventSourceConfig config) {
if (config.Filter != null) worker.SetFilter(config.Filter);
worker.IsFilterWhitelist = config.IsFilterWhitelist;
return worker;
}
WolfxWorker BuildWolfxWorkerFilter(WolfxWorker worker, WolfxEventSourceConfig config) {
static WolfxWorker BuildWolfxWorkerFilter(WolfxWorker worker, WolfxEventSourceConfig config) {
if (config.Filter != null) worker.SetFilter(config.Filter.Select(i => i switch {
"cenc_eew" => typeof(CENCEEW),
"cenc_eqlist" => typeof(WolfxEarthquakeList<CENCEarthquake>),
@@ -158,6 +176,14 @@ namespace Cryville.EEW.Unity {
worker.IsFilterWhitelist = config.IsFilterWhitelist;
return worker;
}
static BMKGOpenDataWorker BuildBMKGOpenDataWorkerUris(BMKGOpenDataWorker worker, BMKGOpenDataEventSourceConfig config) {
worker.SetDataUris(config.Subtypes.Select(i => new Uri(string.Format(CultureInfo.InvariantCulture, "https://data.bmkg.go.id/DataMKG/TEWS/{0}.json", i))));
return worker;
}
static USGSQuakeMLWorker BuildUSGSQuakeMLWorkerUri(USGSQuakeMLWorker worker, USGSQuakeMLEventSourceConfig config) {
worker.SetFeedRelativeUri(new(string.Format(CultureInfo.InvariantCulture, "/earthquakes/feed/v1.0/summary/{0}.quakeml", config.Subtype), UriKind.Relative));
return worker;
}
readonly OngoingReportManager _ongoingReportManager = new();
readonly ConcurrentQueue<Action> _uiActionQueue = new();
@@ -165,13 +191,16 @@ namespace Cryville.EEW.Unity {
void OnReported(object sender, ReportViewModel e) {
if (e.Model is Exception && e.Model is not SourceWorkerNetworkException)
Debug.LogError(e);
_grouper.Report(e);
_ongoingReportManager.Report(e);
_uiActionQueue.Enqueue(() => {
m_mapElementManager.SetSelected(e);
if (m_mapElementManager.OngoingCount == 0) {
m_mapElementManager.SetSelected(e);
m_cameraController.OnMapElementUpdated();
}
if (e.InvalidatedTime == null && (!(e.RevisionKey?.IsCancellation ?? false))) {
_latestHistoryReport = e;
}
m_cameraController.OnMapElementUpdated();
});
}
void OnOngoingReported(ReportViewModel item, CollectionChangeAction action) {
@@ -181,7 +210,6 @@ namespace Cryville.EEW.Unity {
m_mapElementManager.SetSelected(null);
}
m_ongoingEventList.Add(item);
m_cameraController.OnMapElementUpdated();
});
}
else if (action == CollectionChangeAction.Remove) {
@@ -191,7 +219,6 @@ namespace Cryville.EEW.Unity {
m_mapElementManager.SetSelected(_latestHistoryReport, true);
}
m_ongoingEventList.Remove(item);
m_cameraController.OnMapElementUpdated();
});
}
}

View File

@@ -677,6 +677,7 @@ MonoBehaviour:
m_layerElement: {fileID: 1602500234}
m_layerElementSub: {fileID: 303098821}
m_prefabTile: {fileID: 7683017549812261837, guid: e090edd328c6750478f5849a43a9d278, type: 3}
m_prefabBitmapHolder: {fileID: 1455558857588368834, guid: 1a5cf693e0cf6b94390f72f521c151ba, type: 3}
--- !u!1 &408286580
GameObject:
m_ObjectHideFlags: 0

Binary file not shown.

View File

@@ -0,0 +1,78 @@
fileFormatVersion: 2
guid: 88e8ae9c8ce06934ab7681fb678d7b00
labels:
- RoslynAnalyzer
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
: Any
second:
enabled: 0
settings:
Exclude Android: 1
Exclude Editor: 1
Exclude Linux64: 1
Exclude OSXUniversal: 1
Exclude Win: 1
Exclude Win64: 1
- first:
Android: Android
second:
enabled: 0
settings:
CPU: ARMv7
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
CPU: AnyCPU
DefaultValueInitialized: true
OS: AnyOS
- first:
Standalone: Linux64
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: OSXUniversal
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: Win
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: Win64
second:
enabled: 0
settings:
CPU: None
- first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@@ -0,0 +1,33 @@
fileFormatVersion: 2
guid: 9c2c20067e0adc54c813350fd61f9a3a
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@@ -0,0 +1,33 @@
fileFormatVersion: 2
guid: e9164d2df3d1c03499419935666416ae
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@@ -0,0 +1,33 @@
fileFormatVersion: 2
guid: 152cea136489ac044b7c12c66ba72b53
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,33 @@
fileFormatVersion: 2
guid: e1ef9470a2a1d7b4da9ddd106620b665
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@@ -0,0 +1,33 @@
fileFormatVersion: 2
guid: 48f0c884a8a1e4043948f765ed18e4bc
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,33 @@
fileFormatVersion: 2
guid: 4d3d5b78e07866347b2ba028b4bd3ef8
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@@ -0,0 +1,33 @@
fileFormatVersion: 2
guid: ec4fba30706c64142a5504e3f0e64620
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,33 @@
fileFormatVersion: 2
guid: b3347ce24f73cab44a4191aa8976d88a
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@@ -519,7 +519,7 @@
<param name="Properties">The properties of the feature.</param>
<param name="BoundingBox">The bounding box.</param>
</member>
<member name="M:Cryville.EEW.Models.GeoJSON.Feature.#ctor(System.Object,Cryville.EEW.Models.GeoJSON.Geometry,System.Collections.Generic.IDictionary{System.String,System.Object},System.Double[])">
<member name="M:Cryville.EEW.Models.GeoJSON.Feature.#ctor(System.Text.Json.JsonElement,Cryville.EEW.Models.GeoJSON.Geometry,System.Collections.Generic.IDictionary{System.String,System.Text.Json.JsonElement},System.Double[])">
<summary>
Represents a spatially bounded thing.
</summary>
@@ -741,143 +741,143 @@
<member name="M:Cryville.EEW.Models.GeoJSON.PositionConverter.Write(System.Text.Json.Utf8JsonWriter,Cryville.EEW.Models.GeoJSON.Position,System.Text.Json.JsonSerializerOptions)">
<inheritdoc />
</member>
<member name="T:Cryville.EEW.Models.GeoJSON.GeoJSONSerializationContext">
<member name="T:Cryville.EEW.Models.GeoJSON.GeoJSONSerializerContext">
<summary>
<see cref="T:System.Text.Json.Serialization.JsonSerializerContext" /> for GeoJSON objects.
</summary>
</member>
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializationContext.Double">
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializerContext.Double">
<summary>
Defines the source generated JSON serialization contract metadata for a given type.
</summary>
</member>
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializationContext.NullableDouble">
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializerContext.NullableDouble">
<summary>
Defines the source generated JSON serialization contract metadata for a given type.
</summary>
</member>
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializationContext.DoubleArray">
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializerContext.DoubleArray">
<summary>
Defines the source generated JSON serialization contract metadata for a given type.
</summary>
</member>
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializationContext.Feature">
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializerContext.Feature">
<summary>
Defines the source generated JSON serialization contract metadata for a given type.
</summary>
</member>
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializationContext.FeatureArray">
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializerContext.FeatureArray">
<summary>
Defines the source generated JSON serialization contract metadata for a given type.
</summary>
</member>
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializationContext.FeatureCollection">
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializerContext.FeatureCollection">
<summary>
Defines the source generated JSON serialization contract metadata for a given type.
</summary>
</member>
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializationContext.GeoJSONObject">
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializerContext.GeoJSONObject">
<summary>
Defines the source generated JSON serialization contract metadata for a given type.
</summary>
</member>
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializationContext.Geometry">
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializerContext.Geometry">
<summary>
Defines the source generated JSON serialization contract metadata for a given type.
</summary>
</member>
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializationContext.GeometryArray">
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializerContext.GeometryArray">
<summary>
Defines the source generated JSON serialization contract metadata for a given type.
</summary>
</member>
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializationContext.GeometryCollection">
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializerContext.GeometryCollection">
<summary>
Defines the source generated JSON serialization contract metadata for a given type.
</summary>
</member>
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializationContext.LineString">
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializerContext.LineString">
<summary>
Defines the source generated JSON serialization contract metadata for a given type.
</summary>
</member>
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializationContext.MultiLineString">
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializerContext.MultiLineString">
<summary>
Defines the source generated JSON serialization contract metadata for a given type.
</summary>
</member>
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializationContext.MultiPoint">
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializerContext.MultiPoint">
<summary>
Defines the source generated JSON serialization contract metadata for a given type.
</summary>
</member>
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializationContext.MultiPolygon">
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializerContext.MultiPolygon">
<summary>
Defines the source generated JSON serialization contract metadata for a given type.
</summary>
</member>
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializationContext.Point">
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializerContext.Point">
<summary>
Defines the source generated JSON serialization contract metadata for a given type.
</summary>
</member>
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializationContext.Polygon">
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializerContext.Polygon">
<summary>
Defines the source generated JSON serialization contract metadata for a given type.
</summary>
</member>
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializationContext.Position">
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializerContext.Position">
<summary>
Defines the source generated JSON serialization contract metadata for a given type.
</summary>
</member>
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializationContext.PositionArray">
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializerContext.PositionArray">
<summary>
Defines the source generated JSON serialization contract metadata for a given type.
</summary>
</member>
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializationContext.PositionArrayArray">
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializerContext.PositionArrayArray">
<summary>
Defines the source generated JSON serialization contract metadata for a given type.
</summary>
</member>
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializationContext.PositionArrayArrayArray">
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializerContext.PositionArrayArrayArray">
<summary>
Defines the source generated JSON serialization contract metadata for a given type.
</summary>
</member>
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializationContext.IDictionaryStringObject">
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializerContext.IDictionaryStringJsonElement">
<summary>
Defines the source generated JSON serialization contract metadata for a given type.
</summary>
</member>
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializationContext.Object">
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializerContext.JsonElement">
<summary>
Defines the source generated JSON serialization contract metadata for a given type.
</summary>
</member>
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializationContext.String">
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializerContext.String">
<summary>
Defines the source generated JSON serialization contract metadata for a given type.
</summary>
</member>
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializationContext.Default">
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializerContext.Default">
<summary>
The default <see cref="T:System.Text.Json.Serialization.JsonSerializerContext"/> associated with a default <see cref="T:System.Text.Json.JsonSerializerOptions"/> instance.
</summary>
</member>
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializationContext.GeneratedSerializerOptions">
<member name="P:Cryville.EEW.Models.GeoJSON.GeoJSONSerializerContext.GeneratedSerializerOptions">
<summary>
The source-generated options associated with this context.
</summary>
</member>
<member name="M:Cryville.EEW.Models.GeoJSON.GeoJSONSerializationContext.#ctor">
<member name="M:Cryville.EEW.Models.GeoJSON.GeoJSONSerializerContext.#ctor">
<inheritdoc/>
</member>
<member name="M:Cryville.EEW.Models.GeoJSON.GeoJSONSerializationContext.#ctor(System.Text.Json.JsonSerializerOptions)">
<member name="M:Cryville.EEW.Models.GeoJSON.GeoJSONSerializerContext.#ctor(System.Text.Json.JsonSerializerOptions)">
<inheritdoc/>
</member>
<member name="M:Cryville.EEW.Models.GeoJSON.GeoJSONSerializationContext.GetTypeInfo(System.Type)">
<member name="M:Cryville.EEW.Models.GeoJSON.GeoJSONSerializerContext.GetTypeInfo(System.Type)">
<inheritdoc/>
</member>
<member name="T:Cryville.EEW.Models.XmlSerializedDateTimeOffset">
@@ -1039,6 +1039,9 @@
<member name="P:Cryville.EEW.Report.EmptyRVMGeneratorContext.SeverityScheme">
<inheritdoc />
</member>
<member name="P:Cryville.EEW.Report.EmptyRVMGeneratorContext.LocationConverter">
<inheritdoc />
</member>
<member name="T:Cryville.EEW.Report.EmptySeverityScheme">
<summary>
An empty <see cref="T:Cryville.EEW.Report.ISeverityScheme" /> that always returns <c>-1</c>.
@@ -1189,6 +1192,11 @@
The severity scheme.
</summary>
</member>
<member name="P:Cryville.EEW.Report.IRVMGeneratorContext.LocationConverter">
<summary>
The location converter.
</summary>
</member>
<member name="T:Cryville.EEW.Report.ISeverityScheme">
<summary>
Represents a severity scheme, extracting severity values from different properties.
@@ -1497,6 +1505,11 @@
The culture <c>en-US</c>.
</summary>
</member>
<member name="F:Cryville.EEW.SharedCultures.IdIdCulture">
<summary>
The culture <c>id-ID</c>.
</summary>
</member>
<member name="F:Cryville.EEW.SharedCultures.JaJpCulture">
<summary>
The culture <c>ja-JP</c>.
@@ -1512,6 +1525,16 @@
The culture <c>zh-TW</c>.
</summary>
</member>
<member name="F:Cryville.EEW.SharedCultures.CurrentCulture">
<summary>
The current culture.
</summary>
</member>
<member name="F:Cryville.EEW.SharedCultures.CurrentUICulture">
<summary>
The current UI culture.
</summary>
</member>
<member name="M:Cryville.EEW.SharedCultures.Get(System.String)">
<summary>
Gets a culture of the specified name.
@@ -1549,6 +1572,11 @@
China Standard Time.
</summary>
</member>
<member name="F:Cryville.EEW.SharedTimeZones.SEAsia">
<summary>
SE Asia Standard Time.
</summary>
</member>
<member name="F:Cryville.EEW.SharedTimeZones.Taipei">
<summary>
Taipei Standard Time.

BIN
Assets/Plugins/QuakeML.dll Normal file

Binary file not shown.

View File

@@ -0,0 +1,33 @@
fileFormatVersion: 2
guid: a5809b30a2765e54aa6f2b5d15c00a76
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@@ -0,0 +1,46 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &1455558857588368834
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8746876075196617235}
- component: {fileID: 122704584488816298}
m_Layer: 0
m_Name: Bitmap Holder
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &8746876075196617235
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1455558857588368834}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &122704584488816298
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1455558857588368834}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: c17f6b26e9a6bd74e8b2d071c6951c41, type: 3}
m_Name:
m_EditorClassIdentifier:

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 1a5cf693e0cf6b94390f72f521c151ba
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 75452b90c729a7248958090ab7acd6fd
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,12 @@
{
"Culture": "en-US",
"Strings": {
"Headline": "An earthquake{1} occurred at {0:HH:mm:ss 'on' MMM dd yyyy} Western Indonesia Time.{2}",
"HeadlineDepth": " Hypocenter depth {0}km.",
"HeadlineMagnitude": " of magnitude {0:F1}",
"MaxIntensity": "The maximum intensity observed is {0}.",
"Region": "The epicenter is in {0}.",
"Title": "Earthquake Data.",
"TitleStandAlone": "Earthquake Data"
}
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: e4420490220c6df4fb07cd0c63dec184
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,12 @@
{
"Culture": "id-ID",
"Strings": {
"Headline": "Telah terjadi gempa pada {0:dd MMMM yyyy 'pukul' H 'lewat' m 'menit' s 'detik'} Waktu Indonesia Barat{1}{2}.",
"HeadlineDepth": ", pada kedalaman {0} km",
"HeadlineMagnitude": ", dengan magnitudo {0:F1}",
"MaxIntensity": "Intensitas gempa maksimum yang dirasakan adalah {0}.",
"Region": "Pusat gempa berada di {0}.",
"Title": "Data Gempabumi.",
"TitleStandAlone": "Data Gempabumi"
}
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 76aa8016add210b489ed175d006ef35d
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,12 @@
{
"Culture": "yue-HK",
"Strings": {
"Headline": "印度尼西亞西部時間{0},發生咗一次{1}地震。{2}",
"HeadlineDepth": "震源深度{0}公里。",
"HeadlineMagnitude": "規模{0:F1}級。",
"MaxIntensity": "觀測到嘅最大烈度為{0}。",
"Region": "震中位於{0}。",
"Title": "地震數據。",
"TitleStandAlone": "地震數據"
}
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 8e3514f18dcd7b74b9b54beccc44859a
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,12 @@
{
"Culture": "zh-TW",
"Strings": {
"Headline": "印度尼西亞西部時間{0},發生了一次{1}地震。{2}",
"HeadlineDepth": "震源深度{0}公里。",
"HeadlineMagnitude": "規模{0:F1}級。",
"MaxIntensity": "觀測到的最大震度為{0}。",
"Region": "震中位於{0}。",
"Title": "地震數據。",
"TitleStandAlone": "地震數據"
}
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: cfe65eab919d49d468d19f4ecc516dd8
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,12 @@
{
"Culture": "zh-CN",
"Strings": {
"Headline": "印度尼西亚西部时间{0},发生了一次{1}地震。{2}",
"HeadlineDepth": "震源深度{0}千米。",
"HeadlineMagnitude": "规模{0:F1}级",
"MaxIntensity": "观测到的最大烈度为{0}。",
"Region": "震中位于{0}。",
"Title": "地震数据。",
"TitleStandAlone": "地震数据"
}
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 899b38f34c7628c4e936ec2bdfdd5410
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 470f88c90de9dd74387453bffdbf21f7
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,6 @@
{
"Culture": "en-US",
"Strings": {
"SourceName": "BMKG Open Data"
}
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: a1d44f3546003e1498cfc23e8d16942f
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,6 @@
{
"Culture": "id-ID",
"Strings": {
"SourceName": "Data Terbuka BMKG"
}
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: f3b9467d0b8b4054c818a5607dcc247a
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,6 @@
{
"Culture": "yue-HK",
"Strings": {
"SourceName": "BMKG 開放數據"
}
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: a025449f2f513e14fbbd596f87d47cb3
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,6 @@
{
"Culture": "zh-TW",
"Strings": {
"SourceName": "BMKG 開放數據"
}
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: d7c4a0eac847b5e458d4aaead9380023
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,6 @@
{
"Culture": "zh-CN",
"Strings": {
"SourceName": "BMKG 开放数据"
}
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 76619ea161099bc4ab2efb2ad0802bde
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 561a1f4df4315a04f9bcc5f961a8fd60
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,6 @@
{
"Culture": "en-US",
"Strings": {
"SourceName": "EMSC"
}
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 717e698cdc268a74b990d4c756f2bbda
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,7 @@
{
"Culture": "en-US",
"Parent": "und",
"Strings": {
"526": "Gulf of America"
}
}

Some files were not shown because too many files have changed in this diff Show More