11 Commits

191 changed files with 4397 additions and 297 deletions

View File

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

View File

@@ -13,6 +13,8 @@ namespace Cryville.EEW.Unity {
bool DoDisplayTimeZone, bool DoDisplayTimeZone,
bool DoSwitchBackToHistory, bool DoSwitchBackToHistory,
string OverrideDisplayCulture,
IReadOnlyCollection<EventSourceConfig> EventSources IReadOnlyCollection<EventSourceConfig> EventSources
) { ) {
public static Config Default => new( public static Config Default => new(
@@ -25,6 +27,8 @@ namespace Cryville.EEW.Unity {
true, true,
true, true,
"",
new List<EventSourceConfig> { new List<EventSourceConfig> {
new JMAAtomEventSourceConfig(Array.Empty<string>()), new JMAAtomEventSourceConfig(Array.Empty<string>()),
new UpdateCheckerEventSourceConfig(), new UpdateCheckerEventSourceConfig(),
@@ -54,7 +58,7 @@ namespace Cryville.EEW.Unity {
record NOAAEventSourceConfig([property: JsonRequired] string Subtype) : EventSourceConfig; record NOAAEventSourceConfig([property: JsonRequired] string Subtype) : EventSourceConfig;
record UpdateCheckerEventSourceConfig : EventSourceConfig; record UpdateCheckerEventSourceConfig : EventSourceConfig;
record USGSQuakeMLEventSourceConfig([property: JsonRequired] string Subtype) : 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))] [JsonSerializable(typeof(Config))]
[JsonSourceGenerationOptions(WriteIndented = true)] [JsonSourceGenerationOptions(WriteIndented = true)]

View File

@@ -17,19 +17,24 @@ namespace Cryville.EEW.Unity.Map {
GameObject m_prefabTile; GameObject m_prefabTile;
[SerializeField] [SerializeField]
GameObject m_prefabBitmapHolder; GameObject m_prefabBitmapHolder;
[SerializeField]
int m_maxMapTileZoom = 10;
[SerializeField]
bool m_isEditor;
readonly MapTileCacheManager _tiles = new(); MapTileCacheManager _tiles;
float _elementLayerZ; float _elementLayerZ;
void Start() { void Start() {
_camera = GetComponent<Camera>(); _camera = GetComponent<Camera>();
_tiles = m_isEditor ? new EditorMapTileCacheManager() : new MapTileCacheManager();
_tiles.ExtraCachedZoomLevel = 20; _tiles.ExtraCachedZoomLevel = 20;
_tiles.Parent = m_layerTile; _tiles.Parent = m_layerTile;
_tiles.PrefabTile = m_prefabTile; _tiles.PrefabTile = m_prefabTile;
_tiles.PrefabBitmapHolder = m_prefabBitmapHolder; _tiles.PrefabBitmapHolder = m_prefabBitmapHolder;
_tiles.CacheDir = Application.temporaryCachePath; _tiles.CacheDir = Application.temporaryCachePath;
_camera.orthographicSize = 0.5f / MathF.Max(1, (float)_camera.pixelWidth / _camera.pixelHeight); _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; _mapElementUpdated = true;
} }
void OnDestroy() { void OnDestroy() {
@@ -74,7 +79,7 @@ namespace Cryville.EEW.Unity.Map {
} }
} }
void ZoomToMapElement() { void ZoomToMapElement() {
var aabb = m_layerElement.AABB; var aabb = m_layerElement != null ? m_layerElement.AABB : null;
if (aabb is not RectangleF b) return; if (aabb is not RectangleF b) return;
if (b.Width * _camera.pixelHeight < _camera.pixelWidth * b.Height) if (b.Width * _camera.pixelHeight < _camera.pixelWidth * b.Height)
Scale = b.Height; Scale = b.Height;
@@ -97,14 +102,17 @@ namespace Cryville.EEW.Unity.Map {
transform.localPosition = new(nx, Math.Clamp(transform.position.y, h / 2 - 1, -h / 2), -20); 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)); 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; int zoomScale = 1 << zoom;
_tiles.MoveTo( _tiles.MoveTo(
new(Mathf.FloorToInt(bounds.min.x * zoomScale), Mathf.FloorToInt(-bounds.max.y * zoomScale), zoom), 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) new(Mathf.CeilToInt(bounds.max.x * zoomScale), Mathf.CeilToInt(-bounds.min.y * zoomScale), zoom)
); );
if (m_layerElement != null) {
m_layerElement.Scale = h; m_layerElement.Scale = h;
}
if (m_layerElementSub != null) {
m_layerElementSub.Scale = h; m_layerElementSub.Scale = h;
if (nx - w / 2 < 0) { if (nx - w / 2 < 0) {
@@ -121,3 +129,4 @@ namespace Cryville.EEW.Unity.Map {
} }
} }
} }
}

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

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

View File

@@ -45,13 +45,13 @@ namespace Cryville.EEW.Unity.Map {
_isReady = false; _isReady = false;
} }
if (_req == null || !_req.isDone) return; if (_req == null || !_req.isDone) return;
if (_texHandler.isDone) { if (_texHandler.isDone && _texHandler.texture != null) {
_tex = _texHandler.texture; _tex = _texHandler.texture;
_tex.wrapMode = TextureWrapMode.Clamp; _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); _sprite = Sprite.Create(_tex, new Rect(0, 0, _tex.width, _tex.height), Vector2.zero, _tex.height, 0, SpriteMeshType.FullRect, Vector4.zero, false);
} }
else { else {
Debug.LogError(_req.error); Debug.LogError(_texHandler.error);
_localFile.Delete(); _localFile.Delete();
} }
_req.Dispose(); _req.Dispose();

