using Cryville.EEW.Colors; using Cryville.EEW.Core; using Cryville.EEW.Core.Colors; using Cryville.EEW.FERegion; using Cryville.EEW.Map; using Cryville.EEW.Report; using Cryville.EEW.TTS; using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Text.Json; using UnityEngine; using Color = System.Drawing.Color; namespace Cryville.EEW.Unity { sealed class SharedSettings : IRVMGeneratorContext, IMapGeneratorContext, ITTSMessageGeneratorContext { static SharedSettings s_instance; public static SharedSettings Instance => s_instance ??= new(); public ISeverityScheme SeverityScheme { get; private set; } = DefaultSeverityScheme.Instance; public ISeverityColorMapping SeverityColorMapping { get; private set; } = DefaultSeverityColorMapping.Instance; public bool UseContinuousColor { get; private set; } = true; 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 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 TTSCultures { get; private set; } public bool DoIgnoreLanguageVariant { get; private set; } public TimeZoneInfo OverrideTimeZone { get; private set; } public bool DoDisplayTimeZone { get; private set; } = true; public bool DoSwitchBackToHistory { get; private set; } = true; public IReadOnlyCollection EventSources { get; private set; } public string Id { get; private set; } public byte[] IdBytes { get; } = new byte[32]; public string UnityUserAgent { get; private set; } public void Init() { Id = SystemInfo.deviceUniqueIdentifier; using var hash = SHA256.Create(); hash.ComputeHash(EEW.SharedSettings.Encoding.GetBytes(Id)).CopyTo(IdBytes, 0); #if UNITY_STANDALONE_WIN UnityUserAgent = string.Format( CultureInfo.InvariantCulture, "{0} CysTerraUnity/{1} (Windows NT {2}; {3})", EEW.SharedSettings.UserAgent, Application.version, Environment.OSVersion.Version, RuntimeInformation.OSArchitecture.ToString().ToLowerInvariant() ); #else #error No Unity User Agent #endif var file = new FileInfo(Path.Combine(PlatformConfig.ConfigPath, "config.json")); if (!file.Exists) { using var stream1 = file.OpenWrite(); using var writer = new StreamWriter(stream1, EEW.SharedSettings.Encoding); writer.Write(JsonSerializer.Serialize(Config.Default, ConfigSerializationContext.Default.Config)); } using var stream = file.OpenRead(); var config = JsonSerializer.Deserialize(stream, ConfigSerializationContext.Default.Config) ?? throw new InvalidOperationException("Null config."); SeverityScheme = config.SeverityScheme switch { "Default" => new DefaultSeverityScheme(), "Legacy" => new LegacySeverityScheme(), _ => throw new InvalidOperationException("Unknown severity scheme."), }; SeverityColorMapping = config.ColorScheme switch { "Default" => new DefaultSeverityColorMapping(config.SeverityColorMappingLuminanceMultiplier), "SREV" => new SREVSeverityColorMapping(config.SeverityColorMappingLuminanceMultiplier), "DichromaticYB" => new DichromaticSeverityColorMapping(0.62f, 0.20f, 90, config.SeverityColorMappingLuminanceMultiplier), "DichromaticRC" => new DichromaticSeverityColorMapping(0.62f, 0.25f, 30, config.SeverityColorMappingLuminanceMultiplier), "DichromaticPG" => new DichromaticSeverityColorMapping(0.62f, 0.30f, -30, config.SeverityColorMappingLuminanceMultiplier), "Monochromatic" => new MonochromaticSeverityColorMapping(config.SeverityColorMappingLuminanceMultiplier), _ => throw new InvalidOperationException("Unknown color scheme."), }; UseContinuousColor = config.UseContinuousColor; ColorScheme = config.ColorScheme switch { "Default" => new SeverityBasedColorScheme(SeverityScheme, DefaultSeverityColorMapping.Instance), "SREV" => new SREVColorScheme(), "DichromaticYB" => new SeverityBasedColorScheme(SeverityScheme, new DichromaticSeverityColorMapping(0.62f, 0.20f, 90)), "DichromaticRC" => new SeverityBasedColorScheme(SeverityScheme, new DichromaticSeverityColorMapping(0.62f, 0.25f, 30)), "DichromaticPG" => new SeverityBasedColorScheme(SeverityScheme, new DichromaticSeverityColorMapping(0.62f, 0.30f, -30)), "Monochromatic" => new SeverityBasedColorScheme(SeverityScheme, new MonochromaticSeverityColorMapping()), _ => throw new InvalidOperationException("Unknown color scheme."), }; BorderColorScheme = config.ColorScheme switch { "Default" => new WrappedColorScheme(new SeverityBasedColorScheme(SeverityScheme, DefaultSeverityColorMapping.SecondaryInstance)), "SREV" => new WrappedColorScheme(new SREVBorderColorScheme()), "DichromaticYB" => new WrappedColorScheme(new SeverityBasedColorScheme(SeverityScheme, new DichromaticSeverityColorMapping(0.62f, 0.20f, 90, 0.75f))), "DichromaticRC" => new WrappedColorScheme(new SeverityBasedColorScheme(SeverityScheme, new DichromaticSeverityColorMapping(0.62f, 0.25f, 30, 0.75f))), "DichromaticPG" => new WrappedColorScheme(new SeverityBasedColorScheme(SeverityScheme, new DichromaticSeverityColorMapping(0.62f, 0.30f, -30, 0.75f))), "Monochromatic" => new WrappedColorScheme(new SeverityBasedColorScheme(SeverityScheme, new MonochromaticSeverityColorMapping(0.75f))), _ => throw new InvalidOperationException("Unknown color scheme."), }; TextColorScheme = config.ColorScheme switch { "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 { new(CultureInfo.InvariantCulture) }; DoIgnoreLanguageVariant = config.DoIgnoreLanguageVariant; EventSources = config.EventSources; } TimeZoneInfo ParseTimeZone(string timeZone) { if (timeZone == null) return null; if (timeZone == "") return TimeZoneInfo.Local; return TimeZoneInfo.CreateCustomTimeZone("Custom", TimeSpan.Parse(timeZone, CultureInfo.InvariantCulture), null, null); } } }