From 28c4bec67e4452c615b814bdc0be2ac5d2022595 Mon Sep 17 00:00:00 2001 From: David Galehouse Date: Wed, 24 Jul 2019 00:07:05 -0400 Subject: [PATCH] Fixed character info and auto-configure problems when playing on Rubi-Ka 2019 This closes #3 and closes #4 --- AODamageMeter.UI/AODamageMeter.UI.csproj | 1 + AODamageMeter.UI/App.config | 12 +++++ AODamageMeter.UI/App.xaml | 1 + .../Converters/DimensionNameConverter.cs | 16 ++++++ AODamageMeter.UI/Properties/AssemblyInfo.cs | 4 +- .../Properties/Settings.Designer.cs | 39 ++++++++++++++- AODamageMeter.UI/Properties/Settings.settings | 10 ++++ .../ViewModels/CharacterInfoViewModel.cs | 22 +++++++- .../ViewModels/CharacterSelectionViewModel.cs | 14 +++++- .../ViewModels/DamageMeterViewModel.cs | 15 ++++-- AODamageMeter.UI/Views/CharacterInfoView.xaml | 6 +++ .../Views/CharacterSelectionView.xaml | 2 + .../Views/DamageMeterView.xaml.cs | 2 +- AODamageMeter/AODamageMeter.csproj | 6 +-- AODamageMeter/Character.cs | 23 +++++---- AODamageMeter/DamageMeter.cs | 7 ++- AODamageMeter/Enums/Dimension.cs | 50 +++++++++++++++++++ AODamageMeter/Fight.cs | 4 +- README.md | 5 +- 19 files changed, 209 insertions(+), 30 deletions(-) create mode 100644 AODamageMeter.UI/Converters/DimensionNameConverter.cs create mode 100644 AODamageMeter/Enums/Dimension.cs diff --git a/AODamageMeter.UI/AODamageMeter.UI.csproj b/AODamageMeter.UI/AODamageMeter.UI.csproj index 03fc1ec..341021f 100644 --- a/AODamageMeter.UI/AODamageMeter.UI.csproj +++ b/AODamageMeter.UI/AODamageMeter.UI.csproj @@ -90,6 +90,7 @@ + diff --git a/AODamageMeter.UI/App.config b/AODamageMeter.UI/App.config index 973fa99..d3ccd76 100644 --- a/AODamageMeter.UI/App.config +++ b/AODamageMeter.UI/App.config @@ -118,6 +118,18 @@ True + + + + + + + RubiKa + + + 100 + diff --git a/AODamageMeter.UI/App.xaml b/AODamageMeter.UI/App.xaml index d0b8c58..b6f81c7 100644 --- a/AODamageMeter.UI/App.xaml +++ b/AODamageMeter.UI/App.xaml @@ -16,6 +16,7 @@ + #73CBD3 diff --git a/AODamageMeter.UI/Converters/DimensionNameConverter.cs b/AODamageMeter.UI/Converters/DimensionNameConverter.cs new file mode 100644 index 0000000..49430ee --- /dev/null +++ b/AODamageMeter.UI/Converters/DimensionNameConverter.cs @@ -0,0 +1,16 @@ +using System; +using System.Globalization; +using System.Windows.Data; + +namespace AODamageMeter.UI.Converters +{ + [ValueConversion(typeof(Dimension), typeof(string))] + public class DimensionNameConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + => ((Dimension)value).GetName(); + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + => DimensionHelpers.GetDimensionOrDefault((string)value); + } +} diff --git a/AODamageMeter.UI/Properties/AssemblyInfo.cs b/AODamageMeter.UI/Properties/AssemblyInfo.cs index a4a15a7..5f6e53e 100644 --- a/AODamageMeter.UI/Properties/AssemblyInfo.cs +++ b/AODamageMeter.UI/Properties/AssemblyInfo.cs @@ -15,5 +15,5 @@ [assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)] -[assembly: AssemblyVersion("1.4.0.0")] -[assembly: AssemblyFileVersion("1.4.0.0")] +[assembly: AssemblyVersion("1.4.1.0")] +[assembly: AssemblyFileVersion("1.4.1.0")] diff --git a/AODamageMeter.UI/Properties/Settings.Designer.cs b/AODamageMeter.UI/Properties/Settings.Designer.cs index 12ba9b6..3b1948b 100644 --- a/AODamageMeter.UI/Properties/Settings.Designer.cs +++ b/AODamageMeter.UI/Properties/Settings.Designer.cs @@ -12,7 +12,7 @@ namespace AODamageMeter.UI.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.1.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.9.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); @@ -421,5 +421,42 @@ public bool UpgradeRequired { this["UpgradeRequired"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("\r\n")] + public global::System.Collections.Specialized.StringCollection Dimensions { + get { + return ((global::System.Collections.Specialized.StringCollection)(this["Dimensions"])); + } + set { + this["Dimensions"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("RubiKa")] + public global::AODamageMeter.Dimension SelectedDimension { + get { + return ((global::AODamageMeter.Dimension)(this["SelectedDimension"])); + } + set { + this["SelectedDimension"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("100")] + public double DimensionColumnWidth { + get { + return ((double)(this["DimensionColumnWidth"])); + } + set { + this["DimensionColumnWidth"] = value; + } + } } } diff --git a/AODamageMeter.UI/Properties/Settings.settings b/AODamageMeter.UI/Properties/Settings.settings index 5d1ae10..852aa89 100644 --- a/AODamageMeter.UI/Properties/Settings.settings +++ b/AODamageMeter.UI/Properties/Settings.settings @@ -104,5 +104,15 @@ True + + <?xml version="1.0" encoding="utf-16"?> +<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" /> + + + RubiKa + + + 100 + \ No newline at end of file diff --git a/AODamageMeter.UI/ViewModels/CharacterInfoViewModel.cs b/AODamageMeter.UI/ViewModels/CharacterInfoViewModel.cs index cdbdf89..7f56175 100644 --- a/AODamageMeter.UI/ViewModels/CharacterInfoViewModel.cs +++ b/AODamageMeter.UI/ViewModels/CharacterInfoViewModel.cs @@ -15,10 +15,11 @@ public sealed class CharacterInfoViewModel : ViewModelBase private CharacterSelectionViewModel _characterSelectionViewModel; public CharacterInfoViewModel(CharacterSelectionViewModel characterSelectionViewModel, - string characterName = null, string logFilePath = null) + string characterName = null, Dimension dimension = Dimension.RubiKa, string logFilePath = null) { _characterSelectionViewModel = characterSelectionViewModel; CharacterName = characterName; + Dimension = dimension; LogFilePath = logFilePath; AutoConfigureCommand = new RelayCommand(ExecuteAutoConfigureCommand); } @@ -37,6 +38,23 @@ public string CharacterName } } + public static IReadOnlyList Dimensions { get; } = DimensionHelpers.AllDimensions + .Select(d => d.GetName()) + .ToArray(); + + private Dimension _dimension; + public Dimension Dimension + { + get => _dimension; + set + { + if (Set(ref _dimension, value)) + { + AutoConfigureResult = null; + } + } + } + private string _logFilePath; public string LogFilePath { @@ -120,7 +138,7 @@ private void ExecuteAutoConfigureCommand() return; } - var characterAndBioRetriever = Character.GetOrCreateCharacterAndBioRetriever(CharacterName); + var characterAndBioRetriever = Character.GetOrCreateCharacterAndBioRetriever(CharacterName, Dimension); var character = characterAndBioRetriever.character; characterAndBioRetriever.bioRetriever.Wait(); // Not worth using await and binding IsEnableds. if (!character.HasPlayerInfo) diff --git a/AODamageMeter.UI/ViewModels/CharacterSelectionViewModel.cs b/AODamageMeter.UI/ViewModels/CharacterSelectionViewModel.cs index 6e8614f..0d9a7ef 100644 --- a/AODamageMeter.UI/ViewModels/CharacterSelectionViewModel.cs +++ b/AODamageMeter.UI/ViewModels/CharacterSelectionViewModel.cs @@ -79,25 +79,35 @@ private void TryClearFile() private void Load() { var characterNames = Settings.Default.CharacterNames.Cast().ToArray(); + var dimensions = Settings.Default.Dimensions.Cast().ToArray(); var logFilePaths = Settings.Default.LogFilePaths.Cast().ToArray(); for (int i = 0; i < characterNames.Length; ++i) { - CharacterInfoViewModels.Add(new CharacterInfoViewModel(this, characterNames[i], logFilePaths[i])); + CharacterInfoViewModels.Add(new CharacterInfoViewModel(this, + characterNames[i], + DimensionHelpers.GetDimensionOrDefault(dimensions.ElementAtOrDefault(i)), + logFilePaths[i])); } string selectedCharacterName = Settings.Default.SelectedCharacterName; + Dimension selectedDimension = Settings.Default.SelectedDimension; string selectedLogFilePath = Settings.Default.SelectedLogFilePath; SelectedCharacterInfoViewModel = CharacterInfoViewModels - .FirstOrDefault(c => c.CharacterName == selectedCharacterName && c.LogFilePath == selectedLogFilePath); + .FirstOrDefault(c => c.CharacterName == selectedCharacterName + && c.Dimension == selectedDimension + && c.LogFilePath == selectedLogFilePath); } public void Save() { Settings.Default.CharacterNames.Clear(); Settings.Default.CharacterNames.AddRange(CharacterInfoViewModels.Select(c => c.CharacterName).ToArray()); + Settings.Default.Dimensions.Clear(); + Settings.Default.Dimensions.AddRange(CharacterInfoViewModels.Select(c => DimensionHelpers.GetName(c.Dimension)).ToArray()); Settings.Default.LogFilePaths.Clear(); Settings.Default.LogFilePaths.AddRange(CharacterInfoViewModels.Select(c => c.LogFilePath).ToArray()); Settings.Default.SelectedCharacterName = SelectedCharacterInfoViewModel?.CharacterName; + Settings.Default.SelectedDimension = SelectedCharacterInfoViewModel?.Dimension ?? Dimension.RubiKa; Settings.Default.SelectedLogFilePath = SelectedCharacterInfoViewModel?.LogFilePath; Settings.Default.Save(); } diff --git a/AODamageMeter.UI/ViewModels/DamageMeterViewModel.cs b/AODamageMeter.UI/ViewModels/DamageMeterViewModel.cs index 3d9818d..bf5697b 100644 --- a/AODamageMeter.UI/ViewModels/DamageMeterViewModel.cs +++ b/AODamageMeter.UI/ViewModels/DamageMeterViewModel.cs @@ -15,6 +15,7 @@ public sealed class DamageMeterViewModel : ViewModelBase { private readonly IProgress _rowUpdater; private string _characterName; + private Dimension _dimension; private string _logFilePath; private CancellationTokenSource _damageMeterUpdaterCTS; private Task _damageMeterUpdater; @@ -29,7 +30,10 @@ public DamageMeterViewModel() ToggleIsPausedCommand = new RelayCommand(ExecuteToggleIsPausedCommand); ResetAndSaveFightCommand = new RelayCommand(ExecuteResetAndSaveFightCommand); ResetFightCommand = new RelayCommand(ExecuteResetFightCommand); - TryInitializeDamageMeter(Settings.Default.SelectedCharacterName, Settings.Default.SelectedLogFilePath); + TryInitializeDamageMeter( + Settings.Default.SelectedCharacterName, + Settings.Default.SelectedDimension, + Settings.Default.SelectedLogFilePath); // Performance optimization: don't let performance degrade as the # of fights in the fight history increase. // Would be more complicated to extend this to views within a historical fight, but possible. But don't need // to do it there because it's less expensive than the unavoidable cost of updating the current fight. @@ -78,12 +82,14 @@ public ObservableCollection DisplayedRows private set => Set(ref _displayedRows, value); } - public bool TryInitializeDamageMeter(string characterName, string logFilePath) + public bool TryInitializeDamageMeter(string characterName, Dimension dimension, string logFilePath) { if (string.IsNullOrWhiteSpace(characterName) || string.IsNullOrWhiteSpace(logFilePath)) return false; - if (characterName == _characterName && logFilePath == _logFilePath) + if (characterName == _characterName + && dimension == _dimension + && logFilePath == _logFilePath) return true; if (!File.Exists(logFilePath)) @@ -95,8 +101,9 @@ public bool TryInitializeDamageMeter(string characterName, string logFilePath) DisposeDamageMeter(); _characterName = characterName; + _dimension = dimension; _logFilePath = logFilePath; - DamageMeter = new DamageMeter(characterName, logFilePath) + DamageMeter = new DamageMeter(characterName, dimension, logFilePath) { IsPaused = IsPaused, PetRegistrations = PetRegistrationRepository.PetRegistrations diff --git a/AODamageMeter.UI/Views/CharacterInfoView.xaml b/AODamageMeter.UI/Views/CharacterInfoView.xaml index 0a69939..698fdec 100644 --- a/AODamageMeter.UI/Views/CharacterInfoView.xaml +++ b/AODamageMeter.UI/Views/CharacterInfoView.xaml @@ -48,6 +48,12 @@ + + + + diff --git a/AODamageMeter.UI/Views/CharacterSelectionView.xaml b/AODamageMeter.UI/Views/CharacterSelectionView.xaml index 1d28802..e486397 100644 --- a/AODamageMeter.UI/Views/CharacterSelectionView.xaml +++ b/AODamageMeter.UI/Views/CharacterSelectionView.xaml @@ -51,6 +51,8 @@ + net462 - 1.4.0.0 - 1.4.0.0 - 1.4.0 + 1.4.1.0 + 1.4.1.0 + 1.4.1 diff --git a/AODamageMeter/Character.cs b/AODamageMeter/Character.cs index 5559250..465d61b 100644 --- a/AODamageMeter/Character.cs +++ b/AODamageMeter/Character.cs @@ -15,15 +15,18 @@ public class Character protected static readonly Dictionary _characterBioRetrievers = new Dictionary(); protected readonly object _lock = new object(); // Just using a single object for convenience; see comments/links below. - protected Character(string name) + protected Character(string name, Dimension dimension) { Name = name; UncoloredName = UncolorName(name); + Dimension = dimension; } public string Name { get; } public string UncoloredName { get; } + public Dimension Dimension { get; } + protected bool _isPlayer; public bool IsPlayer { @@ -117,14 +120,15 @@ public bool HasOrganizationInfo // in of the bio, after the HTTP request comes in, that can happen in parallel. When it does happen in parallel we // have to worry about locking and volatility and so on, which is why we use locks above. See: // http://stackoverflow.com/q/33528408, http://stackoverflow.com/q/434890, http://jonskeet.uk/csharp/threads/volatility.shtml. - public static Character GetOrCreateCharacter(string name) => GetOrCreateCharacterAndBioRetriever(name).character; - public static (Character character, Task bioRetriever) GetOrCreateCharacterAndBioRetriever(string name) + public static Character GetOrCreateCharacter(string name, Dimension dimension) + => GetOrCreateCharacterAndBioRetriever(name, dimension).character; + public static (Character character, Task bioRetriever) GetOrCreateCharacterAndBioRetriever(string name, Dimension dimension) { - if (_characters.TryGetValue(name, out Character character)) + if (_characters.TryGetValue($"{name} ({dimension.GetName()})", out Character character)) return (character, _characterBioRetrievers[character]); - character = new Character(name); - _characters.Add(name, character); + character = new Character(name, dimension); + _characters.Add($"{name} ({dimension.GetName()})", character); Task characterBioRetriever = RetrieveCharacterBio(character); _characterBioRetrievers.Add(character, characterBioRetriever); @@ -148,7 +152,8 @@ protected static async Task RetrieveCharacterBio(Character character) character.IsPlayer = !IsAmbiguousPlayerName(character.Name); var response = await _httpClient - .GetAsync($"http://people.anarchy-online.com/character/bio/d/5/name/{character.Name}/bio.xml?data_type=json").ConfigureAwait(false); + .GetAsync($"http://people.anarchy-online.com/character/bio/d/{character.Dimension.GetDimensionID()}/name/{character.Name}/bio.xml?data_type=json") + .ConfigureAwait(false); if (response.IsSuccessStatusCode) { var characterBio = await response.Content.ReadAsAsync().ConfigureAwait(false); @@ -170,8 +175,8 @@ protected static async Task RetrieveCharacterBio(Character character) } } - public static bool TryGetCharacter(string name, out Character character) - => _characters.TryGetValue(name, out character); + public static bool TryGetCharacter(string name, Dimension dimension, out Character character) + => _characters.TryGetValue($"{name} ({dimension.GetName()})", out character); private static bool IsUppercase(char c) => c >= 'A' && c <= 'Z'; private static bool IsLowercaseOrDigit(char c) => c >= 'a' && c <= 'z' || c >= '0' && c <= '9'; diff --git a/AODamageMeter/DamageMeter.cs b/AODamageMeter/DamageMeter.cs index 69b37d2..e00ed45 100644 --- a/AODamageMeter/DamageMeter.cs +++ b/AODamageMeter/DamageMeter.cs @@ -8,15 +8,18 @@ public class DamageMeter : IDisposable { protected readonly StreamReader _logStreamReader; - public DamageMeter(string characterName, string logFilePath, DamageMeterMode mode = DamageMeterMode.RealTime) + public DamageMeter(string characterName, Dimension dimension, string logFilePath, + DamageMeterMode mode = DamageMeterMode.RealTime) { + Dimension = dimension; LogFilePath = logFilePath; _logStreamReader = new StreamReader(File.Open(LogFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)); Mode = mode; - Owner = Character.GetOrCreateCharacter(characterName); + Owner = Character.GetOrCreateCharacter(characterName, dimension); Owner.IsPlayer = true; } + public Dimension Dimension { get; } public string LogFilePath { get; } public DamageMeterMode Mode { get; } public bool IsRealTimeMode => Mode == DamageMeterMode.RealTime; diff --git a/AODamageMeter/Enums/Dimension.cs b/AODamageMeter/Enums/Dimension.cs new file mode 100644 index 0000000..c7b266b --- /dev/null +++ b/AODamageMeter/Enums/Dimension.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace AODamageMeter +{ + public enum Dimension + { + RubiKa, + RubiKa2019 + } + + public static class DimensionHelpers + { + public static Dimension GetDimensionOrDefault(string value, Dimension @default = Dimension.RubiKa) + { + switch (value) + { + case "Rubi-Ka": return Dimension.RubiKa; + case "Rubi-Ka 2019": return Dimension.RubiKa2019; + default: return @default; + } + } + + public static string GetName(this Dimension dimension) + { + switch (dimension) + { + case Dimension.RubiKa: return "Rubi-Ka"; + case Dimension.RubiKa2019: return "Rubi-Ka 2019"; + default: throw new NotImplementedException(); + } + } + + public static int GetDimensionID(this Dimension dimension) + { + switch (dimension) + { + case Dimension.RubiKa: return 5; + case Dimension.RubiKa2019: return 6; + default: throw new NotImplementedException(); + } + } + + public static readonly IReadOnlyList AllDimensions = Enum.GetValues(typeof(Dimension)) + .Cast() + .OrderBy(d => d) + .ToArray(); + } +} diff --git a/AODamageMeter/Fight.cs b/AODamageMeter/Fight.cs index 0c7ac5f..2067eee 100644 --- a/AODamageMeter/Fight.cs +++ b/AODamageMeter/Fight.cs @@ -210,7 +210,7 @@ public bool TryDeregisterFightPet(FightCharacter fightPet) } public FightCharacter GetOrCreateFightCharacter(string name, DateTime enteredTime) - => GetOrCreateFightCharacter(Character.GetOrCreateCharacter(name), enteredTime); + => GetOrCreateFightCharacter(Character.GetOrCreateCharacter(name, DamageMeter.Dimension), enteredTime); public FightCharacter GetOrCreateFightCharacter(Character character, DateTime enteredTime) { @@ -232,7 +232,7 @@ public FightCharacter GetOrCreateFightCharacter(Character character, DateTime en public bool TryGetFightCharacter(string name, out FightCharacter fightCharacter) { - if (Character.TryGetCharacter(name, out Character character)) + if (Character.TryGetCharacter(name, DamageMeter.Dimension, out Character character)) return TryGetFightCharacter(character, out fightCharacter); fightCharacter = null; diff --git a/README.md b/README.md index f3c357a..e04c26d 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,11 @@ AO Damage Meter Real-time graphical damage meter for the sci-fi MMORPG Anarchy Online. -Latest release [here](https://github.com/nicgalehouse/AODamageMeter/releases/tag/v1.4.0) (built for W10, but it probably works on W7 too). +Latest release [here](https://github.com/nicgalehouse/AODamageMeter/releases/tag/v1.4.1) (built for W10, but it probably works on W7 too). Video demonstration [here](https://youtu.be/K4iU7KronOg). -Manual log window configuration process [here](https://www.youtube.com/watch?v=gdknGvEJjPs). There's an auto-configure option, but it's currently broken on the new Rubi-Ka 2019 server. +Manual log window configuration process [here](https://www.youtube.com/watch?v=gdknGvEJjPs), in case auto-configure doesn't work. Features -------- @@ -23,6 +23,7 @@ Features + Update 1.3: Separates regulars (normals, crits, glances) and specials in weapon damage %-breakdown to help evaluate the benefit of crit increase/decrease. + Update 1.3: Tracks nano interrupts (requires System channel). + Update 1.4: Tracks regular blockers from Keeper Ward nanos, improving accuracy of hit chance and hit attempt statistics (requires System channel). ++ Update 1.4.1: Fixed character info and auto-configure problems when playing on Rubi-Ka 2019. Instructions ------------