View File

@@ -4,7 +4,7 @@ using System.IO;
using UnityEngine; using UnityEngine;
namespace Cryville.EEW.Unity.Map { namespace Cryville.EEW.Unity.Map {
sealed class MapTileCacheManager : MapTileCacheManager<MapTileBitmapHolder> { class MapTileCacheManager : MapTileCacheManager<MapTileBitmapHolder> {
public GameObject PrefabTile { get; set; } public GameObject PrefabTile { get; set; }
public GameObject PrefabBitmapHolder { get; set; } public GameObject PrefabBitmapHolder { get; set; }
@@ -12,7 +12,11 @@ namespace Cryville.EEW.Unity.Map {
public string CacheDir { get; set; } 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}"); protected override string GetCacheFilePath(MapTileIndex index) => Path.Combine(CacheDir, $"map/{index.Z}/{index.NX}/{index.NY}");

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.Colors;
using Cryville.EEW.Core;
using Cryville.EEW.Core.Colors; using Cryville.EEW.Core.Colors;
using Cryville.EEW.FERegion; using Cryville.EEW.FERegion;
using Cryville.EEW.Map; using Cryville.EEW.Map;
@@ -25,9 +26,21 @@ namespace Cryville.EEW.Unity {
public IColorScheme ColorScheme { get; private set; } = new SeverityBasedColorScheme(DefaultSeverityScheme.Instance, DefaultSeverityColorMapping.Instance); 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 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 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 => TimeSpan.FromMinutes(60); // TODO TTS
public CultureInfo RVMCulture { get; private set; } = SharedCultures.CurrentUICulture;
readonly int _infoLocationSpecificity = 3;
readonly int _ttsLocationSpecificity = 3;
readonly LocationNamer _locationNamer = new() { Namer = new FERegionLongNamer() }; // TODO TTS
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 TimeZoneInfo OverrideTimeZone { get; private set; } public TimeZoneInfo OverrideTimeZone { get; private set; }
public bool DoDisplayTimeZone { get; private set; } = true; public bool DoDisplayTimeZone { get; private set; } = true;
public bool DoSwitchBackToHistory { get; private set; } = true; public bool DoSwitchBackToHistory { get; private set; } = true;
@@ -104,6 +117,9 @@ namespace Cryville.EEW.Unity {
OverrideTimeZone = ParseTimeZone(config.OverrideTimeZone); OverrideTimeZone = ParseTimeZone(config.OverrideTimeZone);
DoDisplayTimeZone = config.DoDisplayTimeZone; DoDisplayTimeZone = config.DoDisplayTimeZone;
DoSwitchBackToHistory = config.DoSwitchBackToHistory; DoSwitchBackToHistory = config.DoSwitchBackToHistory;
RVMCulture = config.OverrideDisplayCulture is string rvmCulture
? (string.IsNullOrEmpty(rvmCulture) ? SharedCultures.CurrentUICulture : SharedCultures.Get(rvmCulture))
: CultureInfo.InvariantCulture;
EventSources = config.EventSources; EventSources = config.EventSources;
} }

View File

@@ -5,7 +5,7 @@ using System.IO;
using UnityEngine; using UnityEngine;
namespace Cryville.EEW.Unity { namespace Cryville.EEW.Unity {
class SoundPlayer : Core.SoundPlayer { class SoundPlayer : Core.Audio.SoundPlayer {
public SoundPlayer() : base(GetEngineList(), AudioUsage.NotificationEvent) { } public SoundPlayer() : base(GetEngineList(), AudioUsage.NotificationEvent) { }
static List<Type> GetEngineList() => new() { static List<Type> GetEngineList() => new() {
typeof(Audio.Wasapi.MMDeviceEnumeratorWrapper), typeof(Audio.Wasapi.MMDeviceEnumeratorWrapper),

View File

@@ -4,7 +4,7 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Cryville.EEW.Unity { namespace Cryville.EEW.Unity {
class TTSWorker : Core.TTSWorker { class TTSWorker : Core.Audio.TTSWorker {
public TTSWorker() : base(CreateSoundPlayer()) { } public TTSWorker() : base(CreateSoundPlayer()) { }
static SoundPlayer CreateSoundPlayer() { static SoundPlayer CreateSoundPlayer() {

View File

@@ -23,6 +23,7 @@ namespace Cryville.EEW.Unity.UI {
child.SetViewModel(e); child.SetViewModel(e);
child.transform.SetParent(m_listView, false); child.transform.SetParent(m_listView, false);
_displayingViews.Add(child); _displayingViews.Add(child);
OnDisplayingViewsChanged();
SwitchTo(_displayingReports.Count - 1); SwitchTo(_displayingReports.Count - 1);
@@ -37,6 +38,7 @@ namespace Cryville.EEW.Unity.UI {
child.SetParent(null, false); child.SetParent(null, false);
Destroy(child.gameObject); Destroy(child.gameObject);
_displayingViews.RemoveAt(index); _displayingViews.RemoveAt(index);
OnDisplayingViewsChanged();
if (_displayingReports.Count == 0) { if (_displayingReports.Count == 0) {
m_currentView.gameObject.SetActive(false); m_currentView.gameObject.SetActive(false);
@@ -49,6 +51,14 @@ namespace Cryville.EEW.Unity.UI {
if (_displayingReports.Count <= 1) m_listView.gameObject.SetActive(false); 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() { void Awake() {
if (Instance != null) { if (Instance != null) {
@@ -63,6 +73,7 @@ namespace Cryville.EEW.Unity.UI {
int _index = -1; int _index = -1;
float _tickDown; float _tickDown;
float _maxBaseDuration;
void Update() { void Update() {
if (_displayingReports.Count == 0) return; if (_displayingReports.Count == 0) return;
_tickDown -= Time.deltaTime; _tickDown -= Time.deltaTime;
@@ -77,12 +88,15 @@ namespace Cryville.EEW.Unity.UI {
_index = index; _index = index;
var e = _displayingReports[index]; var e = _displayingReports[index];
m_currentView.SetViewModel(e, true); m_currentView.SetViewModel(e, true);
var keyProp = e.Properties.FirstOrDefault();
_displayingViews[_index].SetCurrent(true); _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); m_currentView.gameObject.SetActive(true);
Worker.Instance.SetCurrent(e); 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) { public void OnItemClicked(ReportViewModel viewModel) {
int index = _displayingReports.IndexOf(viewModel); int index = _displayingReports.IndexOf(viewModel);
if (index == -1) return; if (index == -1) return;

View File

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

View File

@@ -64,6 +64,7 @@ namespace Cryville.EEW.Unity {
BuildWorkers(); BuildWorkers();
_worker.RVMGeneratorContext = SharedSettings.Instance; _worker.RVMGeneratorContext = SharedSettings.Instance;
_worker.TTSMessageGeneratorContext = SharedSettings.Instance; _worker.TTSMessageGeneratorContext = SharedSettings.Instance;
_worker.RVMCulture = SharedSettings.Instance.RVMCulture;
_ongoingReportManager.Changed += OnOngoingReported; _ongoingReportManager.Changed += OnOngoingReported;
_worker.Reported += OnReported; _worker.Reported += OnReported;
_grouper.GroupUpdated += OnGroupUpdated; _grouper.GroupUpdated += OnGroupUpdated;
@@ -87,9 +88,10 @@ namespace Cryville.EEW.Unity {
_ongoingReportManager.Dispose(); _ongoingReportManager.Dispose();
} }
static void RegisterViewModelGenerators(CoreWorker worker) { CENCEarthquakeRVMGenerator _cencEarthquakeRVMGenerator;
void RegisterViewModelGenerators(CoreWorker worker) {
worker.RegisterViewModelGenerator(new BMKGEarthquakeRVMGenerator()); worker.RegisterViewModelGenerator(new BMKGEarthquakeRVMGenerator());
worker.RegisterViewModelGenerator(new CENCEarthquakeRVMGenerator()); worker.RegisterViewModelGenerator(_cencEarthquakeRVMGenerator = new CENCEarthquakeRVMGenerator());
worker.RegisterViewModelGenerator(new CENCEEWRVMGenerator()); worker.RegisterViewModelGenerator(new CENCEEWRVMGenerator());
worker.RegisterViewModelGenerator(new CWAEarthquakeRVMGenerator()); worker.RegisterViewModelGenerator(new CWAEarthquakeRVMGenerator());
worker.RegisterViewModelGenerator(new CWAEEWRVMGenerator()); worker.RegisterViewModelGenerator(new CWAEEWRVMGenerator());
@@ -104,9 +106,10 @@ namespace Cryville.EEW.Unity {
worker.RegisterViewModelGenerator(new SichuanEEWRVMGenerator()); worker.RegisterViewModelGenerator(new SichuanEEWRVMGenerator());
worker.RegisterViewModelGenerator(new VersionRVMGenerator()); worker.RegisterViewModelGenerator(new VersionRVMGenerator());
} }
static void RegisterTTSMessageGenerators(CoreWorker worker) { CENCEarthquakeTTSMessageGenerator _cencEarthquakeTTSMessageGenerator;
void RegisterTTSMessageGenerators(CoreWorker worker) {
worker.RegisterTTSMessageGenerator(new BMKGEarthquakeTTSMessageGenerator()); worker.RegisterTTSMessageGenerator(new BMKGEarthquakeTTSMessageGenerator());
worker.RegisterTTSMessageGenerator(new CENCEarthquakeTTSMessageGenerator()); worker.RegisterTTSMessageGenerator(_cencEarthquakeTTSMessageGenerator = new CENCEarthquakeTTSMessageGenerator());
worker.RegisterTTSMessageGenerator(new CENCEEWTTSMessageGenerator()); worker.RegisterTTSMessageGenerator(new CENCEEWTTSMessageGenerator());
worker.RegisterTTSMessageGenerator(new CWAEarthquakeTTSMessageGenerator()); worker.RegisterTTSMessageGenerator(new CWAEarthquakeTTSMessageGenerator());
worker.RegisterTTSMessageGenerator(new CWAEEWTTSMessageGenerator()); worker.RegisterTTSMessageGenerator(new CWAEEWTTSMessageGenerator());
@@ -129,7 +132,7 @@ namespace Cryville.EEW.Unity {
BMKGOpenDataWorker bmkgWorker = new(new Uri("http://localhost:9095/autogempa.json")); BMKGOpenDataWorker bmkgWorker = new(new Uri("http://localhost:9095/autogempa.json"));
bmkgWorker.SetDataUris(new Uri[] { new("http://localhost:9095/gempadirasakan.json") }); bmkgWorker.SetDataUris(new Uri[] { new("http://localhost:9095/gempadirasakan.json") });
_worker.AddWorker(bmkgWorker); _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")); _worker.AddWorker(new UpdateCheckerWorker(typeof(Worker).Assembly.GetName().Version?.ToString(3) ?? "", "unity"));
#else #else
foreach (var source in SharedSettings.Instance.EventSources) { foreach (var source in SharedSettings.Instance.EventSources) {
@@ -163,7 +166,7 @@ namespace Cryville.EEW.Unity {
worker.IsFilterWhitelist = config.IsFilterWhitelist; worker.IsFilterWhitelist = config.IsFilterWhitelist;
return worker; 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 { if (config.Filter != null) worker.SetFilter(config.Filter.Select(i => i switch {
"cenc_eew" => typeof(CENCEEW), "cenc_eew" => typeof(CENCEEW),
"cenc_eqlist" => typeof(WolfxEarthquakeList<CENCEarthquake>), "cenc_eqlist" => typeof(WolfxEarthquakeList<CENCEarthquake>),
@@ -174,6 +177,11 @@ namespace Cryville.EEW.Unity {
_ => throw new InvalidOperationException("Unknown Wolfx event type."), _ => throw new InvalidOperationException("Unknown Wolfx event type."),
})); }));
worker.IsFilterWhitelist = config.IsFilterWhitelist; worker.IsFilterWhitelist = config.IsFilterWhitelist;
_cencEarthquakeRVMGenerator.UseRawLocationName
= _cencEarthquakeTTSMessageGenerator.UseRawLocationName
= config.UseRawCENCLocationName;
return worker; return worker;
} }
static BMKGOpenDataWorker BuildBMKGOpenDataWorkerUris(BMKGOpenDataWorker worker, BMKGOpenDataEventSourceConfig config) { static BMKGOpenDataWorker BuildBMKGOpenDataWorkerUris(BMKGOpenDataWorker worker, BMKGOpenDataEventSourceConfig config) {

View File

@@ -0,0 +1,33 @@
fileFormatVersion: 2
guid: 550171b48a648b34e9ce5f1aba6244f1
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: 0f848a4ea2f35e7449e584beee48c659
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.

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