20 Commits

Author SHA1 Message Date
a8f46113d4 build: Update project version 2025-06-06 19:33:15 +08:00
99736f114d style: Code cleanup 2025-06-06 19:32:42 +08:00
4d1a008106 feat: Add logs 2025-06-06 19:32:31 +08:00
9318cbca4e feat: Add new event sources 2025-06-06 19:31:27 +08:00
a162f345c4 ci: Update plugins 2025-06-06 19:30:21 +08:00
1af4afc7c6 build: Update project version 2025-05-07 22:56:45 +08:00
a3efe939e8 fix: Fix TTS COM exception in IL2CPP 2025-05-07 22:56:32 +08:00
5daee1a01a feat: Add TTS related settings 2025-05-06 20:35:52 +08:00
2d5d305528 feat: Implement TTS 2025-05-06 20:35:08 +08:00
8da46c0511 build: Update project version 2025-04-29 19:54:46 +08:00
75b5d7708c fix: Disable force HTTPS in NOAA Atom worker when debugging 2025-04-29 19:54:27 +08:00
5b2177a795 feat: Add using raw location name settings for CENC earthquake reports 2025-04-29 19:54:16 +08:00
8cb33dca5f ci: Update plugins 2025-04-29 19:53:24 +08:00
ae2e0af18a fix: Improve ongoing report round-robin period 2025-04-29 19:52:41 +08:00
2ac5a3d4f0 build: Update project version 2025-04-08 10:01:06 +08:00
5f78a1afde refactor: Code cleanup 2025-04-08 10:00:47 +08:00
ef5cf78a03 feat: Add display culture config 2025-04-08 10:00:28 +08:00
b60e62af70 feat: Adapt to breaking changes 2025-04-08 10:00:01 +08:00
3e59fe1462 feat: Implement region editor 2025-04-08 09:56:47 +08:00
4b4bf5ed65 ci: Update plugins 2025-04-08 09:53:33 +08:00
326 changed files with 9229 additions and 345 deletions

View File

@@ -1,19 +1,60 @@
using Cryville.Common.Font;
using Cryville.Common.Logging;
using Cryville.Common.Unity.UI;
using Cryville.Culture;
using System;
using System.Globalization;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using UnityEngine;
using Logger = Cryville.Common.Logging.Logger;
namespace Cryville.EEW.Unity {
class App {
public static string AppDataPath { get; private set; }
public static Logger MainLogger { get; private set; }
static FileStream _logFileStream;
static StreamLoggerListener _logWriter;
static bool _init;
public static void Init() {
if (_init) return;
_init = true;
AppDataPath = Application.persistentDataPath;
var logPath = Directory.CreateDirectory(Path.Combine(AppDataPath, "logs"));
_logFileStream = new FileStream(
Path.Combine(
logPath.FullName,
string.Format(
CultureInfo.InvariantCulture,
"{0}.log",
DateTimeOffset.UtcNow.ToString("yyyyMMddHHmmssfff", CultureInfo.InvariantCulture)
)
),
FileMode.Create, FileAccess.Write, FileShare.Read
);
_logWriter = new StreamLoggerListener(_logFileStream) { AutoFlush = true };
MainLogger = new Logger();
var listener = new InstantLoggerListener();
listener.Log += MainLogger.Log;
MainLogger.AddListener(_logWriter);
Application.logMessageReceivedThreaded += OnInternalLog;
MainLogger.Log(1, "App", null, "App Version: {0}", Application.version);
MainLogger.Log(1, "App", null, "Unity Version: {0}", Application.unityVersion);
MainLogger.Log(1, "App", null, "Operating System: {0}, Unity = {1}, Family = {2}", Environment.OSVersion, SystemInfo.operatingSystem, SystemInfo.operatingSystemFamily);
MainLogger.Log(1, "App", null, "Platform: Build = {0}, Unity = {1}", PlatformConfig.Name, Application.platform);
MainLogger.Log(1, "App", null, "Culture: {0}, UI = {1}, Unity = {2}", SharedCultures.CurrentCulture, SharedCultures.CurrentUICulture, Application.systemLanguage);
MainLogger.Log(1, "App", null, "Device: Model = {0}, Type = {1}", SystemInfo.deviceModel, SystemInfo.deviceType);
MainLogger.Log(1, "App", null, "Graphics: Name = {0}, Type = {1}, Vendor = {2}, Version = {3}", SystemInfo.graphicsDeviceName, SystemInfo.graphicsDeviceType, SystemInfo.graphicsDeviceVendor, SystemInfo.graphicsDeviceVersion);
MainLogger.Log(1, "App", null, "Processor: Count = {0}, Frequency = {1}MHz, Type = {2}", SystemInfo.processorCount, SystemInfo.processorFrequency, SystemInfo.processorType);
MainLogger.Log(1, "App", null, "Initializing font manager");
foreach (var res in Resources.LoadAll<TextAsset>("cldr/common/validity")) {
IdValidity.Load(LoadXmlDocument(res));
}
@@ -25,7 +66,10 @@ namespace Cryville.EEW.Unity {
};
TMPLocalizedText.DefaultShader = Resources.Load<Shader>(PlatformConfig.TextShader);
MainLogger.Log(1, "App", null, "Loading config");
SharedSettings.Instance.Init();
MainLogger.Log(1, "App", null, "Initialized");
}
static readonly Encoding _encoding = new UTF8Encoding(false, true);
@@ -40,5 +84,16 @@ namespace Cryville.EEW.Unity {
using var reader = XmlReader.Create(stream, _xmlSettings);
return XDocument.Load(reader);
}
static void OnInternalLog(string condition, string stackTrace, LogType type) {
var l = type switch {
LogType.Log => 1,
LogType.Assert => 2,
LogType.Warning => 3,
LogType.Error or LogType.Exception => 4,
_ => 1,
};
MainLogger.Log(l, "Internal", null, "{0}\n{1}", condition, stackTrace);
}
}
}

View File

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

View File

@@ -1,5 +1,9 @@
using Cryville.EEW.Core;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Cryville.EEW.Unity {
@@ -8,11 +12,18 @@ namespace Cryville.EEW.Unity {
float SeverityColorMappingLuminanceMultiplier,
bool UseContinuousColor,
string ColorScheme,
string LocationNamer,
string OverrideTimeZone,
bool DoDisplayTimeZone,
bool DoSwitchBackToHistory,
string NowcastWarningDelayTolerance,
string OverrideDisplayCulture,
IReadOnlyCollection<TTSCultureConfig> TTSCultures,
bool DoIgnoreLanguageVariant,
IReadOnlyCollection<EventSourceConfig> EventSources
) {
public static Config Default => new(
@@ -20,11 +31,18 @@ namespace Cryville.EEW.Unity {
1f,
false,
"Default",
"FERegionLong",
null,
true,
true,
"1:00:00",
"",
new List<TTSCultureConfig> { new(SharedCultures.CurrentUICulture) },
true,
new List<EventSourceConfig> {
new JMAAtomEventSourceConfig(Array.Empty<string>()),
new UpdateCheckerEventSourceConfig(),
@@ -37,6 +55,7 @@ namespace Cryville.EEW.Unity {
[JsonDerivedType(typeof(BMKGOpenDataEventSourceConfig), "BMKGOpenData")]
[JsonDerivedType(typeof(CWAOpenDataEventSourceConfig), "CWAOpenData")]
[JsonDerivedType(typeof(EMSCRealTimeEventSourceConfig), "EMSCRealTime")]
[JsonDerivedType(typeof(GeoNetEventSourceConfig), "GeoNet")]
[JsonDerivedType(typeof(GlobalQuakeServerEventSourceConfig), "GlobalQuakeServer")]
[JsonDerivedType(typeof(GlobalQuakeServer15EventSourceConfig), "GlobalQuakeServer15")]
[JsonDerivedType(typeof(JMAAtomEventSourceConfig), "JMAAtom")]
@@ -48,15 +67,30 @@ namespace Cryville.EEW.Unity {
record BMKGOpenDataEventSourceConfig([property: JsonRequired] string[] Subtypes) : EventSourceConfig;
record CWAOpenDataEventSourceConfig([property: JsonRequired] string Subtype, [property: JsonRequired] string Token) : EventSourceConfig;
record EMSCRealTimeEventSourceConfig() : EventSourceConfig;
record GeoNetEventSourceConfig(int MinimumMMI = 3, bool DoGetFullHistory = false, bool DoGetStrongMotionInfo = true) : 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;
record WolfxEventSourceConfig(IReadOnlyCollection<string> Filter = null, bool IsFilterWhitelist = false, bool UseRawCENCLocationName = false) : EventSourceConfig;
[JsonSerializable(typeof(Config))]
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSourceGenerationOptions(Converters = new Type[] { typeof(CultureInfoConverter) }, WriteIndented = true)]
sealed partial class ConfigSerializationContext : JsonSerializerContext { }
sealed class CultureInfoConverter : JsonConverter<CultureInfo> {
public override CultureInfo Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {
Debug.Assert(typeToConvert == typeof(CultureInfo));
var value = reader.GetString();
if (value == null) return CultureInfo.InvariantCulture;
if (value == "") return SharedCultures.CurrentUICulture;
return SharedCultures.Get(value);
}
public override void Write(Utf8JsonWriter writer, CultureInfo value, JsonSerializerOptions options) {
writer.WriteStringValue(value.Name);
}
}
}

View File

@@ -3,6 +3,7 @@
"rootNamespace": "",
"references": [
"GUID:b92f9c7ac10b1c04e86fc48210f62ab1",
"GUID:1e0937e40dadba24a97b7342c4559580",
"GUID:e5b7e7f40a80a814ba706299d68f9213",
"GUID:da293eebbcb9a4947a212534c52d1a32"
],

View File

@@ -17,19 +17,24 @@ namespace Cryville.EEW.Unity.Map {
GameObject m_prefabTile;
[SerializeField]
GameObject m_prefabBitmapHolder;
[SerializeField]
int m_maxMapTileZoom = 10;
[SerializeField]
bool m_isEditor;
readonly MapTileCacheManager _tiles = new();
MapTileCacheManager _tiles;
float _elementLayerZ;
void Start() {
_camera = GetComponent<Camera>();
_tiles = m_isEditor ? new EditorMapTileCacheManager() : new MapTileCacheManager();
_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;
if (m_layerElement != null) _elementLayerZ = m_layerElement.transform.position.z;
_mapElementUpdated = true;
}
void OnDestroy() {
@@ -74,7 +79,7 @@ namespace Cryville.EEW.Unity.Map {
}
}
void ZoomToMapElement() {
var aabb = m_layerElement.AABB;
var aabb = m_layerElement != null ? m_layerElement.AABB : null;
if (aabb is not RectangleF b) return;
if (b.Width * _camera.pixelHeight < _camera.pixelWidth * b.Height)
Scale = b.Height;
@@ -97,26 +102,30 @@ namespace Cryville.EEW.Unity.Map {
transform.localPosition = new(nx, Math.Clamp(transform.position.y, h / 2 - 1, -h / 2), -20);
var bounds = new Bounds((Vector2)transform.position, new Vector2(w, h));
int zoom = Math.Clamp((int)Math.Log(vz / 256, 2) + 1, 0, 10);
int zoom = Math.Clamp((int)Math.Log(vz / 256, 2) + 1, 0, m_maxMapTileZoom);
int zoomScale = 1 << zoom;
_tiles.MoveTo(
new(Mathf.FloorToInt(bounds.min.x * zoomScale), Mathf.FloorToInt(-bounds.max.y * zoomScale), zoom),
new(Mathf.CeilToInt(bounds.max.x * zoomScale), Mathf.CeilToInt(-bounds.min.y * zoomScale), zoom)
);
m_layerElement.Scale = h;
m_layerElementSub.Scale = h;
if (m_layerElement != null) {
m_layerElement.Scale = h;
}
if (m_layerElementSub != null) {
m_layerElementSub.Scale = h;
if (nx - w / 2 < 0) {
m_layerElementSub.gameObject.SetActive(true);
m_layerElementSub.transform.localPosition = new(-1, 0, _elementLayerZ);
}
else if (nx + w / 2 > 1) {
m_layerElementSub.gameObject.SetActive(true);
m_layerElementSub.transform.localPosition = new(1, 0, _elementLayerZ);
}
else {
m_layerElementSub.gameObject.SetActive(false);
if (nx - w / 2 < 0) {
m_layerElementSub.gameObject.SetActive(true);
m_layerElementSub.transform.localPosition = new(-1, 0, _elementLayerZ);
}
else if (nx + w / 2 > 1) {
m_layerElementSub.gameObject.SetActive(true);
m_layerElementSub.transform.localPosition = new(1, 0, _elementLayerZ);
}
else {
m_layerElementSub.gameObject.SetActive(false);
}
}
}
}

View File

@@ -0,0 +1,15 @@
using Cryville.EEW.Core.Map;
using System.IO;
using UnityEngine;
namespace Cryville.EEW.Unity.Map {
sealed class EditorMapTileCacheManager : MapTileCacheManager {
protected override MapTileBitmapHolder CreateBitmapHolder(MapTileIndex index) => new(
index,
GameObject.Instantiate(PrefabBitmapHolder, Parent, false),
new($"https://tile.openstreetmap.org/{index.Z}/{index.NX}/{index.NY}.png")
);
protected override string GetCacheFilePath(MapTileIndex index) => Path.Combine(CacheDir, $"map_editor/{index.Z}/{index.NX}/{index.NY}");
}
}

View File

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

View File

@@ -2,6 +2,7 @@ using Cryville.EEW.BMKGOpenData.Map;
using Cryville.EEW.Core;
using Cryville.EEW.CWAOpenData.Map;
using Cryville.EEW.EMSC.Map;
using Cryville.EEW.GeoNet.Map;
using Cryville.EEW.GlobalQuake.Map;
using Cryville.EEW.JMAAtom.Map;
using Cryville.EEW.Map;
@@ -135,6 +136,9 @@ namespace Cryville.EEW.Unity.Map {
new CWATsunamiMapGenerator(),
new EMSCRealTimeEventMapGenerator(),
new FujianEEWMapGenerator(),
new GeoNetQuakeHistoryMapGenerator(),
new GeoNetQuakeMapGenerator(),
new GeoNetStrongMapGenerator(),
new GlobalQuakeMapViewGenerator(),
new JMAAtomMapGenerator(),
new JMAEEWMapGenerator(),

View File

@@ -7,10 +7,12 @@ using UnityEngine;
namespace Cryville.EEW.Unity.Map {
sealed class MapTileBitmapHolder : Core.Map.MapTileBitmapHolder {
MapTileBitmapHolderBehaviour _behaviour;
readonly MapTileBitmapHolderBehaviour _behaviour;
readonly Uri _uri;
public MapTileBitmapHolder(MapTileIndex index, GameObject gameObject) : base(index) {
public MapTileBitmapHolder(MapTileIndex index, GameObject gameObject, Uri uri) : base(index) {
_behaviour = gameObject.GetComponent<MapTileBitmapHolderBehaviour>();
_uri = uri;
}
protected override void Dispose(bool disposing) {
@@ -20,8 +22,7 @@ namespace Cryville.EEW.Unity.Map {
}
}
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 Uri GetUri() => _uri;
protected override Task LoadBitmap(FileInfo file, CancellationToken cancellationToken) {
_behaviour.Load(file);

View File

@@ -40,18 +40,18 @@ namespace Cryville.EEW.Unity.Map {
_req.SendWebRequest();
}
catch (Exception ex) {
Debug.LogException(ex);
App.MainLogger.Log(4, "Map", null, "An error occurred when loading map tile {0}: {1}", _localFile, ex);
}
_isReady = false;
}
if (_req == null || !_req.isDone) return;
if (_texHandler.isDone) {
if (_texHandler.isDone && _texHandler.texture != null) {
_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);
App.MainLogger.Log(4, "Map", null, "An error occurred when loading map tile {0}: {1}", _localFile, _texHandler.error);
_localFile.Delete();
}
_req.Dispose();

View File

@@ -4,7 +4,7 @@ using System.IO;
using UnityEngine;
namespace Cryville.EEW.Unity.Map {
sealed class MapTileCacheManager : MapTileCacheManager<MapTileBitmapHolder> {
class MapTileCacheManager : MapTileCacheManager<MapTileBitmapHolder> {
public GameObject PrefabTile { get; set; }
public GameObject PrefabBitmapHolder { get; set; }
@@ -12,8 +12,12 @@ namespace Cryville.EEW.Unity.Map {
public string CacheDir { get; set; }
protected override MapTileBitmapHolder CreateBitmapHolder(MapTileIndex index) => new(index, GameObject.Instantiate(PrefabBitmapHolder, Parent, false));
protected override MapTileBitmapHolder CreateBitmapHolder(MapTileIndex index) => new(
index,
GameObject.Instantiate(PrefabBitmapHolder, Parent, false),
new($"https://server.arcgisonline.com/ArcGIS/rest/services/Ocean/World_Ocean_Base/MapServer/tile/{index.Z}/{index.NY}/{index.NX}")
);
protected override string GetCacheFilePath(MapTileIndex index) => Path.Combine(CacheDir, $"map/{index.Z}/{index.NX}/{index.NY}");
readonly Dictionary<MapTile<MapTileBitmapHolder>, MapTile> _map = new();

View File

@@ -0,0 +1,219 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text.Json;
using System.Text.Json.Serialization;
using TMPro;
using UnityEngine;
namespace Cryville.EEW.Unity.Map {
sealed class RegionEditor : MonoBehaviour {
QuadTreeNode _root;
[SerializeField] CameraController m_cameraController;
[SerializeField] GameObject m_regionViewPrefab;
[SerializeField] TMP_Text m_textSelectedInfo;
[SerializeField] TMP_Text m_textHoveredInfo;
[SerializeField] TMP_InputField m_inputId;
readonly Dictionary<QuadTreeNode, RegionView> _map = new();
void Start() {
var file = new FileInfo(Path.Combine(Application.persistentDataPath, "regions.json"));
if (file.Exists) {
using var stream = file.OpenRead();
_root = JsonSerializer.Deserialize<QuadTreeNode>(stream);
}
else {
_root = NewNode();
}
BuildView(_root);
}
public void Save() {
var file = new FileInfo(Path.Combine(Application.persistentDataPath, "regions.json"));
using var stream = file.Open(FileMode.Create);
JsonSerializer.Serialize(stream, _root);
}
void BuildView(QuadTreeNode node) {
var view = Instantiate(m_regionViewPrefab, transform, false).GetComponent<RegionView>();
view.Init(node.X, node.Y, node.Z);
view.Id = node.Data.Id;
view.IsLeaf = node.Children == null;
_map.Add(node, view);
BuildChildViews(node);
}
void BuildChildViews(QuadTreeNode node) {
if (node.Children == null) return;
foreach (var child in node.Children) {
BuildView(child);
}
}
void DestroyChildViews(QuadTreeNode node) {
if (node.Children == null) return;
foreach (var child in node.Children) {
Destroy(_map[child].gameObject);
_map.Remove(child);
}
}
QuadTreeNode _hoveredNode;
QuadTreeNode _selectedNode;
Vector3? _ppos;
void Update() {
var pos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
pos.y += 1;
var hoveredNode = _root.Get(pos);
if (hoveredNode != _hoveredNode) {
HoverNode(hoveredNode);
}
if (Input.GetMouseButtonDown(0)) {
_ppos = Input.mousePosition;
}
if (Input.GetMouseButton(0) && _ppos is Vector3 pos0) {
if (Input.mousePosition != pos0) {
_ppos = null;
}
}
if (hoveredNode == null) return;
if (Input.GetMouseButtonUp(0) && _ppos != null) {
SelectNode(hoveredNode);
_ppos = null;
}
if (m_inputId.isFocused)
return;
if (Input.GetKeyUp(KeyCode.A)) {
MergeNode(hoveredNode);
}
if (Input.GetKeyUp(KeyCode.S)) {
SplitNode(hoveredNode);
}
if (Input.GetKeyUp(KeyCode.C)) {
m_inputId.text = hoveredNode.Data.Id;
}
if (Input.GetKeyUp(KeyCode.V)) {
hoveredNode.Data.Id = m_inputId.text;
_map[hoveredNode].Id = hoveredNode.Data.Id;
}
}
void HoverNode(QuadTreeNode node) {
if (_hoveredNode != null) {
_map[_hoveredNode].IsHovered = false;
}
_hoveredNode = node;
if (_hoveredNode != null) {
_map[_hoveredNode].IsHovered = true;
m_textHoveredInfo.text = string.Format(CultureInfo.InvariantCulture, "<Hovered>\nZ: {2}, XY: ({0}, {1})\nD: {3}", node.X, node.Y, node.Z, node.Data.Id);
}
else {
m_textHoveredInfo.text = "";
}
}
void SelectNode(QuadTreeNode node) {
if (_selectedNode != null) {
_map[_selectedNode].IsSelected = false;
}
_selectedNode = node;
if (_selectedNode != null) {
_map[_selectedNode].IsSelected = true;
m_textSelectedInfo.text = string.Format(CultureInfo.InvariantCulture, "<Selected>\nZ: {2}, XY: ({0}, {1})\nD: {3}", node.X, node.Y, node.Z, node.Data.Id);
}
else {
m_textSelectedInfo.text = "";
}
}
void MergeNode(QuadTreeNode node) {
var parent = node.Parent;
if (parent == null)
return;
DestroyChildViews(parent);
_map[parent].IsLeaf = true;
parent.Merge();
_hoveredNode = null;
if (_selectedNode != null && !_map.ContainsKey(_selectedNode)) {
_selectedNode = null;
}
}
void SplitNode(QuadTreeNode node) {
node.Split();
_map[node].IsLeaf = false;
BuildChildViews(node);
}
static QuadTreeNode NewNode() => new() { Data = new("") };
sealed class QuadTreeNode {
QuadTreeNode[] m_children;
public QuadTreeNode[] Children {
get => m_children;
set {
if (m_children != null) {
foreach (var child in m_children) {
child.DetachFromParent();
}
}
m_children = value;
UpdateChildren();
}
}
QuadTreeNode m_parent;
[JsonIgnore] public QuadTreeNode Parent => m_parent;
void AttachToParent(QuadTreeNode parent, int index) {
if (m_parent != null && m_parent != parent)
throw new InvalidOperationException("Node already in a tree.");
m_parent = parent;
X = (parent.X << 1) | (index is 0 or 3 ? 1 : 0);
Y = (parent.Y << 1) | (index is 0 or 1 ? 1 : 0);
Z = parent.Z + 1;
UpdateChildren();
}
void DetachFromParent() => m_parent = null;
void UpdateChildren() {
if (m_children != null) {
for (int i = 0; i < m_children.Length; i++) {
m_children[i].AttachToParent(this, i);
}
}
}
[JsonIgnore] public int X { get; private set; }
[JsonIgnore] public int Y { get; private set; }
[JsonIgnore] public int Z { get; private set; }
public RegionData Data { get; set; }
public QuadTreeNode Get(Vector2 pos) {
if ((pos.x is < 0 or >= 1) || (pos.y is < 0 or >= 1))
return null;
if (m_children == null)
return this;
Vector2 subPos = pos * 2;
subPos.x %= 1;
subPos.y %= 1;
return pos.x >= 0.5f
? (pos.y >= 0.5f ? m_children[0] : m_children[3]).Get(subPos)
: (pos.y >= 0.5f ? m_children[1] : m_children[2]).Get(subPos);
}
public void Merge() {
Children = null;
}
public void Split() {
Children = new QuadTreeNode[] {
new() { Data = Data.Copy() },
new() { Data = Data.Copy() },
new() { Data = Data.Copy() },
new() { Data = Data.Copy() },
};
}
}
sealed record RegionData(string Id) {
public string Id { get; set; } = Id;
public RegionData Copy() => (RegionData)MemberwiseClone();
}
}
}

View File

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

View File

@@ -0,0 +1,68 @@
using UnityEngine;
namespace Cryville.EEW.Unity.Map {
sealed class RegionView : MonoBehaviour {
[SerializeField]
SpriteRenderer m_spriteRenderer;
Color _color;
bool m_isHovered;
public bool IsHovered {
get => m_isHovered;
set {
m_isHovered = value;
UpdateColor();
}
}
bool m_isSelected;
public bool IsSelected {
get => m_isSelected;
set {
m_isSelected = value;
UpdateColor();
}
}
bool m_isLeaf = true;
public bool IsLeaf {
get => m_isLeaf;
set {
m_isLeaf = value;
UpdateColor();
}
}
string m_id;
public string Id {
get => m_id;
set {
m_id = value;
unchecked {
uint hash = (uint)value.GetHashCode();
_color = Color.HSVToRGB(((hash >> 24) ^ ((hash >> 16) & 0xff) ^ ((hash >> 8) & 0xff) ^ (hash & 0xff)) / (float)0xff, 1, 1);
}
UpdateColor();
}
}
public void Init(int x, int y, int z) {
float scale = 1f / (1 << z);
transform.localScale = new Vector3(scale, scale, 1);
transform.localPosition = new Vector3(x * scale, y * scale - 1, -1 - z / 100f);
}
void UpdateColor() {
if (!m_isLeaf)
_color.a = 0.0f;
else if (m_isSelected)
_color.a = 0.6f;
else if (m_isHovered)
_color.a = 0.4f;
else
_color.a = 0.2f;
m_spriteRenderer.color = _color;
}
}
}

View File

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

View File

@@ -1,4 +1,5 @@
using Cryville.EEW.Colors;
using Cryville.EEW.Core;
using Cryville.EEW.Core.Colors;
using Cryville.EEW.FERegion;
using Cryville.EEW.Map;
@@ -25,8 +26,23 @@ namespace Cryville.EEW.Unity {
public IColorScheme ColorScheme { get; private set; } = new SeverityBasedColorScheme(DefaultSeverityScheme.Instance, DefaultSeverityColorMapping.Instance);
public ISubColorScheme BorderColorScheme { get; private set; } = new WrappedColorScheme(new SeverityBasedColorScheme(DefaultSeverityScheme.Instance, DefaultSeverityColorMapping.SecondaryInstance));
public ISubColorScheme TextColorScheme { get; private set; } = new DefaultTextColorScheme(Color.White, Color.Black);
public ILocationConverter LocationConverter => new FERegionLongConverter(); // TODO TTS
public TimeSpan NowcastWarningDelayTolerance => TimeSpan.FromMinutes(60); // TODO TTS
public TimeSpan NowcastWarningDelayTolerance { get; private set; } = TimeSpan.FromMinutes(60);
public CultureInfo RVMCulture { get; private set; } = SharedCultures.CurrentUICulture;
readonly int _infoLocationSpecificity = 3;
readonly int _ttsLocationSpecificity = 3;
readonly LocationNamer _locationNamer = new() { Namer = new FERegionLongNamer() };
public bool NameLocation(double lat, double lon, CultureInfo localCulture, ref CultureInfo targetCulture, out string name, out int specificity) {
specificity = _ttsLocationSpecificity;
return _locationNamer.Name(lat, lon, localCulture, ref targetCulture, out name, ref specificity);
}
public bool NameLocation(double lat, double lon, CultureInfo localCulture, ref CultureInfo targetCulture, out string name) {
int specificity = _infoLocationSpecificity;
return _locationNamer.Name(lat, lon, localCulture, ref targetCulture, out name, ref specificity);
}
public IReadOnlyCollection<TTSCultureConfig> TTSCultures { get; private set; }
public bool DoIgnoreLanguageVariant { get; private set; }
public TimeZoneInfo OverrideTimeZone { get; private set; }
public bool DoDisplayTimeZone { get; private set; } = true;
@@ -101,9 +117,20 @@ namespace Cryville.EEW.Unity {
"SREV" => new DefaultTextColorScheme(Color.White, Color.FromArgb(28, 28, 28), 0.555f),
_ => new DefaultTextColorScheme(Color.White, Color.Black),
};
_locationNamer.Namer = config.LocationNamer switch {
"FERegionShort" => new FERegionShortNamer(),
_ => new FERegionLongNamer(),
};
if (config.NowcastWarningDelayTolerance is string nowcastWarningDelayTolerance)
NowcastWarningDelayTolerance = TimeSpan.Parse(nowcastWarningDelayTolerance, CultureInfo.InvariantCulture);
OverrideTimeZone = ParseTimeZone(config.OverrideTimeZone);
DoDisplayTimeZone = config.DoDisplayTimeZone;
DoSwitchBackToHistory = config.DoSwitchBackToHistory;
RVMCulture = config.OverrideDisplayCulture is string rvmCulture
? (string.IsNullOrEmpty(rvmCulture) ? SharedCultures.CurrentUICulture : SharedCultures.Get(rvmCulture))
: CultureInfo.InvariantCulture;
TTSCultures = config.TTSCultures ?? new List<TTSCultureConfig> { new(CultureInfo.InvariantCulture) };
DoIgnoreLanguageVariant = config.DoIgnoreLanguageVariant;
EventSources = config.EventSources;
}

View File

@@ -5,7 +5,7 @@ using System.IO;
using UnityEngine;
namespace Cryville.EEW.Unity {
class SoundPlayer : Core.SoundPlayer {
class SoundPlayer : Core.Audio.SoundPlayer {
public SoundPlayer() : base(GetEngineList(), AudioUsage.NotificationEvent) { }
static List<Type> GetEngineList() => new() {
typeof(Audio.Wasapi.MMDeviceEnumeratorWrapper),
@@ -13,6 +13,7 @@ namespace Cryville.EEW.Unity {
};
protected override Stream Open(string path) {
App.MainLogger.Log(0, "Audio", null, "Opening audio file {0}", path);
path = Path.Combine(Application.streamingAssetsPath, "Sounds", path + ".ogg");
if (!File.Exists(path)) return null;
return new FileStream(path, FileMode.Open, FileAccess.Read);

View File

@@ -1,25 +1,53 @@
using SpeechLib;
using System;
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
namespace Cryville.EEW.Unity {
class TTSWorker : Core.TTSWorker {
public TTSWorker() : base(CreateSoundPlayer()) { }
class TTSWorker : Core.Audio.TTSWorker {
readonly ISpVoice _voice;
public TTSWorker() : base(CreateSoundPlayer()) {
App.MainLogger.Log(1, "Audio", null, "Initializing TTS worker");
try {
_voice = new SpVoiceClass();
}
catch { }
}
static SoundPlayer CreateSoundPlayer() {
App.MainLogger.Log(1, "Audio", null, "Creating sound player");
try {
return new SoundPlayer();
}
catch (InvalidOperationException) {
catch (InvalidOperationException ex) {
App.MainLogger.Log(3, "Audio", null, "An error occurred when creating sound player: {0}", ex);
return null;
}
}
protected override bool IsSpeaking() => false;
protected override bool IsSpeaking() {
if (_voice == null) return false;
_voice.GetStatus(out var status, out _);
return (status.dwRunningState & (uint)SpeechRunState.SRSEIsSpeaking) != 0;
}
protected override Task Speak(CultureInfo culture, string content, CancellationToken cancellationToken) => Task.CompletedTask;
protected override Task Speak(CultureInfo culture, string content, CancellationToken cancellationToken) {
if (_voice == null) return Task.CompletedTask;
_voice.Speak(
string.Format(CultureInfo.InvariantCulture, "<LANG LANGID=\"{0:x}\">{1}</LANG>", culture.LCID, content),
(uint)(SpeechVoiceSpeakFlags.SVSFlagsAsync | SpeechVoiceSpeakFlags.SVSFPurgeBeforeSpeak),
out _
);
App.MainLogger.Log(0, "Audio", null, "TTS ({0}): {1}", culture, content);
return Task.CompletedTask;
}
protected override void StopCurrent() { }
protected override void StopCurrent() {
if (_voice == null) return;
App.MainLogger.Log(0, "Audio", null, "TTS stopping current");
_voice.Skip("SENTENCE", int.MaxValue, out _);
}
}
}

View File

@@ -23,6 +23,7 @@ namespace Cryville.EEW.Unity.UI {
child.SetViewModel(e);
child.transform.SetParent(m_listView, false);
_displayingViews.Add(child);
OnDisplayingViewsChanged();
SwitchTo(_displayingReports.Count - 1);
@@ -37,6 +38,7 @@ namespace Cryville.EEW.Unity.UI {
child.SetParent(null, false);
Destroy(child.gameObject);
_displayingViews.RemoveAt(index);
OnDisplayingViewsChanged();
if (_displayingReports.Count == 0) {
m_currentView.gameObject.SetActive(false);
@@ -49,6 +51,14 @@ namespace Cryville.EEW.Unity.UI {
if (_displayingReports.Count <= 1) m_listView.gameObject.SetActive(false);
}
void OnDisplayingViewsChanged() {
_maxBaseDuration = 1;
foreach (var e in _displayingReports) {
float duration = GetBaseDuration(e);
if (duration > _maxBaseDuration)
_maxBaseDuration = duration;
}
}
void Awake() {
if (Instance != null) {
@@ -63,6 +73,7 @@ namespace Cryville.EEW.Unity.UI {
int _index = -1;
float _tickDown;
float _maxBaseDuration;
void Update() {
if (_displayingReports.Count == 0) return;
_tickDown -= Time.deltaTime;
@@ -77,12 +88,15 @@ namespace Cryville.EEW.Unity.UI {
_index = index;
var e = _displayingReports[index];
m_currentView.SetViewModel(e, true);
var keyProp = e.Properties.FirstOrDefault();
_displayingViews[_index].SetCurrent(true);
_tickDown = MathF.Exp(Math.Max(-1f, keyProp?.Severity ?? -1f) + 1);
_tickDown = GetBaseDuration(e) / Math.Min(_maxBaseDuration, 4) * 4;
m_currentView.gameObject.SetActive(true);
Worker.Instance.SetCurrent(e);
}
static float GetBaseDuration(ReportViewModel e) {
return MathF.Exp(Math.Max(-1f, e.Properties.FirstOrDefault()?.Severity ?? -1f) + 1);
}
public void OnItemClicked(ReportViewModel viewModel) {
int index = _displayingReports.IndexOf(viewModel);
if (index == -1) return;

View File

@@ -12,8 +12,8 @@ namespace Cryville.EEW.Unity.UI {
_textView = GetComponent<TMP_Text>();
}
StringBuilder _sb = new();
char[] _buffer = new char[256];
readonly StringBuilder _sb = new();
readonly char[] _buffer = new char[256];
void Update() {
_sb.Clear();
_sb.AppendFormat(

View File

@@ -5,6 +5,8 @@ using Cryville.EEW.CWAOpenData;
using Cryville.EEW.CWAOpenData.Model;
using Cryville.EEW.CWAOpenData.TTS;
using Cryville.EEW.EMSC;
using Cryville.EEW.GeoNet;
using Cryville.EEW.GeoNet.TTS;
using Cryville.EEW.GlobalQuake;
using Cryville.EEW.JMAAtom;
using Cryville.EEW.JMAAtom.TTS;
@@ -58,16 +60,21 @@ namespace Cryville.EEW.Unity {
}
void Start() {
App.MainLogger.Log(1, "App", null, "Initializing localized resources manager");
LocalizedResources.Init(new LocalizedResourcesManager());
RegisterViewModelGenerators(_worker);
RegisterTTSMessageGenerators(_worker);
BuildWorkers();
_worker.RVMGeneratorContext = SharedSettings.Instance;
_worker.TTSMessageGeneratorContext = SharedSettings.Instance;
_worker.RVMCulture = SharedSettings.Instance.RVMCulture;
_worker.SetTTSCultures(SharedSettings.Instance.TTSCultures ?? new TTSCultureConfig[0]);
_worker.IgnoreLanguageVariant = SharedSettings.Instance.DoIgnoreLanguageVariant;
_ongoingReportManager.Changed += OnOngoingReported;
_worker.Reported += OnReported;
_grouper.GroupUpdated += OnGroupUpdated;
_grouper.GroupRemoved += OnGroupRemoved;
App.MainLogger.Log(1, "App", null, "Worker ready");
Task.Run(() => GatewayVerify(_cancellationTokenSource.Token)).ContinueWith(task => {
if (task.IsFaulted) {
OnReported(this, new() { Title = task.Exception.Message });
@@ -87,15 +94,19 @@ namespace Cryville.EEW.Unity {
_ongoingReportManager.Dispose();
}
static void RegisterViewModelGenerators(CoreWorker worker) {
CENCEarthquakeRVMGenerator _cencEarthquakeRVMGenerator;
void RegisterViewModelGenerators(CoreWorker worker) {
worker.RegisterViewModelGenerator(new BMKGEarthquakeRVMGenerator());
worker.RegisterViewModelGenerator(new CENCEarthquakeRVMGenerator());
worker.RegisterViewModelGenerator(_cencEarthquakeRVMGenerator = 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 GeoNetQuakeHistoryRVMGenerator());
worker.RegisterViewModelGenerator(new GeoNetQuakeRVMGenerator());
worker.RegisterViewModelGenerator(new GeoNetStrongRVMGenerator());
worker.RegisterViewModelGenerator(new GlobalQuakeRVMGenerator());
worker.RegisterViewModelGenerator(new JMAAtomRVMGenerator());
worker.RegisterViewModelGenerator(new JMAEEWRVMGenerator());
@@ -104,14 +115,18 @@ namespace Cryville.EEW.Unity {
worker.RegisterViewModelGenerator(new SichuanEEWRVMGenerator());
worker.RegisterViewModelGenerator(new VersionRVMGenerator());
}
static void RegisterTTSMessageGenerators(CoreWorker worker) {
CENCEarthquakeTTSMessageGenerator _cencEarthquakeTTSMessageGenerator;
void RegisterTTSMessageGenerators(CoreWorker worker) {
worker.RegisterTTSMessageGenerator(new BMKGEarthquakeTTSMessageGenerator());
worker.RegisterTTSMessageGenerator(new CENCEarthquakeTTSMessageGenerator());
worker.RegisterTTSMessageGenerator(_cencEarthquakeTTSMessageGenerator = new CENCEarthquakeTTSMessageGenerator());
worker.RegisterTTSMessageGenerator(new CENCEEWTTSMessageGenerator());
worker.RegisterTTSMessageGenerator(new CWAEarthquakeTTSMessageGenerator());
worker.RegisterTTSMessageGenerator(new CWAEEWTTSMessageGenerator());
worker.RegisterTTSMessageGenerator(new CWATsunamiTTSMessageGenerator());
worker.RegisterTTSMessageGenerator(new FujianEEWTTSMessageGenerator());
worker.RegisterTTSMessageGenerator(new GeoNetQuakeHistoryTTSMessageGenerator());
worker.RegisterTTSMessageGenerator(new GeoNetQuakeTTSMessageGenerator());
worker.RegisterTTSMessageGenerator(new GeoNetStrongTTSMessageGenerator());
worker.RegisterTTSMessageGenerator(new JMAAtomTTSMessageGenerator());
worker.RegisterTTSMessageGenerator(new JMAEEWTTSMessageGenerator());
worker.RegisterTTSMessageGenerator(new NOAATTSMessageGenerator());
@@ -120,6 +135,7 @@ namespace Cryville.EEW.Unity {
bool _verified;
void BuildWorkers() {
App.MainLogger.Log(1, "App", null, "Building workers");
#if UNITY_EDITOR
_worker.AddWorker(new WolfxWorker(new Uri("ws://localhost:9995/wolfx")));
_worker.AddWorker(new JMAAtomWorker(new Uri("http://localhost:9095/eqvol.xml")));
@@ -129,30 +145,31 @@ namespace Cryville.EEW.Unity {
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 NOAAAtomWorker(new("http://localhost:9095/PAAQAtom.xml"), forceHttps: false));
_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),
BMKGOpenDataEventSourceConfig bmkgOpenData => BuildBMKGOpenDataWorkerUris(new(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),
"E-A0014-001" => new CWAReportWorker<Tsunami>(new("https://opendata.cwa.gov.tw/api/v1/rest/datastore/E-A0014-001"), cwaOpenData.Token, 1440, 17280),
"E-A0015-001" => new CWAReportWorker<Earthquake>(new("https://opendata.cwa.gov.tw/api/v1/rest/datastore/E-A0015-001"), cwaOpenData.Token),
"E-A0016-001" => new CWAReportWorker<Earthquake>(new("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")),
GeoNetEventSourceConfig geoNet => BuildGeoNetWorker(new(new("https://api.geonet.org.nz/quake"), new("https://api.geonet.org.nz/quake/history/index"), new("https://api.geonet.org.nz/intensity/strong/processed/index")), geoNet),
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),
JMAAtomEventSourceConfig jmaAtom => BuildJMAAtomWorkerFilter(new(new("https://www.data.jma.go.jp/developer/xml/feed/eqvol.xml")), jmaAtom),
NOAAEventSourceConfig noaaAtom => noaaAtom.Subtype switch {
"PAAQ" => new NOAAAtomWorker(new("https://www.tsunami.gov/events/xml/PAAQAtom.xml"), new("https://www.tsunami.gov/"), new("/php/esri.php?e=t", UriKind.Relative), "PAAQ"),
"PHEB" => new NOAAAtomWorker(new("https://www.tsunami.gov/events/xml/PHEBAtom.xml"), new("https://www.tsunami.gov/"), new("/php/esri.php?e=t", UriKind.Relative), "PHEB"),
_ => 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),
USGSQuakeMLEventSourceConfig usgsQuakeML => BuildUSGSQuakeMLWorkerUri(new USGSQuakeMLWorker(new("https://earthquake.usgs.gov/earthquakes/feed/v1.0/quakeml.php")), usgsQuakeML),
WolfxEventSourceConfig wolfx => BuildWolfxWorkerFilter(new WolfxWorker(new("wss://ws-api.wolfx.jp/all_eew")), wolfx),
_ => throw new InvalidOperationException("Unknown event source type."),
});
}
@@ -163,7 +180,7 @@ namespace Cryville.EEW.Unity {
worker.IsFilterWhitelist = config.IsFilterWhitelist;
return worker;
}
static WolfxWorker BuildWolfxWorkerFilter(WolfxWorker worker, WolfxEventSourceConfig config) {
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>),
@@ -174,12 +191,23 @@ namespace Cryville.EEW.Unity {
_ => throw new InvalidOperationException("Unknown Wolfx event type."),
}));
worker.IsFilterWhitelist = config.IsFilterWhitelist;
_cencEarthquakeRVMGenerator.UseRawLocationName
= _cencEarthquakeTTSMessageGenerator.UseRawLocationName
= config.UseRawCENCLocationName;
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 GeoNetWorker BuildGeoNetWorker(GeoNetWorker worker, GeoNetEventSourceConfig pref) {
worker.MinimumMMI = pref.MinimumMMI;
worker.DoGetFullHistory = pref.DoGetFullHistory;
worker.DoGetStrongMotionInfo = pref.DoGetStrongMotionInfo;
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;
@@ -190,7 +218,7 @@ namespace Cryville.EEW.Unity {
ReportViewModel _latestHistoryReport;
void OnReported(object sender, ReportViewModel e) {
if (e.Model is Exception && e.Model is not SourceWorkerNetworkException)
Debug.LogError(e);
App.MainLogger.Log(4, "Map", null, "Received an error from {0}: {1}", sender.GetType(), e.Model);
_grouper.Report(e);
_ongoingReportManager.Report(e);
_uiActionQueue.Enqueue(() => {

Binary file not shown.

View File

@@ -0,0 +1,33 @@
fileFormatVersion: 2
guid: 7aa0c56ccfdaf9443b58f26bf40eed01
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:

View File

@@ -0,0 +1,185 @@
<?xml version="1.0"?>
<doc>
<assembly>
<name>Cryville.Common.Logging</name>
</assembly>
<members>
<member name="T:Cryville.Common.Logging.Logger">
<summary>
A logger.
</summary>
</member>
<member name="M:Cryville.Common.Logging.Logger.AddListener(Cryville.Common.Logging.LoggerListener)">
<summary>
Attaches a listener to the logger.
</summary>
<param name="listener">The logger listener.</param>
</member>
<member name="M:Cryville.Common.Logging.Logger.RemoveListener(Cryville.Common.Logging.LoggerListener)">
<summary>
Detaches a listener from the logger.
</summary>
<param name="listener">The logger listener.</param>
</member>
<member name="M:Cryville.Common.Logging.Logger.Log(System.Int32,System.String,System.String,System.Object[])">
<summary>
Logs to the logger.
</summary>
<param name="level">The severity level.</param>
<param name="category">The category.</param>
<param name="format">The format string.</param>
<param name="args">The arguments for formatting.</param>
</member>
<member name="M:Cryville.Common.Logging.Logger.Log(System.Int32,System.String,System.IFormatProvider,System.String,System.Object[])">
<summary>
Logs to the logger.
</summary>
<param name="level">The severity level.</param>
<param name="category">The category.</param>
<param name="provider">The format provider.</param>
<param name="format">The format string.</param>
<param name="args">The arguments for formatting.</param>
</member>
<member name="M:Cryville.Common.Logging.Logger.Log(System.Int32,System.String,System.String)">
<summary>
Logs to the logger.
</summary>
<param name="level">The severity level.</param>
<param name="category">The category.</param>
<param name="message">The message.</param>
</member>
<member name="M:Cryville.Common.Logging.Logger.Log(System.Int32,System.String,System.Char[])">
<summary>
Logs to the logger.
</summary>
<param name="level">The severity level.</param>
<param name="category">The category.</param>
<param name="message">An array of <see cref="T:System.Char" /> containing the message.</param>
</member>
<member name="M:Cryville.Common.Logging.Logger.Log(System.Int32,System.String,System.Char[],System.Int32,System.Int32)">
<summary>
Logs to the logger.
</summary>
<param name="level">The severity level.</param>
<param name="category">The category.</param>
<param name="message">An array of <see cref="T:System.Char" /> containing the message.</param>
<param name="index">A zero-based index of the first character of the message within <paramref name="message" />.</param>
<param name="length">The length of the message.</param>
</member>
<member name="M:Cryville.Common.Logging.Logger.Log(System.Int32,System.String,System.Char*,System.Int32)">
<summary>
Logs to the logger.
</summary>
<param name="level">The severity level.</param>
<param name="category">The category.</param>
<param name="message">A pointer to the first character of the message.</param>
<param name="length">The length of the message.</param>
</member>
<member name="T:Cryville.Common.Logging.LoggerListener">
<summary>
A logger listener.
</summary>
</member>
<member name="M:Cryville.Common.Logging.LoggerListener.Dispose(System.Boolean)">
<summary>
Closes the logger listener and cleans up all the resources.
</summary>
<param name="disposing">Whether to clean up managed resources.</param>
</member>
<member name="M:Cryville.Common.Logging.LoggerListener.Dispose">
<summary>
Closes the logger listener.
</summary>
</member>
<member name="M:Cryville.Common.Logging.LoggerListener.OnLog(System.Int32,System.String,System.String)">
<summary>
Handles an incoming log.
</summary>
<param name="level">The severity level.</param>
<param name="category">The category.</param>
<param name="message">The message.</param>
</member>
<member name="M:Cryville.Common.Logging.LoggerListener.OnLog(System.Int32,System.String,System.Char[],System.Int32,System.Int32)">
<summary>
Handles an incoming log.
</summary>
<param name="level">The severity level.</param>
<param name="category">The category.</param>
<param name="message">An array of <see cref="T:System.Char" /> containing the message.</param>
<param name="index">A zero-based index of the first character of the message within <paramref name="message" />.</param>
<param name="length">The length of the message.</param>
</member>
<member name="M:Cryville.Common.Logging.LoggerListener.OnLog(System.Int32,System.String,System.Char*,System.Int32)">
<summary>
Handles an incoming log.
</summary>
<param name="level">The severity level.</param>
<param name="category">The category.</param>
<param name="message">A pointer to the first character of the message.</param>
<param name="length">The length of the message.</param>
</member>
<member name="T:Cryville.Common.Logging.InstantLoggerListener">
<summary>
A <see cref="T:Cryville.Common.Logging.LoggerListener" /> that calls a callback function on log.
</summary>
</member>
<member name="E:Cryville.Common.Logging.InstantLoggerListener.Log">
<summary>
Occurs when a log is logged to the logger.
</summary>
</member>
<member name="M:Cryville.Common.Logging.InstantLoggerListener.OnLog(System.Int32,System.String,System.String)">
<inheritdoc />
</member>
<member name="T:Cryville.Common.Logging.BufferedLoggerListener">
<summary>
A <see cref="T:Cryville.Common.Logging.LoggerListener" /> that buffers the logs for enumeration.
</summary>
</member>
<member name="M:Cryville.Common.Logging.BufferedLoggerListener.OnLog(System.Int32,System.String,System.String)">
<inheritdoc />
</member>
<member name="M:Cryville.Common.Logging.BufferedLoggerListener.Enumerate(Cryville.Common.Logging.LogHandler)">
<summary>
Enumerates the buffered logs.
</summary>
<param name="callback">The callback function to receive the logs.</param>
</member>
<member name="T:Cryville.Common.Logging.StreamLoggerListener">
<summary>
A <see cref="T:Cryville.Common.Logging.LoggerListener" /> that writes logs into a stream.
</summary>
<param name="stream">The stream.</param>
<param name="encoding">The encoding.</param>
</member>
<member name="M:Cryville.Common.Logging.StreamLoggerListener.#ctor(System.IO.Stream,System.Text.Encoding)">
<summary>
A <see cref="T:Cryville.Common.Logging.LoggerListener" /> that writes logs into a stream.
</summary>
<param name="stream">The stream.</param>
<param name="encoding">The encoding.</param>
</member>
<member name="M:Cryville.Common.Logging.StreamLoggerListener.#ctor(System.IO.Stream)">
<summary>
Creates an instance of the <see cref="T:Cryville.Common.Logging.StreamLoggerListener" /> class.
</summary>
<param name="stream">The stream.</param>
</member>
<member name="P:Cryville.Common.Logging.StreamLoggerListener.AutoFlush">
<summary>
Whether to flush the stream every time a log is written.
</summary>
</member>
<member name="M:Cryville.Common.Logging.StreamLoggerListener.OnLog(System.Int32,System.String,System.String)">
<inheritdoc />
</member>
<member name="T:Cryville.Common.Logging.LogHandler">
<summary>
Represents the method that will handle a log.
</summary>
<param name="level">The severity level.</param>
<param name="category">The category.</param>
<param name="message">The message.</param>
</member>
</members>
</doc>

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 72ded0675457e0348809193a9c1092b5
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

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