├── .dependabot └── config.yml.txt ├── .editorconfig ├── .gitignore ├── LICENSE.txt ├── README.md ├── SmartHunter.sln ├── SmartHunter ├── App.config ├── App.xaml ├── App.xaml.cs ├── Core │ ├── AddressRange.cs │ ├── BytePattern.cs │ ├── Command.cs │ ├── Config │ │ ├── ConfigContainer.cs │ │ ├── ContractResolver.cs │ │ ├── PreserveCollectionIntegrity.cs │ │ ├── StringFloatConverter.cs │ │ └── WidgetConfig.cs │ ├── Data │ │ ├── Bindable.cs │ │ ├── ContextualWidget.cs │ │ ├── Progress.cs │ │ ├── TimedVisibility.cs │ │ ├── Widget.cs │ │ └── WidgetContext.cs │ ├── FileContainer.cs │ ├── GenericEventArgs.cs │ ├── Helpers │ │ ├── MemoryHelper.cs │ │ ├── Updater.cs │ │ └── WindowHelper.cs │ ├── KeyboardInput.cs │ ├── KeyboardInputEventArgs.cs │ ├── Log.cs │ ├── MemoryUpdater.cs │ ├── Overlay.cs │ ├── PointerTrace.cs │ ├── PointerTraceLevel.cs │ ├── Setting.cs │ ├── StateMachine.cs │ ├── ThreadedMemoryScan.cs │ ├── Windows │ │ └── WidgetWindow.cs │ └── WindowsApi.cs ├── Game │ ├── Config │ │ ├── BytePatternConfig.cs │ │ ├── CrownPreset.cs │ │ ├── DebugConfig.cs │ │ ├── DebugWidgetConfig.cs │ │ ├── LocalizationConfig.cs │ │ ├── MainConfig.cs │ │ ├── MemoryConditionConfig.cs │ │ ├── MemoryConfig.cs │ │ ├── MemorySource.cs │ │ ├── MonsterConfig.cs │ │ ├── MonsterCrownConfig.cs │ │ ├── MonsterDataConfig.cs │ │ ├── MonsterPartConfig.cs │ │ ├── MonsterStatusEffectConfig.cs │ │ ├── MonsterWidgetConfig.cs │ │ ├── OverlayConfig.cs │ │ ├── PlayerDataConfig.cs │ │ ├── PlayerWidgetConfig.cs │ │ ├── StatusEffectConfig.cs │ │ └── TeamWidgetConfig.cs │ ├── Data │ │ ├── Game.cs │ │ ├── Monster.cs │ │ ├── MonsterCrown.cs │ │ ├── MonsterPart.cs │ │ ├── MonsterStatusEffect.cs │ │ ├── Player.cs │ │ ├── PlayerStatusEffect.cs │ │ ├── ViewModels │ │ │ ├── ConsoleViewModel.cs │ │ │ ├── OverlayViewModel.cs │ │ │ └── SettingsViewModel.cs │ │ ├── WeaponType.cs │ │ └── WidgetContexts │ │ │ ├── DebugWidgetContext.cs │ │ │ ├── MonsterWidgetContext.cs │ │ │ ├── PlayerWidgetContext.cs │ │ │ └── TeamWidgetContext.cs │ ├── Helpers │ │ ├── ConfigHelper.cs │ │ ├── LocalizationHelper.cs │ │ └── MhwHelper.cs │ ├── InputControl.cs │ ├── MhwMemoryUpdater.cs │ └── MhwOverlay.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── SmartHunter.csproj └── Ui │ ├── Converters │ ├── AngleToIsLargeArcConverter.cs │ ├── AngleToPointConverter.cs │ ├── BoolToVisibilityConverter.cs │ ├── ColorTransformConverter.cs │ ├── EnumComparisonConverter.cs │ ├── FractionToPercentageConverter.cs │ ├── LocalizerConverter.cs │ ├── NumberComparisonConverter.cs │ ├── NumberToCenteredMarginConverter.cs │ ├── PlayerToPlayerIndexConverter.cs │ ├── StringArrayContainsConverter.cs │ ├── StringFormatConverter.cs │ └── WeaponTypeToNameConverter.cs │ ├── Fonts │ ├── Roboto-Bold.ttf │ └── Roboto-Medium.ttf │ ├── Resources │ └── Default.xaml │ └── Windows │ ├── ConsoleWindow.xaml │ ├── ConsoleWindow.xaml.cs │ ├── DebugWidgetWindow.xaml │ ├── DebugWidgetWindow.xaml.cs │ ├── MonsterWidgetWindow.xaml │ ├── MonsterWidgetWindow.xaml.cs │ ├── PlayerWidgetWindow.xaml │ ├── PlayerWidgetWindow.xaml.cs │ ├── TeamWidgetWindow.xaml │ └── TeamWidgetWindow.xaml.cs ├── build ├── PackageRelease.ps1 └── build.cmd └── doc └── Config.json.md /.dependabot/config.yml.txt: -------------------------------------------------------------------------------- 1 | version: 1 2 | update_configs: 3 | - package_manager: "dotnet:nuget" 4 | directory: "/" 5 | update_schedule: "live" 6 | target_branch: dev 7 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | # Top-most EditorConfig file 4 | root = true 5 | 6 | # Default settings: 7 | [*] 8 | charset = utf-8 9 | indent_style = space 10 | indent_size = 4 11 | insert_final_newline = true 12 | trim_trailing_whitespace = true 13 | 14 | # C# files 15 | [*.cs] 16 | end_of_line = crlf 17 | 18 | # Documentation for Visual Studio .editorconfig configuration: 19 | # https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference 20 | 21 | ## Advanced 22 | dotnet_sort_system_directives_first = true 23 | 24 | ## Code Style 25 | 26 | ### General 27 | 28 | # 'this.' preferences 29 | dotnet_style_qualification_for_field = false:suggestion 30 | dotnet_style_qualification_for_property = false:suggestion 31 | dotnet_style_qualification_for_method = false:suggestion 32 | dotnet_style_qualification_for_event = false:suggestion 33 | 34 | # Predefined type preferences 35 | dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion 36 | dotnet_style_predefined_type_for_member_access = true:suggestion 37 | 38 | # 'using' preferences 39 | csharp_using_directive_placement = outside_namespace:suggestion 40 | 41 | # Modifier preferences 42 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion 43 | csharp_preferred_modifier_order = public, private, protected, internal, static, extern, new, virtual, abstract, sealed, override, readonly, unsafe, volatile, async:suggestion 44 | dotnet_style_readonly_field = true:suggestion 45 | 46 | # parenthesis preferences 47 | dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:suggestion 48 | dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:suggestion 49 | dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:suggestion 50 | dotnet_style_parentheses_in_other_operators = never_if_unnecessary:suggestion 51 | 52 | # Expression-level preferences 53 | dotnet_style_object_initializer = true:suggestion 54 | dotnet_style_collection_initializer = true:suggestion 55 | dotnet_style_explicit_tuple_names = true:suggestion 56 | dotnet_style_prefer_inferred_tuple_names = true:suggestion 57 | dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion 58 | dotnet_style_prefer_auto_properties = true:none 59 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion 60 | dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion 61 | dotnet_style_prefer_conditional_expression_over_return = true:suggestion 62 | csharp_prefer_simple_default_expression = true:suggestion 63 | csharp_style_deconstructed_variable_declaration = true:suggestion 64 | csharp_style_pattern_local_over_anonymous_function = true:suggestion 65 | 66 | ## Pattern matching 67 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion 68 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion 69 | 70 | # Variable preferences 71 | csharp_style_inlined_variable_declaration = true:suggestion 72 | 73 | # Null checking preferences 74 | csharp_style_throw_expression = true:suggestion 75 | csharp_style_conditional_delegate_call = true:suggestion 76 | dotnet_style_coalesce_expression = true:suggestion 77 | dotnet_style_null_propagation = true:suggestion 78 | 79 | # 'var' preferences' 80 | csharp_style_var_for_built_in_types = true:suggestion 81 | csharp_style_var_when_type_is_apparent = true:suggestion 82 | csharp_style_var_elsewhere = true:suggestion 83 | 84 | # Expression-bodied members 85 | csharp_style_expression_bodied_methods = true:suggestion 86 | csharp_style_expression_bodied_constructors = when_on_single_line:suggestion 87 | csharp_style_expression_bodied_operators = true:suggestion 88 | csharp_style_expression_bodied_properties = true:suggestion 89 | csharp_style_expression_bodied_indexers = true:suggestion 90 | csharp_style_expression_bodied_accessors = true:suggestion 91 | 92 | ### Formatting 93 | 94 | #### Indentation 95 | csharp_indent_block_contents = true 96 | csharp_indent_braces = false 97 | csharp_indent_case_contents = true 98 | csharp_indent_switch_labels = true 99 | csharp_indent_labels = flush_left 100 | 101 | #### New Lines 102 | # braces 103 | csharp_new_line_before_open_brace = all 104 | # keywords 105 | csharp_new_line_before_else = true 106 | csharp_new_line_before_catch = true 107 | csharp_new_line_before_finally = true 108 | # expressions 109 | csharp_new_line_before_members_in_object_initializers = true 110 | csharp_new_line_before_members_in_anonymous_types = true 111 | csharp_new_line_within_query_expression_clauses = true 112 | 113 | #### Spacing 114 | # method declarations 115 | csharp_space_between_method_declaration_name_and_open_parenthesis = false 116 | csharp_space_between_method_declaration_parameter_list_parentheses = false 117 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false 118 | # method calls 119 | csharp_space_between_method_call_name_and_opening_parenthesis = false 120 | csharp_space_between_method_call_parameter_list_parentheses = false 121 | csharp_space_between_method_call_empty_parameter_list_parentheses = false 122 | # other spacing options 123 | csharp_space_after_keywords_in_control_flow_statements = true 124 | csharp_space_between_parentheses = false 125 | csharp_space_after_cast = false 126 | csharp_space_around_declaration_statements = do_not_ignore 127 | # brackets 128 | csharp_space_before_open_square_brackets = false 129 | csharp_space_between_empty_square_brackets = false 130 | csharp_space_between_square_brackets = false 131 | # delimiters 132 | csharp_space_after_colon_in_inheritance_clause = true 133 | csharp_space_after_comma = true 134 | csharp_space_after_dot = false 135 | csharp_space_after_semicolon_in_for_statement = true 136 | csharp_space_before_colon_in_inheritance_clause = true 137 | csharp_space_before_comma = false 138 | csharp_space_before_dot = false 139 | csharp_space_before_semicolon_in_for_statement = false 140 | # operators 141 | csharp_space_around_binary_operators = before_and_after 142 | 143 | #### Wrapping 144 | csharp_preserve_single_line_blocks = true 145 | csharp_preserve_single_line_statements = false 146 | 147 | ### Naming 148 | # name all constant fields using PascalCase 149 | dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion 150 | dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields 151 | dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style 152 | 153 | dotnet_naming_symbols.constant_fields.applicable_kinds = field 154 | dotnet_naming_symbols.constant_fields.required_modifiers = const 155 | 156 | dotnet_naming_style.pascal_case_style.capitalization = pascal_case 157 | 158 | # static fields should have s_ prefix 159 | dotnet_naming_rule.static_fields_should_have_prefix.severity = suggestion 160 | dotnet_naming_rule.static_fields_should_have_prefix.symbols = static_fields 161 | dotnet_naming_rule.static_fields_should_have_prefix.style = static_prefix_style 162 | 163 | dotnet_naming_symbols.static_fields.applicable_kinds = field 164 | dotnet_naming_symbols.static_fields.required_modifiers = static 165 | 166 | dotnet_naming_style.static_prefix_style.required_prefix = s_ 167 | dotnet_naming_style.static_prefix_style.capitalization = camel_case 168 | 169 | # internal and private fields should be _camelCase 170 | dotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion 171 | dotnet_naming_rule.camel_case_for_private_internal_fields.symbols = private_internal_fields 172 | dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_underscore_style 173 | 174 | dotnet_naming_symbols.private_internal_fields.applicable_kinds = field 175 | dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal 176 | 177 | dotnet_naming_style.camel_case_underscore_style.required_prefix = _ 178 | dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case 179 | 180 | # Markdown files 181 | [*.md] 182 | trim_trailing_whitespace = false 183 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | [Bb]in 2 | [Dd]ebug/ 3 | [Pp]ublish/ 4 | [Rr]elease*/ 5 | obj/ 6 | .vs/ 7 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 r00telement 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SmartHunter - Monster Hunter: World Overlay 2 | 3 | A complete overlay for Monster Hunter: World on PC with Iceborne support. Originally distributed on [Nexus Mods](https://www.nexusmods.com/monsterhunterworld/mods/793). Features include: 4 | 5 | - Monster widget - name, health, parts, status effect buildup, and crown. 6 | - Team widget - name and damage meters. 7 | - Player widget - buff, debuff, and equipment/mantle timers. 8 | - Open source - freely learn from and contribute to the project. 9 | - Skinnable - create and distribute your own rich styles and animations with XAML. 10 | - Easy localization - create and distribute your own translations for our international friends. 11 | 12 | ## Requirements 13 | 14 | - [.NET Framework runtime](https://dotnet.microsoft.com/download/dotnet-framework) (4.6.1 is required 4.8 is recommended). 15 | - Monster Hunter: World running in borderless window or windowed mode. 16 | 17 | ## How to install 18 | 19 | - Download the latest release from [here](https://github.com/sir-wilhelm/SmartHunter/releases) (Assets > SmartHunter.zip). 20 | - Extract the contents of the zip. 21 | - Right-click SmartHunter.exe > Properties > check Unblock > click OK. 22 | 23 | ## How to use 24 | 25 | - Launch `SmartHunter.exe`. 26 | - Hold `LeftAlt` to view widget locations. 27 | - Click and drag widgets to move them. 28 | - Use the mouse wheel scroll over widgets to rescale them. 29 | - Other modifiers: 30 | - Press and hold `F1` to hide all widgets. 31 | - Press `RightCtrl` to toggle widget visibility. 32 | 33 | ### How to update 34 | 35 | - SmartHunter automatically checks the latest release, and if a new version is released it will auto download, extract, and clean up the old files. 36 | - To disable this feature set `AutomaticallyCheckAndDownloadUpdates` to `false` in `Config.json`. 37 | - You can always grab the latest version from the [releases](https://github.com/sir-wilhelm/SmartHunter/releases) page. 38 | 39 | ### How to use custom data 40 | 41 | - To better support auto updates, the .json data files are recreated by default. 42 | - To change/use custom data files set `UseCustomData` to `true` in `Config.json`. 43 | - Note: Memory.json is not 44 | 45 | ### How to create and use new localizations 46 | 47 | - Create a copy of `en-US.json` and rename it for the locale you are translating to. 48 | - Translate the strings in the second part of each key value pair. Do not change the keys. 49 | - Ensure the new file is in the SmartHunter folder. 50 | - Open `Config.json` and point `LocalizationFileName` to the new file. 51 | 52 | ### How to create and use new skins 53 | 54 | - Create a copy of `Default.xaml` and rename it appropriately. 55 | - Make changes to the new file. 56 | - Ensure the new file is in the SmartHunter folder. 57 | - Open `Config.json` and point `SkinFileName` to the new file. 58 | 59 | # FAQ 60 | 61 | Can I configure what is visible? 62 | Yes - see `Config.json` documentation [here](/doc/Config.json.md). 63 | 64 | Why don't monster parts and status effects update properly in multiplayer sessions? 65 | This data only updates properly for the quest host. This is just the way the game works and it can't be worked around. 66 | 67 | Where is the config file? 68 | `Config.json` is generated when SmartHunter is first launched. 69 | -------------------------------------------------------------------------------- /SmartHunter.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29613.14 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SmartHunter", "SmartHunter\SmartHunter.csproj", "{F5F99CEF-1C16-48E6-A88B-1A66D3B53998}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2A20B067-F085-4EB5-8667-7E708ACE5755}" 9 | ProjectSection(SolutionItems) = preProject 10 | .editorconfig = .editorconfig 11 | .gitignore = .gitignore 12 | LICENSE.txt = LICENSE.txt 13 | README.md = README.md 14 | EndProjectSection 15 | EndProject 16 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{ABF62AAC-2B01-43AB-9233-F2C3F4F746B3}" 17 | ProjectSection(SolutionItems) = preProject 18 | build\build.cmd = build\build.cmd 19 | build\PackageRelease.ps1 = build\PackageRelease.ps1 20 | EndProjectSection 21 | EndProject 22 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "doc", "doc", "{AC741825-8381-4958-A594-773ED0E868FF}" 23 | ProjectSection(SolutionItems) = preProject 24 | doc\Config.json.md = doc\Config.json.md 25 | EndProjectSection 26 | EndProject 27 | Global 28 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 29 | Debug|Any CPU = Debug|Any CPU 30 | Release|Any CPU = Release|Any CPU 31 | EndGlobalSection 32 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 33 | {F5F99CEF-1C16-48E6-A88B-1A66D3B53998}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 34 | {F5F99CEF-1C16-48E6-A88B-1A66D3B53998}.Debug|Any CPU.Build.0 = Debug|Any CPU 35 | {F5F99CEF-1C16-48E6-A88B-1A66D3B53998}.Release|Any CPU.ActiveCfg = Release|Any CPU 36 | {F5F99CEF-1C16-48E6-A88B-1A66D3B53998}.Release|Any CPU.Build.0 = Release|Any CPU 37 | EndGlobalSection 38 | GlobalSection(SolutionProperties) = preSolution 39 | HideSolutionNode = FALSE 40 | EndGlobalSection 41 | GlobalSection(ExtensibilityGlobals) = postSolution 42 | SolutionGuid = {A27E60A3-31A8-4F18-8D9E-30FA3B4CAF53} 43 | EndGlobalSection 44 | EndGlobal 45 | -------------------------------------------------------------------------------- /SmartHunter/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /SmartHunter/App.xaml: -------------------------------------------------------------------------------- 1 |  4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /SmartHunter/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using System.Reflection; 5 | using System.Text; 6 | using System.Windows; 7 | using System.Xaml; 8 | using SmartHunter.Core; 9 | using SmartHunter.Game; 10 | using SmartHunter.Game.Data.ViewModels; 11 | using SmartHunter.Game.Helpers; 12 | using SmartHunter.Ui.Windows; 13 | using XamlReader = System.Windows.Markup.XamlReader; 14 | 15 | namespace SmartHunter 16 | { 17 | public partial class App : Application 18 | { 19 | MhwOverlay m_Overlay; 20 | FileContainer m_SkinFile; 21 | 22 | string m_LastSkinFileName; 23 | 24 | protected override void OnStartup(StartupEventArgs e) 25 | { 26 | // Initialize the console view model first thing so we can see any problems that may occur 27 | var consoleViewModel = ConsoleViewModel.Instance; 28 | 29 | var assemblyVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString(); 30 | var fileVersionInfoVersion = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion; 31 | Log.WriteLine($"Started: Assembly Version: {assemblyVersion} | File Version: {fileVersionInfoVersion}"); 32 | 33 | SetPerMonitorDpiAwareness(); 34 | 35 | ConfigHelper.EnsureConfigs(); 36 | ConfigHelper.Main.Loaded += Config_Loaded; 37 | 38 | m_SkinFile = new FileContainer(ConfigHelper.Main.Values.SkinFileName); 39 | m_SkinFile.Changed += (s1, e1) => { LoadSkin(); }; 40 | LoadSkin(); 41 | 42 | m_Overlay = new MhwOverlay(new ConsoleWindow(), new TeamWidgetWindow(), new MonsterWidgetWindow(), new PlayerWidgetWindow(), new DebugWidgetWindow()); 43 | 44 | base.OnStartup(e); 45 | } 46 | 47 | protected override void OnExit(ExitEventArgs e) 48 | { 49 | Log.WriteLine("Ended"); 50 | base.OnExit(e); 51 | } 52 | 53 | private void Config_Loaded(object sender, EventArgs e) 54 | { 55 | if (m_LastSkinFileName != ConfigHelper.Main.Values.SkinFileName) 56 | { 57 | LoadSkin(); 58 | } 59 | } 60 | 61 | void LoadSkin() 62 | { 63 | if (ConfigHelper.Main.Values.Debug.UseInternalSkin) 64 | { 65 | return; 66 | } 67 | 68 | var skinFileName = ConfigHelper.Main.Values.SkinFileName; 69 | if (!File.Exists(FileContainer.GetFullPathFileName(skinFileName))) 70 | { 71 | Log.WriteLine($"Failed to load skin file '{skinFileName}'"); 72 | return; 73 | } 74 | 75 | m_SkinFile.TryChangeFileName(skinFileName); 76 | 77 | try 78 | { 79 | ResourceDictionary resourceDictionary = null; 80 | 81 | using (var streamReader = new StreamReader(m_SkinFile.FullPathFileName, Encoding.UTF8)) 82 | { 83 | var xmlReaderSettings = new XamlXmlReaderSettings 84 | { 85 | LocalAssembly = Assembly.GetExecutingAssembly() 86 | }; 87 | 88 | using (var xamlReader = new XamlXmlReader(streamReader.BaseStream, XamlReader.GetWpfSchemaContext(), xmlReaderSettings)) 89 | { 90 | resourceDictionary = XamlReader.Load(xamlReader) as ResourceDictionary; 91 | } 92 | } 93 | 94 | if (resourceDictionary != null) 95 | { 96 | Resources.MergedDictionaries.Clear(); 97 | Resources.MergedDictionaries.Add(resourceDictionary); 98 | 99 | if (m_Overlay != null) 100 | { 101 | m_Overlay.RefreshWidgetsLayout(); 102 | } 103 | 104 | Log.WriteLine($"{m_SkinFile.FileName} loaded"); 105 | } 106 | } 107 | catch (Exception ex) 108 | { 109 | Log.WriteException(ex); 110 | } 111 | 112 | m_LastSkinFileName = skinFileName; 113 | } 114 | 115 | void SetPerMonitorDpiAwareness() 116 | { 117 | // Win 8.1 added support for per monitor dpi 118 | if (Environment.OSVersion.Version >= new Version(6, 3, 0)) 119 | { 120 | // Win 10 creators update added support for per monitor v2 121 | if (Environment.OSVersion.Version >= new Version(10, 0, 15063)) 122 | { 123 | WindowsApi.SetProcessDpiAwarenessContext((int)WindowsApi.DPI_AWARENESS_CONTEXT.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); 124 | } 125 | else 126 | { 127 | WindowsApi.SetProcessDpiAwareness(WindowsApi.PROCESS_DPI_AWARENESS.PROCESS_PER_MONITOR_DPI_AWARE); 128 | } 129 | } 130 | else 131 | { 132 | WindowsApi.SetProcessDPIAware(); 133 | } 134 | } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /SmartHunter/Core/AddressRange.cs: -------------------------------------------------------------------------------- 1 | namespace SmartHunter.Core 2 | { 3 | public class AddressRange 4 | { 5 | public ulong Start { get; private set; } 6 | public ulong End { get; private set; } 7 | public ulong Size { get; private set; } 8 | 9 | public AddressRange(ulong start, ulong size) 10 | { 11 | Start = start; 12 | End = start + size; 13 | Size = size; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /SmartHunter/Core/BytePattern.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using SmartHunter.Game.Config; 5 | 6 | namespace SmartHunter.Core 7 | { 8 | public class BytePattern 9 | { 10 | public BytePatternConfig Config { get; } 11 | public byte?[] Bytes { get; private set; } 12 | public List MatchedAddresses { get; private set; } 13 | 14 | public BytePattern(BytePatternConfig config) 15 | { 16 | Config = config; 17 | Bytes = BytesFromString(config.PatternString); 18 | MatchedAddresses = new List(); 19 | } 20 | 21 | public static byte?[] BytesFromString(string byteString) 22 | { 23 | List byteList = new List(); 24 | 25 | var singleByteStrings = byteString.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries); 26 | 27 | foreach (var singleByteString in singleByteStrings) 28 | { 29 | byte parsedByte = 0; 30 | if (byte.TryParse(singleByteString, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out parsedByte)) 31 | { 32 | byteList.Add(parsedByte); 33 | } 34 | else 35 | { 36 | byteList.Add(null); 37 | } 38 | } 39 | 40 | return byteList.ToArray(); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /SmartHunter/Core/Command.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Input; 3 | 4 | namespace SmartHunter.Core 5 | { 6 | #pragma warning disable 67 7 | public class Command : ICommand 8 | { 9 | private readonly Action _action; 10 | private readonly Func _canExecuteFunction; 11 | 12 | public Command(Action action, Func canExecute = null) 13 | { 14 | _action = action; 15 | _canExecuteFunction = canExecute; 16 | } 17 | 18 | public bool CanExecute(object parameter) 19 | { 20 | if (_canExecuteFunction != null) 21 | { 22 | return _canExecuteFunction(this, parameter); 23 | } 24 | return true; 25 | } 26 | 27 | public void Execute(object parameter) 28 | { 29 | _action(parameter); 30 | } 31 | 32 | public event EventHandler CanExecuteChanged; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /SmartHunter/Core/Config/ConfigContainer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.IO; 4 | using Newtonsoft.Json; 5 | using Newtonsoft.Json.Converters; 6 | using SmartHunter.Config; 7 | using SmartHunter.Game.Helpers; 8 | using ErrorEventArgs = Newtonsoft.Json.Serialization.ErrorEventArgs; 9 | 10 | namespace SmartHunter.Core.Config 11 | { 12 | public class ConfigContainer : FileContainer 13 | { 14 | public T Values = (T)Activator.CreateInstance(typeof(T), new object[] { }); 15 | 16 | public event EventHandler Loaded; 17 | 18 | public ConfigContainer(string fileName) : base(fileName) 19 | { 20 | var isDesignInstance = LicenseManager.UsageMode == LicenseUsageMode.Designtime; 21 | if (!isDesignInstance) 22 | { 23 | Load(); 24 | } 25 | } 26 | 27 | public void HandleDeserializationError(object sender, ErrorEventArgs args) 28 | { 29 | Log.WriteException(args.ErrorContext.Error); 30 | args.ErrorContext.Handled = true; 31 | } 32 | 33 | protected override void OnChanged() => Load(); 34 | 35 | private void Load() 36 | { 37 | if (File.Exists(FullPathFileName) && !FileName.Equals("Memory.json")) 38 | { 39 | try 40 | { 41 | string contents = null; 42 | using (var stream = File.Open(FullPathFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 43 | using (var reader = new StreamReader(stream, System.Text.Encoding.UTF8)) 44 | { 45 | contents = reader.ReadToEnd(); 46 | } 47 | 48 | var customLanguage = typeof(T).Equals(typeof(LocalizationConfig)) && !FileName.Equals("en-US.json"); 49 | var fileContentsEqualsAutoGen = contents == GetAutoGenerateedJson(); 50 | if (!fileContentsEqualsAutoGen && FileName != "Config.json" && !customLanguage) 51 | { 52 | Log.WriteWarning($"Warning: {FileName} differs from autogenerated version."); 53 | } 54 | 55 | var settings = new JsonSerializerSettings 56 | { 57 | Formatting = Formatting.Indented, 58 | ContractResolver = new ContractResolver(), 59 | Error = HandleDeserializationError, 60 | }; 61 | 62 | // Solves dictionary/lists being added to instead of overwritten but causes problems elsewhere 63 | // https://stackoverflow.com/questions/29113063/json-net-why-does-it-add-to-list-instead-of-overwriting 64 | // https://stackoverflow.com/questions/27848547/explanation-for-objectcreationhandling-using-newtonsoft-json 65 | // This has been moved to ContractResolver to target Dictionaries specifically 66 | // settings.ObjectCreationHandling = ObjectCreationHandling.Replace; 67 | settings.Converters.Add(new StringEnumConverter()); 68 | settings.Converters.Add(new StringFloatConverter()); 69 | 70 | if (FileName.Equals("Config.json") || fileContentsEqualsAutoGen || ConfigHelper.Main.Values.UseCustomData || customLanguage) 71 | { 72 | JsonConvert.PopulateObject(contents, Values, settings); 73 | Log.WriteLine($"{FileName} loaded"); 74 | } 75 | else 76 | { 77 | Log.WriteLine($"{FileName} will be renamed to custom_{FileName} and recreated..."); 78 | Log.WriteLine("This can be disabled by setting [\"UseCustomData\": true,] in Config.json."); 79 | 80 | File.Delete($"custom_{FileName}"); 81 | File.Move(FileName, $"custom_{FileName}"); 82 | Save(); 83 | } 84 | } 85 | catch (Exception ex) 86 | { 87 | Log.WriteException(ex); 88 | } 89 | } 90 | else 91 | { 92 | Save(); 93 | } 94 | 95 | Loaded?.Invoke(this, null); 96 | } 97 | 98 | public void Save(bool printToLog = true) 99 | { 100 | TryPauseWatching(); 101 | 102 | try 103 | { 104 | File.WriteAllText(FullPathFileName, GetAutoGenerateedJson()); 105 | if (printToLog) 106 | { 107 | Log.WriteLine($"{FileName} saved"); 108 | } 109 | } 110 | catch (Exception ex) 111 | { 112 | Log.WriteException(ex); 113 | } 114 | 115 | TryUnpauseWatching(); 116 | } 117 | 118 | private string GetAutoGenerateedJson() 119 | { 120 | var settings = new JsonSerializerSettings 121 | { 122 | Formatting = Formatting.Indented, 123 | NullValueHandling = NullValueHandling.Ignore, 124 | ContractResolver = new ContractResolver() 125 | }; 126 | 127 | settings.Converters.Add(new StringEnumConverter()); 128 | settings.Converters.Add(new StringFloatConverter()); 129 | 130 | return JsonConvert.SerializeObject(Values, settings); 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /SmartHunter/Core/Config/ContractResolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | using Newtonsoft.Json; 5 | using Newtonsoft.Json.Serialization; 6 | 7 | namespace SmartHunter.Core.Config 8 | { 9 | public class ContractResolver : DefaultContractResolver 10 | { 11 | protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) 12 | { 13 | // Replace dictionaries entirely unless integrity is preserved 14 | var property = base.CreateProperty(member, memberSerialization); 15 | if (property.ObjectCreationHandling == null && GetDictionaryKeyType(property.PropertyType) != null && member.GetCustomAttribute() == null) 16 | { 17 | property.ObjectCreationHandling = ObjectCreationHandling.Replace; 18 | } 19 | 20 | // Exclude empty arrays from writing 21 | if (property.PropertyType.IsArray) 22 | { 23 | property.ShouldSerialize = instance => 24 | { 25 | var arrayField = instance.GetType().GetField(property.PropertyName); 26 | if (arrayField != null) 27 | { 28 | var array = arrayField.GetValue(instance) as Array; 29 | if (array != null) 30 | { 31 | return array.Length > 0; 32 | } 33 | } 34 | 35 | return true; 36 | }; 37 | } 38 | 39 | return property; 40 | } 41 | 42 | Type GetDictionaryKeyType(Type type) 43 | { 44 | while (type != null) 45 | { 46 | if (type.IsGenericType) 47 | { 48 | var genType = type.GetGenericTypeDefinition(); 49 | if (genType == typeof(Dictionary<,>)) 50 | { 51 | return type.GetGenericArguments()[0]; 52 | } 53 | } 54 | 55 | type = type.BaseType; 56 | } 57 | 58 | return null; 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /SmartHunter/Core/Config/PreserveCollectionIntegrity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SmartHunter.Core.Config 4 | { 5 | public class PreserveCollectionIntegrity : Attribute 6 | { 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /SmartHunter/Core/Config/StringFloatConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using Newtonsoft.Json; 4 | 5 | namespace SmartHunter.Core.Config 6 | { 7 | public class StringFloatConverter : JsonConverter 8 | { 9 | public override bool CanConvert(Type objectType) 10 | { 11 | return objectType == typeof(float); 12 | } 13 | 14 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 15 | { 16 | var floatValue = (float)value; 17 | writer.WriteRawValue(floatValue.ToString("0.##", CultureInfo.InvariantCulture)); 18 | } 19 | 20 | public override bool CanRead 21 | { 22 | get 23 | { 24 | return false; 25 | } 26 | } 27 | 28 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 29 | { 30 | throw new NotImplementedException(); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /SmartHunter/Core/Config/WidgetConfig.cs: -------------------------------------------------------------------------------- 1 | namespace SmartHunter.Core.Config 2 | { 3 | public class WidgetConfig 4 | { 5 | public bool IsVisible = true; 6 | public float X; 7 | public float Y; 8 | public float Scale = 1f; 9 | 10 | public WidgetConfig(float x, float y) 11 | { 12 | X = x; 13 | Y = y; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /SmartHunter/Core/Data/Bindable.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Runtime.CompilerServices; 3 | 4 | namespace SmartHunter.Core.Data 5 | { 6 | public abstract class Bindable : INotifyPropertyChanged 7 | { 8 | public event PropertyChangedEventHandler PropertyChanged; 9 | public void NotifyPropertyChanged(string propertyName) 10 | { 11 | if (PropertyChanged != null) 12 | { 13 | PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 14 | } 15 | } 16 | 17 | protected bool SetProperty(ref T storage, T value, [CallerMemberName] string propertyName = null) 18 | { 19 | if (Equals(storage, value)) 20 | { 21 | return false; 22 | } 23 | 24 | storage = value; 25 | NotifyPropertyChanged(propertyName); 26 | 27 | return true; 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /SmartHunter/Core/Data/ContextualWidget.cs: -------------------------------------------------------------------------------- 1 | using SmartHunter.Core.Config; 2 | 3 | namespace SmartHunter.Core.Data 4 | { 5 | public class ContextualWidget : Widget where TWidgetContext : WidgetContext 6 | { 7 | private TWidgetContext m_Context; 8 | public TWidgetContext Context 9 | { 10 | get { return m_Context; } 11 | set { SetProperty(ref m_Context, value); } 12 | } 13 | 14 | public ContextualWidget(WidgetConfig widgetConfig, TWidgetContext context = null) : base(widgetConfig) 15 | { 16 | m_Context = context; 17 | } 18 | 19 | public override void UpdateFromConfig() 20 | { 21 | base.UpdateFromConfig(); 22 | 23 | if (Context != null) 24 | { 25 | Context.UpdateFromConfig(); 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /SmartHunter/Core/Data/Progress.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | 4 | namespace SmartHunter.Core.Data 5 | { 6 | public class Progress : Bindable, IComparable 7 | { 8 | private float _max; 9 | private float _current; 10 | private readonly bool _shouldCapCurrent; 11 | 12 | public Progress(float max, float current, bool shouldCapCurrent = false) 13 | { 14 | _shouldCapCurrent = shouldCapCurrent; 15 | 16 | Max = max; 17 | Current = current; 18 | } 19 | 20 | public float Max 21 | { 22 | get => _max; 23 | set => SetProperty(ref _max, value); 24 | } 25 | 26 | public float Current 27 | { 28 | get => _current; 29 | set 30 | { 31 | if (_shouldCapCurrent) 32 | { 33 | value = Cap(value, _max); 34 | } 35 | 36 | if (SetProperty(ref _current, value)) 37 | { 38 | if (_current > _max) 39 | { 40 | Max = _current; 41 | } 42 | 43 | NotifyPropertyChanged(nameof(Fraction)); 44 | NotifyPropertyChanged(nameof(Angle)); 45 | NotifyPropertyChanged(nameof(Color)); 46 | } 47 | } 48 | } 49 | 50 | public string Color 51 | { 52 | get 53 | { 54 | Color c; 55 | if (Fraction > 0.5f) 56 | { 57 | var red = (int)(255f * 2 * (1 - Fraction)); 58 | c = System.Drawing.Color.FromArgb(255, red, 255, 0); 59 | } 60 | else 61 | { 62 | var green = (int)(255f * 2 * Fraction); 63 | c = System.Drawing.Color.FromArgb(255, 255, green, 0); 64 | } 65 | return "#" + c.R.ToString("X2") + c.G.ToString("X2") + "00"; 66 | } 67 | } 68 | 69 | public float Fraction => _current / _max; 70 | public float Angle => Fraction * 359.999f; 71 | 72 | // We only really want the default compare to compare nulls. 73 | // We can then compare by Current in a separate pass for better control. 74 | public int CompareTo(object obj) 75 | { 76 | if (obj == null) 77 | { 78 | return 1; 79 | } 80 | 81 | return 0; 82 | } 83 | 84 | private float Cap(float value, float max) 85 | { 86 | if (value < 0) 87 | { 88 | value = 0; 89 | } 90 | 91 | if (value > max) 92 | { 93 | value = max; 94 | } 95 | 96 | return value; 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /SmartHunter/Core/Data/TimedVisibility.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SmartHunter.Core.Data 4 | { 5 | public abstract class TimedVisibility : Bindable 6 | { 7 | public DateTimeOffset InitialTime { get; private set; } 8 | public DateTimeOffset? LastChangedTime { get; private set; } 9 | 10 | public event EventHandler> Changed; 11 | 12 | public TimedVisibility() 13 | { 14 | InitialTime = DateTimeOffset.UtcNow; 15 | } 16 | 17 | protected void UpdateLastChangedTime() 18 | { 19 | LastChangedTime = DateTimeOffset.UtcNow; 20 | 21 | if (Changed != null) 22 | { 23 | Changed(this, new GenericEventArgs(LastChangedTime.Value)); 24 | } 25 | } 26 | 27 | protected bool IsTimeVisible(bool showUnchanged, float hideAfterSeconds) 28 | { 29 | if (!showUnchanged && LastChangedTime == null) 30 | { 31 | return false; 32 | } 33 | 34 | DateTimeOffset time = InitialTime; 35 | if (LastChangedTime != null) 36 | { 37 | time = LastChangedTime.Value; 38 | } 39 | 40 | var hideTime = time.AddSeconds(hideAfterSeconds); 41 | if (hideTime < DateTimeOffset.UtcNow) 42 | { 43 | return false; 44 | } 45 | else 46 | { 47 | return true; 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /SmartHunter/Core/Data/Widget.cs: -------------------------------------------------------------------------------- 1 | using SmartHunter.Core.Config; 2 | 3 | namespace SmartHunter.Core.Data 4 | { 5 | public class Widget : Bindable 6 | { 7 | readonly WidgetConfig _widgetConfig; 8 | private float _x; 9 | private float _y; 10 | private float _scale = 1; 11 | private bool _isVisible = true; 12 | 13 | public Widget(WidgetConfig widgetConfig) 14 | { 15 | _widgetConfig = widgetConfig; 16 | UpdateFromConfig(); 17 | } 18 | 19 | public float X 20 | { 21 | get => _x; 22 | set 23 | { 24 | if (SetProperty(ref _x, value) && _x != _widgetConfig.X) 25 | { 26 | UpdateConfig(); 27 | } 28 | } 29 | } 30 | 31 | public float Y 32 | { 33 | get => _y; 34 | set 35 | { 36 | if (SetProperty(ref _y, value) && _y != _widgetConfig.Y) 37 | { 38 | UpdateConfig(); 39 | } 40 | } 41 | } 42 | 43 | public float Scale 44 | { 45 | get => _scale; 46 | set 47 | { 48 | if (SetProperty(ref _scale, value) && _scale != _widgetConfig.Scale) 49 | { 50 | UpdateConfig(); 51 | } 52 | } 53 | } 54 | 55 | public bool IsVisible 56 | { 57 | get => _isVisible; 58 | set 59 | { 60 | if (SetProperty(ref _isVisible, value) && _isVisible != _widgetConfig.IsVisible) 61 | { 62 | UpdateConfig(); 63 | } 64 | } 65 | } 66 | 67 | public bool CanSaveConfig { get; set; } 68 | 69 | public virtual void UpdateFromConfig() 70 | { 71 | X = _widgetConfig.X; 72 | Y = _widgetConfig.Y; 73 | Scale = _widgetConfig.Scale; 74 | IsVisible = _widgetConfig.IsVisible; 75 | } 76 | 77 | private void UpdateConfig() 78 | { 79 | _widgetConfig.X = _x; 80 | _widgetConfig.Y = _y; 81 | _widgetConfig.Scale = _scale; 82 | _widgetConfig.IsVisible = _isVisible; 83 | 84 | CanSaveConfig = true; 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /SmartHunter/Core/Data/WidgetContext.cs: -------------------------------------------------------------------------------- 1 | namespace SmartHunter.Core.Data 2 | { 3 | public abstract class WidgetContext : Bindable 4 | { 5 | public virtual void UpdateFromConfig() { } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /SmartHunter/Core/FileContainer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.IO; 4 | using System.Reflection; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | 8 | namespace SmartHunter.Core 9 | { 10 | public class FileContainer 11 | { 12 | FileSystemWatcher m_FileWatcher = null; 13 | 14 | public string FileName { get; private set; } 15 | 16 | public string FullPath 17 | { 18 | get 19 | { 20 | return GetFullPath(); 21 | } 22 | } 23 | 24 | public string FullPathFileName 25 | { 26 | get 27 | { 28 | return GetFullPathFileName(FileName); 29 | } 30 | } 31 | 32 | public event EventHandler Changed; 33 | 34 | public FileContainer(string fileName) 35 | { 36 | FileName = fileName; 37 | 38 | bool isDesignInstance = LicenseManager.UsageMode == LicenseUsageMode.Designtime; 39 | if (!isDesignInstance) 40 | { 41 | WatchFile(true); 42 | } 43 | } 44 | 45 | public void TryChangeFileName(string fileName) 46 | { 47 | if (FileName == fileName) 48 | { 49 | return; 50 | } 51 | 52 | bool watching = m_FileWatcher != null; 53 | if (watching) 54 | { 55 | WatchFile(false); 56 | } 57 | 58 | FileName = fileName; 59 | 60 | OnChanged(); 61 | if (Changed != null) 62 | { 63 | Changed(this, new EventArgs()); 64 | } 65 | 66 | if (watching) 67 | { 68 | WatchFile(true); 69 | } 70 | } 71 | 72 | void WatchFile(bool watch) 73 | { 74 | if (watch && m_FileWatcher == null) 75 | { 76 | if (!String.IsNullOrEmpty(FileName)) 77 | { 78 | m_FileWatcher = new FileSystemWatcher(); 79 | m_FileWatcher.Path = FullPath; 80 | m_FileWatcher.NotifyFilter = NotifyFilters.LastWrite; 81 | m_FileWatcher.Filter = FileName; 82 | m_FileWatcher.Changed += FileWatcher_Changed; 83 | m_FileWatcher.EnableRaisingEvents = true; 84 | } 85 | } 86 | else if (!watch && m_FileWatcher != null) 87 | { 88 | m_FileWatcher.Changed -= FileWatcher_Changed; 89 | m_FileWatcher.Dispose(); 90 | m_FileWatcher = null; 91 | } 92 | } 93 | 94 | async void FileWatcher_Changed(object sender, FileSystemEventArgs e) 95 | { 96 | TryPauseWatching(); 97 | 98 | await Task.Delay(100); 99 | 100 | Application.Current.Dispatcher.Invoke(delegate 101 | { 102 | OnChanged(); 103 | if (Changed != null) 104 | { 105 | Changed(this, new EventArgs()); 106 | } 107 | }); 108 | 109 | TryUnpauseWatching(); 110 | } 111 | 112 | protected void TryPauseWatching() 113 | { 114 | if (m_FileWatcher != null) 115 | { 116 | m_FileWatcher.EnableRaisingEvents = false; 117 | } 118 | } 119 | 120 | protected void TryUnpauseWatching() 121 | { 122 | if (m_FileWatcher != null) 123 | { 124 | m_FileWatcher.EnableRaisingEvents = true; 125 | } 126 | } 127 | 128 | virtual protected void OnChanged() { } 129 | 130 | public static string GetFullPath() 131 | { 132 | return Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase).Replace("file:\\", "") + "\\"; 133 | } 134 | 135 | public static string GetFullPathFileName(string fileName) 136 | { 137 | return GetFullPath() + fileName; 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /SmartHunter/Core/GenericEventArgs.cs: -------------------------------------------------------------------------------- 1 | namespace SmartHunter.Core 2 | { 3 | public class GenericEventArgs 4 | { 5 | public T Value { get; private set; } 6 | 7 | public GenericEventArgs(T value) 8 | { 9 | Value = value; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /SmartHunter/Core/Helpers/Updater.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Net; 4 | using System.Reflection; 5 | using Newtonsoft.Json; 6 | 7 | namespace SmartHunter.Core.Helpers 8 | { 9 | public class Updater 10 | { 11 | private readonly string _apiEndpoint = "https://api.github.com/repos/sir-wilhelm/SmartHunter/releases/latest"; 12 | private readonly string _userAgent = "Mozilla/4.0 (Compatible; Windows NT 5.1; MSIE 6.0) (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)"; 13 | 14 | public bool CheckForUpdates() 15 | { 16 | try 17 | { 18 | var latestRelease = GetLatestRelease(); 19 | var needsUpdates = new Version(latestRelease.tag_name) > Assembly.GetExecutingAssembly().GetName().Version; 20 | if (!needsUpdates) 21 | { 22 | Log.WriteLine("No updates found."); 23 | } 24 | return needsUpdates; 25 | } 26 | catch (Exception e) 27 | { 28 | Log.WriteLine($"An error has occured while searching for updates:{Environment.NewLine}{e}"); 29 | Log.WriteLine("Resuming the normal flow of the application."); 30 | return false; 31 | } 32 | } 33 | 34 | private LatestRelease GetLatestRelease() 35 | { 36 | var request = WebRequest.CreateHttp(_apiEndpoint); 37 | request.ContentType = "application/json"; 38 | request.UserAgent = _userAgent; 39 | using var stream = request.GetResponse().GetResponseStream(); 40 | using var reader = new StreamReader(stream); 41 | var latestReleaseAsJson = reader.ReadToEnd(); 42 | return JsonConvert.DeserializeObject(latestReleaseAsJson); 43 | } 44 | 45 | public bool DownloadUpdates() 46 | { 47 | try 48 | { 49 | var latestRelease = GetLatestRelease(); 50 | 51 | using var client = new WebClient(); 52 | var releaseZip = latestRelease.assets[0]; 53 | Log.WriteLine("Deleting older update."); 54 | File.Delete(releaseZip.name); 55 | client.DownloadFile(releaseZip.browser_download_url, releaseZip.name); 56 | return true; 57 | } 58 | catch (Exception e) 59 | { 60 | Log.WriteLine($"An error has occured while downloading update:{Environment.NewLine}{e}"); 61 | return false; 62 | } 63 | } 64 | 65 | internal class LatestRelease 66 | { 67 | public string tag_name { get; set; } 68 | public Asset[] assets { get; set; } 69 | } 70 | internal class Asset 71 | { 72 | public string name { get; set; } 73 | public string browser_download_url { get; set; } 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /SmartHunter/Core/Helpers/WindowHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using System.Windows; 3 | using System.Windows.Interop; 4 | 5 | namespace SmartHunter.Core.Helpers 6 | { 7 | public static class WindowHelper 8 | { 9 | static uint TopMostWindowSizePositions 10 | { 11 | get 12 | { 13 | return (uint)WindowsApi.WindowSizePositionFlag.SWP_NOMOVE 14 | | (uint)WindowsApi.WindowSizePositionFlag.SWP_NOSIZE 15 | | (uint)WindowsApi.WindowSizePositionFlag.SWP_SHOWWINDOW 16 | | (uint)WindowsApi.WindowSizePositionFlag.SWP_NOACTIVATE; 17 | } 18 | } 19 | 20 | static uint TopMostSelectableWindowStyleFlags 21 | { 22 | get 23 | { 24 | return (uint)WindowsApi.WindowStyleFlag.WS_EX_LAYERED 25 | | (uint)WindowsApi.WindowStyleFlag.WS_EX_TOPMOST; 26 | } 27 | } 28 | 29 | static uint TopMostTransparentWindowStyleFlags 30 | { 31 | get 32 | { 33 | return (uint)WindowsApi.WindowStyleFlag.WS_EX_LAYERED 34 | | (uint)WindowsApi.WindowStyleFlag.WS_EX_TRANSPARENT 35 | | (uint)WindowsApi.WindowStyleFlag.WS_EX_TOPMOST; 36 | } 37 | } 38 | 39 | public static void SetTopMostSelectable(Window window) 40 | { 41 | var handle = new WindowInteropHelper(window).EnsureHandle(); 42 | WindowsApi.SetWindowLong(handle, (int)WindowsApi.WindowLongGroup.GWL_EXSTYLE, TopMostSelectableWindowStyleFlags); 43 | WindowsApi.SetWindowPos(handle, -1, 0, 0, 0, 0, TopMostWindowSizePositions); 44 | } 45 | 46 | public static void SetTopMostTransparent(Window window) 47 | { 48 | var handle = new WindowInteropHelper(window).EnsureHandle(); 49 | WindowsApi.SetWindowLong(handle, (int)WindowsApi.WindowLongGroup.GWL_EXSTYLE, TopMostTransparentWindowStyleFlags); 50 | WindowsApi.SetWindowPos(handle, -1, 0, 0, 0, 0, TopMostWindowSizePositions); 51 | } 52 | 53 | // Experimental function to set the window background to use Windows 10 acrylic - this part of the win api is poorly documented 54 | public static void EnableAcrylic(Window window) 55 | { 56 | var handle = new WindowInteropHelper(window).EnsureHandle(); 57 | 58 | var accent = new WindowsApi.AccentPolicy(); 59 | accent.GradientColor = 0x01000000; 60 | 61 | accent.AccentState = WindowsApi.AccentState.ACCENT_ENABLE_ACRYLICBLURBEHIND; 62 | 63 | var accentStructSize = Marshal.SizeOf(accent); 64 | 65 | var accentPtr = Marshal.AllocHGlobal(accentStructSize); 66 | Marshal.StructureToPtr(accent, accentPtr, false); 67 | 68 | var data = new WindowsApi.WindowCompositionAttributeData(); 69 | data.Attribute = WindowsApi.WindowCompositionAttribute.WCA_ACCENT_POLICY; 70 | data.SizeOfData = accentStructSize; 71 | data.Data = accentPtr; 72 | 73 | WindowsApi.SetWindowCompositionAttribute(handle, ref data); 74 | 75 | Marshal.FreeHGlobal(accentPtr); 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /SmartHunter/Core/KeyboardInput.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using System.Windows.Input; 4 | 5 | namespace SmartHunter.Core 6 | { 7 | public class KeyboardInput 8 | { 9 | IntPtr m_User32Handle; 10 | IntPtr m_KeyboardHookHandle; 11 | 12 | WindowsApi.HookProc m_KeyboardHook; 13 | 14 | public event EventHandler InputReceived; 15 | 16 | public KeyboardInput() 17 | { 18 | Hook(); 19 | } 20 | 21 | ~KeyboardInput() 22 | { 23 | Unhook(); 24 | } 25 | 26 | void Hook() 27 | { 28 | m_KeyboardHookHandle = IntPtr.Zero; 29 | m_User32Handle = IntPtr.Zero; 30 | m_KeyboardHook = KeyboardHook; 31 | 32 | m_User32Handle = WindowsApi.LoadLibrary("User32"); 33 | if (m_User32Handle != IntPtr.Zero) 34 | { 35 | m_KeyboardHookHandle = WindowsApi.SetWindowsHookEx((int)WindowsApi.WindowsHook.WH_KEYBOARD_LL, m_KeyboardHook, m_User32Handle, 0); 36 | } 37 | } 38 | 39 | void Unhook() 40 | { 41 | if (m_KeyboardHookHandle != IntPtr.Zero) 42 | { 43 | WindowsApi.UnhookWindowsHookEx(m_KeyboardHookHandle); 44 | m_KeyboardHookHandle = IntPtr.Zero; 45 | m_KeyboardHook -= KeyboardHook; 46 | } 47 | 48 | if (m_User32Handle != IntPtr.Zero) 49 | { 50 | WindowsApi.FreeLibrary(m_User32Handle); 51 | m_User32Handle = IntPtr.Zero; 52 | } 53 | } 54 | 55 | static Key KeyFromVirtualCode(uint virtualCode) 56 | { 57 | return KeyInterop.KeyFromVirtualKey((int)virtualCode); 58 | } 59 | 60 | static int VirtualCodeFromKey(Key key) 61 | { 62 | return KeyInterop.VirtualKeyFromKey(key); 63 | } 64 | 65 | IntPtr KeyboardHook(int nCode, IntPtr wParam, IntPtr lParam) 66 | { 67 | if (nCode >= 0) 68 | { 69 | var keyboardMessage = (WindowsApi.KeyboardMessage)wParam.ToInt32(); 70 | var keyboardData = (WindowsApi.KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(WindowsApi.KBDLLHOOKSTRUCT)); 71 | 72 | var key = KeyFromVirtualCode(keyboardData.VkCode); 73 | bool isDown = keyboardMessage == WindowsApi.KeyboardMessage.WM_KEYDOWN || keyboardMessage == WindowsApi.KeyboardMessage.WM_SYSKEYDOWN; 74 | 75 | InputReceived?.Invoke(this, new KeyboardInputEventArgs(key, isDown)); 76 | } 77 | 78 | return WindowsApi.CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /SmartHunter/Core/KeyboardInputEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Input; 3 | 4 | namespace SmartHunter.Core 5 | { 6 | public class KeyboardInputEventArgs : EventArgs 7 | { 8 | public Key Key { get; private set; } 9 | public bool IsDown { get; private set; } 10 | 11 | public KeyboardInputEventArgs(Key key, bool isDown) 12 | { 13 | Key = key; 14 | IsDown = isDown; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /SmartHunter/Core/Log.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.IO; 4 | using System.Security.AccessControl; 5 | 6 | namespace SmartHunter.Core 7 | { 8 | public static class Log 9 | { 10 | static string s_FileName = "Log.txt"; 11 | 12 | public static event EventHandler> LineReceived; 13 | 14 | public static void WriteLine(string message) 15 | { 16 | var line = string.Format("[{0:yyyy-MM-dd HH:mm:ss}] {1}", DateTimeOffset.Now.ToUniversalTime(), message); 17 | Console.WriteLine(line); 18 | 19 | LineReceived?.Invoke(null, new GenericEventArgs(line)); 20 | 21 | bool isDesignInstance = LicenseManager.UsageMode == LicenseUsageMode.Designtime; 22 | if (!isDesignInstance) 23 | { 24 | try 25 | { 26 | using var fileStream = new FileStream(s_FileName, FileMode.OpenOrCreate, FileSystemRights.AppendData, FileShare.Write, 4096, FileOptions.None); 27 | using var streamWriter = new StreamWriter(fileStream); 28 | streamWriter.AutoFlush = true; 29 | streamWriter.WriteLine(line); 30 | } 31 | catch (Exception) { } 32 | } 33 | } 34 | 35 | public static void WriteException(Exception exception) => WriteLine($"{exception.GetType().Name}: {exception.Message}\r\n{exception.StackTrace}"); 36 | 37 | public static void WriteWarning(string warning) => 38 | // prep for adding support for colored messages to ConsoleWindow. 39 | WriteLine(warning); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /SmartHunter/Core/Overlay.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Windows; 3 | using System.Windows.Input; 4 | using SmartHunter.Core.Helpers; 5 | using SmartHunter.Core.Windows; 6 | 7 | namespace SmartHunter.Core 8 | { 9 | public abstract class Overlay 10 | { 11 | KeyboardInput m_KeyboardInput; 12 | 13 | Window m_MainWindow; 14 | protected WidgetWindow[] WidgetWindows { get; private set; } 15 | 16 | public Overlay(Window mainWindow, params WidgetWindow[] widgetWindows) 17 | { 18 | m_MainWindow = mainWindow; 19 | WidgetWindows = widgetWindows; 20 | 21 | m_MainWindow.Loaded += MainWindow_Loaded; 22 | m_MainWindow.Closing += MainWindow_Closing; 23 | 24 | m_KeyboardInput = new KeyboardInput(); 25 | m_KeyboardInput.InputReceived += KeyboardInput_InputReceived; 26 | 27 | m_MainWindow.Show(); 28 | } 29 | 30 | private void MainWindow_Loaded(object sender, RoutedEventArgs e) 31 | { 32 | UpdateWidgetsFromConfig(); 33 | /* 34 | foreach (var widgetWindow in WidgetWindows) 35 | { 36 | if (!widgetWindow.IsVisible) 37 | { 38 | widgetWindow.Owner = m_MainWindow; 39 | widgetWindow.Opacity = 0.0f; 40 | widgetWindow.Hide(); 41 | } 42 | } 43 | */ 44 | } 45 | 46 | private void MainWindow_Closing(object sender, CancelEventArgs e) 47 | { 48 | foreach (var widgetWindow in WidgetWindows) 49 | { 50 | widgetWindow.Close(); 51 | } 52 | } 53 | 54 | private void ToggleWidgetWindow(WidgetWindow widgetWindow) 55 | { 56 | /* 57 | widgetWindow.Owner = m_MainWindow; 58 | if (widgetWindow.Visibility != Visibility.Visible) 59 | { 60 | widgetWindow.Opacity = 1.0f; 61 | widgetWindow.Show(); 62 | 63 | WindowHelper.SetTopMostTransparent(widgetWindow); 64 | } 65 | else 66 | { 67 | widgetWindow.Opacity = 0.0f; 68 | widgetWindow.Hide(); 69 | } 70 | */ 71 | 72 | if (widgetWindow.Visibility != Visibility.Visible) 73 | { 74 | widgetWindow.Owner = m_MainWindow; 75 | widgetWindow.Show(); 76 | widgetWindow.Owner = null; 77 | 78 | WindowHelper.SetTopMostTransparent(widgetWindow); 79 | } 80 | else 81 | { 82 | widgetWindow.Hide(); 83 | } 84 | } 85 | 86 | public void UpdateWidgetsFromConfig() 87 | { 88 | foreach (var widgetWindow in WidgetWindows) 89 | { 90 | widgetWindow.Widget.UpdateFromConfig(); 91 | 92 | if ((widgetWindow.Widget.IsVisible && widgetWindow.Visibility != Visibility.Visible) || 93 | (!widgetWindow.Widget.IsVisible && widgetWindow.Visibility == Visibility.Visible)) 94 | { 95 | ToggleWidgetWindow(widgetWindow); 96 | } 97 | } 98 | } 99 | 100 | public void RefreshWidgetsLayout() 101 | { 102 | foreach (var widgetWindow in WidgetWindows) 103 | { 104 | var dataContext = widgetWindow.DataContext; 105 | widgetWindow.DataContext = null; 106 | widgetWindow.DataContext = dataContext; 107 | } 108 | } 109 | 110 | private void KeyboardInput_InputReceived(object sender, KeyboardInputEventArgs e) 111 | { 112 | InputReceived(e.Key, e.IsDown); 113 | } 114 | 115 | abstract protected void InputReceived(Key key, bool down); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /SmartHunter/Core/PointerTrace.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace SmartHunter.Core.Helpers 6 | { 7 | public class PointerTrace 8 | { 9 | public List Levels { get; private set; } 10 | 11 | public PointerTrace() 12 | { 13 | Levels = new List(); 14 | } 15 | 16 | public override string ToString() 17 | { 18 | string result = ""; 19 | 20 | if (!Levels.Any()) 21 | { 22 | return result; 23 | } 24 | 25 | // Apply padding to the output so it looks neat and tidy 26 | var largestAddressLength = Levels.Select(traceLevel => $"{traceLevel.Address:X}".Length).OrderByDescending(length => length).First(); 27 | var largestReadResultLength = Levels.Select(traceLevel => $"{traceLevel.ReadResult:X}".Length).OrderByDescending(length => length).First(); 28 | var largestOffsetLength = Levels.Select(traceLevel => $"{traceLevel.Offset:X}".Length).OrderByDescending(length => length).First(); 29 | var largestResultLength = Levels.Select(traceLevel => $"{traceLevel.Result:X}".Length).OrderByDescending(length => length).First(); 30 | 31 | foreach (var traceLevel in Levels) 32 | { 33 | string addressString = $"{traceLevel.Address:X}".PadLeft(largestAddressLength); 34 | string readResultString = $"{traceLevel.ReadResult:X}".PadLeft(largestReadResultLength); 35 | string offsetString = $"{traceLevel.Offset:X}".PadLeft(largestOffsetLength); 36 | string resultString = $"{traceLevel.Result:X}".PadLeft(largestResultLength); 37 | 38 | result += $"{addressString} -> {readResultString} + {offsetString} = {resultString}"; 39 | 40 | if (traceLevel != Levels.Last()) 41 | { 42 | result += "\r\n"; 43 | } 44 | } 45 | 46 | return result; 47 | } 48 | 49 | public override bool Equals(Object obj) 50 | { 51 | if ((obj == null) || !this.GetType().Equals(obj.GetType())) 52 | { 53 | return false; 54 | } 55 | else 56 | { 57 | var other = obj as PointerTrace; 58 | 59 | if (Levels.Count != other.Levels.Count) 60 | { 61 | return false; 62 | } 63 | 64 | for (int index = 0; index < Levels.Count; ++index) 65 | { 66 | if (!Levels[index].Equals(other.Levels[index])) 67 | { 68 | return false; 69 | } 70 | } 71 | 72 | return true; 73 | } 74 | } 75 | 76 | // Generated with Quick Action 77 | public override int GetHashCode() 78 | { 79 | return -653240011 + EqualityComparer>.Default.GetHashCode(Levels); 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /SmartHunter/Core/PointerTraceLevel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SmartHunter.Core.Helpers 4 | { 5 | public class PointerTraceLevel 6 | { 7 | public ulong Address { get; private set; } 8 | public ulong ReadResult { get; private set; } 9 | public long Offset { get; private set; } 10 | public ulong Result { get; private set; } 11 | 12 | public PointerTraceLevel(ulong address, ulong readResult, long offset, ulong result) 13 | { 14 | Address = address; 15 | ReadResult = readResult; 16 | Offset = offset; 17 | Result = result; 18 | } 19 | 20 | public override bool Equals(Object obj) 21 | { 22 | if ((obj == null) || !this.GetType().Equals(obj.GetType())) 23 | { 24 | return false; 25 | } 26 | else 27 | { 28 | var other = obj as PointerTraceLevel; 29 | 30 | return Address == other.Address 31 | && ReadResult == other.ReadResult 32 | && Offset == other.Offset 33 | && Result == other.Result; 34 | } 35 | } 36 | 37 | // Generated with Quick Action 38 | public override int GetHashCode() 39 | { 40 | var hashCode = 1237761341; 41 | hashCode = hashCode * -1521134295 + Address.GetHashCode(); 42 | hashCode = hashCode * -1521134295 + ReadResult.GetHashCode(); 43 | hashCode = hashCode * -1521134295 + Offset.GetHashCode(); 44 | hashCode = hashCode * -1521134295 + Result.GetHashCode(); 45 | return hashCode; 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /SmartHunter/Core/Setting.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace SmartHunter.Core 4 | { 5 | public class Setting 6 | { 7 | public bool Value { get; set; } 8 | public string Name { get; } 9 | public string Description { get; } 10 | public ListSubSettings { get; } 11 | public Command TriggerAction { get; } 12 | public Setting(bool value, string name, string description, Command action = null) 13 | { 14 | Value = value; 15 | Name = name; 16 | Description = description; 17 | SubSettings = new List(); 18 | TriggerAction = action; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /SmartHunter/Core/StateMachine.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | 5 | namespace SmartHunter.Core 6 | { 7 | public class StateMachine 8 | { 9 | public class Transition 10 | { 11 | public T State { get; private set; } 12 | public Func Condition { get; private set; } 13 | public Action Begin { get; private set; } 14 | 15 | public Transition(T state, Func condition, Action begin) 16 | { 17 | State = state; 18 | Condition = condition; 19 | Begin = begin; 20 | } 21 | } 22 | 23 | public class StateData 24 | { 25 | public Action Update { get; private set; } 26 | public Transition[] Transitions { get; private set; } 27 | 28 | public StateData(Action update, Transition[] transitions) 29 | { 30 | Update = update; 31 | Transitions = transitions; 32 | } 33 | } 34 | 35 | Dictionary m_States; 36 | Stopwatch m_Stopwatch; 37 | 38 | public T State { get; private set; } 39 | 40 | public StateMachine() 41 | { 42 | m_States = new Dictionary(); 43 | m_Stopwatch = new Stopwatch(); 44 | m_Stopwatch.Start(); 45 | } 46 | 47 | public void Add(T state, StateData data) 48 | { 49 | m_States[state] = data; 50 | } 51 | 52 | public void Update() 53 | { 54 | if (m_States.TryGetValue(State, out var data)) 55 | { 56 | bool hasTransitioned = false; 57 | 58 | if (data.Transitions != null) 59 | { 60 | foreach (var transition in data.Transitions) 61 | { 62 | if (transition.Condition()) 63 | { 64 | m_Stopwatch.Stop(); 65 | Log.WriteLine($"State Machine: {State.ToString()} ({m_Stopwatch.ElapsedMilliseconds} ms) > {transition.State.ToString()}"); 66 | m_Stopwatch.Restart(); 67 | 68 | State = transition.State; 69 | transition.Begin?.Invoke(); 70 | hasTransitioned = true; 71 | 72 | break; 73 | } 74 | } 75 | } 76 | 77 | if (!hasTransitioned) 78 | { 79 | data.Update?.Invoke(); 80 | } 81 | } 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /SmartHunter/Core/ThreadedMemoryScan.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.Linq; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | using SmartHunter.Core.Helpers; 9 | 10 | namespace SmartHunter.Core 11 | { 12 | public class ThreadedMemoryScan 13 | { 14 | public class Result 15 | { 16 | public AddressRange AddressRange { get; private set; } 17 | public List Matches { get; private set; } 18 | public float ExecutionMilliseconds { get { return m_Stopwatch.ElapsedMilliseconds; } } 19 | 20 | Stopwatch m_Stopwatch; 21 | 22 | public Result(AddressRange addressRange) 23 | { 24 | AddressRange = addressRange; 25 | Matches = new List(); 26 | 27 | m_Stopwatch = new Stopwatch(); 28 | m_Stopwatch.Start(); 29 | } 30 | 31 | public void Complete() 32 | { 33 | m_Stopwatch.Stop(); 34 | } 35 | } 36 | 37 | public class CompletedEventArgs : EventArgs 38 | { 39 | public List Results { get; private set; } 40 | 41 | public ulong FirstMatch 42 | { 43 | get 44 | { 45 | return Results.OrderBy(result => result.AddressRange.Start).SelectMany(result => result.Matches).FirstOrDefault(); 46 | } 47 | } 48 | 49 | public CompletedEventArgs(List results) 50 | { 51 | Results = results; 52 | } 53 | } 54 | 55 | class TaskData 56 | { 57 | public CancellationTokenSource CancellationTokenSource { get; private set; } 58 | public Result Result { get; private set; } 59 | 60 | public TaskData(CancellationTokenSource cancellationTokenSource, AddressRange addressRange) 61 | { 62 | CancellationTokenSource = cancellationTokenSource; 63 | Result = new Result(addressRange); 64 | } 65 | } 66 | 67 | public event EventHandler Completed; 68 | 69 | ConcurrentDictionary>, TaskData> m_Tasks; 70 | Stopwatch m_Stopwatch; 71 | 72 | public Process Process { get; private set; } 73 | public BytePattern Pattern { get; private set; } 74 | public bool StopAfterFirst { get; private set; } 75 | 76 | public bool HasCompleted { get; private set; } 77 | public float ExecutionMilliseconds { get { return m_Stopwatch.ElapsedMilliseconds; } } 78 | 79 | public List Results 80 | { 81 | get 82 | { 83 | List results = new List(); 84 | lock (m_Tasks) 85 | { 86 | results = m_Tasks.Select(task => task.Value.Result).ToList(); 87 | } 88 | 89 | return results; 90 | } 91 | } 92 | 93 | public ThreadedMemoryScan(Process process, BytePattern pattern, AddressRange addressRange, bool stopAfterFirst, int threads = 2) 94 | { 95 | Process = process; 96 | Pattern = pattern; 97 | StopAfterFirst = stopAfterFirst; 98 | 99 | m_Tasks = new ConcurrentDictionary>, TaskData>(); 100 | 101 | m_Stopwatch = new Stopwatch(); 102 | m_Stopwatch.Start(); 103 | 104 | var addressRangeDivisions = MemoryHelper.DivideAddressRange(addressRange, threads); 105 | foreach (var addressRangeDivision in addressRangeDivisions) 106 | { 107 | AddScanTask(addressRangeDivision); 108 | } 109 | } 110 | 111 | void AddScanTask(AddressRange addressRange) 112 | { 113 | var cancellationTokenSource = new CancellationTokenSource(); 114 | 115 | Task> task = Task.Run(() => 116 | { 117 | try 118 | { 119 | return MemoryHelper.FindPatternAddresses(Process, addressRange, Pattern, StopAfterFirst); 120 | } 121 | catch (TaskCanceledException) 122 | { 123 | } 124 | catch (Exception ex) 125 | { 126 | Log.WriteException(ex); 127 | } 128 | 129 | return null as List; 130 | }, cancellationTokenSource.Token); 131 | 132 | task.ContinueWith((continuingTask) => 133 | { 134 | try 135 | { 136 | TaskData data = null; 137 | lock (m_Tasks) 138 | { 139 | m_Tasks.TryGetValue(continuingTask, out data); 140 | } 141 | 142 | if (data == null) 143 | { 144 | return; 145 | } 146 | 147 | data.Result.Complete(); 148 | 149 | if (HasCompleted) 150 | { 151 | return; 152 | } 153 | 154 | if (continuingTask.Result != null && continuingTask.Result.Any()) 155 | { 156 | Pattern.MatchedAddresses.AddRange(continuingTask.Result.Select(address => address)); 157 | data.Result.Matches.AddRange(continuingTask.Result); 158 | 159 | // Cancel all other threads and complete the scan because we needed only 1 result 160 | if (StopAfterFirst) 161 | { 162 | TryCancel(); 163 | } 164 | } 165 | 166 | // Complete the scan if this is the last thread to finish 167 | if (!HasCompleted) 168 | { 169 | int completedTaskCount = 0; 170 | lock (m_Tasks) 171 | { 172 | completedTaskCount = m_Tasks.Select(t => t.Key).Where(thisTask => thisTask.IsCompleted).Count(); 173 | } 174 | 175 | if (completedTaskCount == m_Tasks.Count) 176 | { 177 | TryComplete(); 178 | } 179 | } 180 | } 181 | catch (TaskCanceledException) 182 | { 183 | } 184 | catch (Exception ex) 185 | { 186 | Log.WriteException(ex); 187 | } 188 | }); 189 | 190 | lock (m_Tasks) 191 | { 192 | m_Tasks.TryAdd(task, new TaskData(cancellationTokenSource, addressRange)); 193 | } 194 | } 195 | 196 | public void TryCancel() 197 | { 198 | foreach (var memoryTaskData in m_Tasks.Values.ToList()) 199 | { 200 | memoryTaskData.CancellationTokenSource.Cancel(); 201 | } 202 | 203 | TryComplete(); 204 | } 205 | 206 | void TryComplete() 207 | { 208 | m_Stopwatch.Stop(); 209 | 210 | if (!HasCompleted) 211 | { 212 | HasCompleted = true; 213 | 214 | if (Completed != null) 215 | { 216 | Completed(this, new CompletedEventArgs(Results)); 217 | } 218 | } 219 | } 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /SmartHunter/Core/Windows/WidgetWindow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows; 3 | using System.Windows.Input; 4 | using SmartHunter.Core.Data; 5 | 6 | namespace SmartHunter.Core.Windows 7 | { 8 | public abstract class WidgetWindow : Window 9 | { 10 | public Widget Widget { get; private set; } 11 | 12 | protected abstract float ScaleMax { get; } 13 | protected abstract float ScaleMin { get; } 14 | protected abstract float ScaleStep { get; } 15 | 16 | public WidgetWindow(Widget widget) 17 | { 18 | Widget = widget; 19 | } 20 | 21 | protected void WidgetWindow_MouseDown(object sender, MouseButtonEventArgs e) 22 | { 23 | if (e.ChangedButton == MouseButton.Left) 24 | { 25 | DragMove(); 26 | } 27 | } 28 | 29 | protected void WidgetWindow_MouseWheel(object sender, MouseWheelEventArgs e) 30 | { 31 | int direction = 0; 32 | if (e.Delta > 0) 33 | { 34 | direction = 1; 35 | } 36 | else if (e.Delta < 0) 37 | { 38 | direction = -1; 39 | } 40 | 41 | float currentScale = Widget.Scale; 42 | currentScale += ScaleStep * direction; 43 | Widget.Scale = Math.Min(Math.Max(currentScale, ScaleMin), ScaleMax); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /SmartHunter/Game/Config/BytePatternConfig.cs: -------------------------------------------------------------------------------- 1 | using SmartHunter.Core; 2 | 3 | namespace SmartHunter.Game.Config 4 | { 5 | public class BytePatternConfig 6 | { 7 | public string Name; 8 | public string PatternString; 9 | public string LastResultAddress; 10 | 11 | public BytePatternConfig(string name, string patternString, string lastResultAddress = "") 12 | { 13 | Name = name; 14 | PatternString = patternString; 15 | LastResultAddress = lastResultAddress; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /SmartHunter/Game/Config/CrownPreset.cs: -------------------------------------------------------------------------------- 1 | namespace SmartHunter.Game.Config 2 | { 3 | public enum CrownPreset 4 | { 5 | Standard, 6 | Alternate, 7 | Savage, 8 | Rajang 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /SmartHunter/Game/Config/DebugConfig.cs: -------------------------------------------------------------------------------- 1 | namespace SmartHunter.Game.Config 2 | { 3 | public class DebugConfig 4 | { 5 | public bool UseInternalSkin = false; 6 | public bool UseSampleData = false; 7 | public bool TraceUniquePointers = false; 8 | public bool ShowWeirdRemovableParts = false; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /SmartHunter/Game/Config/DebugWidgetConfig.cs: -------------------------------------------------------------------------------- 1 | using SmartHunter.Core.Config; 2 | 3 | namespace SmartHunter.Game.Config 4 | { 5 | public class DebugWidgetConfig : WidgetConfig 6 | { 7 | public DebugWidgetConfig(float x, float y) : base(x, y) 8 | { 9 | IsVisible = false; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /SmartHunter/Game/Config/MainConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Windows.Input; 3 | using SmartHunter.Core.Config; 4 | 5 | namespace SmartHunter.Game.Config 6 | { 7 | public class MainConfig 8 | { 9 | public string LocalizationFileName = "en-US.json"; 10 | public string SkinFileName = "Default.xaml"; 11 | public string MonsterDataFileName = "MonsterData.json"; 12 | public string PlayerDataFileName = "PlayerData.json"; 13 | public string MemoryFileName = "Memory.json"; 14 | 15 | public bool ShutdownWhenProcessExits = false; 16 | public bool UseCustomData = false; 17 | public bool AutomaticallyCheckAndDownloadUpdates = true; 18 | 19 | public OverlayConfig Overlay = new OverlayConfig(); 20 | 21 | [PreserveCollectionIntegrity] 22 | public Dictionary Keybinds = new Dictionary() 23 | { 24 | { InputControl.ManipulateWidget, Key.LeftAlt }, 25 | { InputControl.HideWidgets, Key.F1 }, 26 | { InputControl.ToggleWidgests, Key.RightCtrl }, 27 | }; 28 | 29 | public DebugConfig Debug = new DebugConfig(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /SmartHunter/Game/Config/MemoryConditionConfig.cs: -------------------------------------------------------------------------------- 1 | namespace SmartHunter.Game.Config 2 | { 3 | public class MemoryConditionConfig 4 | { 5 | public string[] Offsets; 6 | public byte? ByteValue; 7 | public int? IntValue; 8 | public string StringRegexValue; 9 | 10 | public MemoryConditionConfig() 11 | { 12 | } 13 | 14 | public MemoryConditionConfig(byte byteValue, params string[] offsets) 15 | { 16 | Offsets = offsets; 17 | ByteValue = byteValue; 18 | } 19 | 20 | public MemoryConditionConfig(int intValue, params string[] offsets) 21 | { 22 | Offsets = offsets; 23 | IntValue = intValue; 24 | } 25 | 26 | public MemoryConditionConfig(string stringRegexValue, params string[] offsets) 27 | { 28 | Offsets = offsets; 29 | StringRegexValue = stringRegexValue; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /SmartHunter/Game/Config/MemoryConfig.cs: -------------------------------------------------------------------------------- 1 | using SmartHunter.Core; 2 | 3 | namespace SmartHunter.Game.Config 4 | { 5 | public class MemoryConfig 6 | { 7 | public string ProcessName = "MonsterHunterWorld"; 8 | 9 | public int ThreadsPerScan = 1; 10 | 11 | public BytePatternConfig CurrentPlayerNamePattern = new BytePatternConfig( 12 | "CurrentPlayerNamePattern", 13 | "48 8B 0D ?? ?? ?? ?? 48 8D 55 ?? 45 31 C9 41 89 C0 E8" 14 | ); 15 | 16 | public BytePatternConfig CurrentWeaponPattern = new BytePatternConfig( 17 | "CurrentWeaponPattern", 18 | "48 8B 0D ?? ?? ?? ?? 4C 8D 45 ?? 48 8D 97 ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 8B D8 48 85 C0 " 19 | ); 20 | 21 | public BytePatternConfig PlayerDamagePattern = new BytePatternConfig( 22 | "PlayerDamagePattern", 23 | "48 8B 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 8B D8 48 85 C0 75 04 33 C9" 24 | ); 25 | 26 | public BytePatternConfig PlayerNamePattern = new BytePatternConfig( 27 | "PlayerNamePattern", 28 | "48 8B 0D ?? ?? ?? ?? 48 8D 54 24 38 C6 44 24 20 00 E8 ?? ?? ?? ?? 48 8B 5C 24 70 48 8B 7C 24 60 48 83 C4 68 C3" 29 | ); 30 | 31 | public BytePatternConfig MonsterPattern = new BytePatternConfig( 32 | "MonsterPattern", 33 | "48 8B 0D ?? ?? ?? ?? B2 01 E8 ?? ?? ?? ?? C6 83 ?? ?? ?? ?? ?? 48 8B 0D" 34 | ); 35 | 36 | public BytePatternConfig PlayerBuffPattern = new BytePatternConfig( 37 | "PlayerBuffPattern", 38 | "48 8B 05 ?? ?? ?? ?? 41 8B 94 00 ?? ?? ?? ?? 89 57 ??" 39 | ); 40 | 41 | public BytePatternConfig SelectedMonsterPattern = new BytePatternConfig( 42 | "SelectedMonsterPattern", 43 | "48 8B 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 8B 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 83 A0 ?? ?? ?? ?? ?? C6 43 ?? ??" 44 | ); 45 | 46 | public BytePatternConfig LobbyStatusPattern = new BytePatternConfig( 47 | "LobbyStatusPattern", 48 | "48 8B 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 8B 4E ?? F3 0F 10 86 ?? ?? ?? ?? F3 0F 58 86 ?? ?? ?? ?? F3 0F 11 86 ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 8B 4E ??" 49 | ); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /SmartHunter/Game/Config/MemorySource.cs: -------------------------------------------------------------------------------- 1 | namespace SmartHunter.Game.Config 2 | { 3 | public enum MemorySource 4 | { 5 | Base, 6 | Equipment, 7 | Weapon, 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /SmartHunter/Game/Config/MonsterConfig.cs: -------------------------------------------------------------------------------- 1 | // Monster Size Differences 2 | // https://docs.google.com/spreadsheets/d/1zoRCvF4qKUZCgMGQw3vdtjVS-laX7-px6k1oPCJMg5E 3 | 4 | // Monster Crown Sizes 5 | // https://docs.google.com/spreadsheets/d/1w4puqT7mlzG-Zfh1Ztgk0a35vmba-h-HW2o1G00qFA8 6 | 7 | namespace SmartHunter.Game.Config 8 | { 9 | public class MonsterConfig 10 | { 11 | public string NameStringId; 12 | public MonsterPartConfig[] Parts; 13 | public float BaseSize; 14 | public float ScaleModifier = 1f; 15 | public MonsterCrownConfig Crowns; 16 | public bool isElder = false; 17 | 18 | public MonsterConfig(string nameStringId, MonsterPartConfig[] parts, float baseSize, MonsterCrownConfig crowns, bool elder = false) 19 | { 20 | NameStringId = nameStringId; 21 | Parts = parts; 22 | BaseSize = baseSize; 23 | Crowns = crowns; 24 | isElder = elder; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /SmartHunter/Game/Config/MonsterCrownConfig.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | namespace SmartHunter.Game.Config 4 | { 5 | public class MonsterCrownConfig 6 | { 7 | public float Mini; 8 | public float Silver; 9 | public float Gold; 10 | 11 | public MonsterCrownConfig(CrownPreset crownPreset) 12 | { 13 | switch (crownPreset) 14 | { 15 | case CrownPreset.Standard: 16 | Mini = 0.9f; 17 | Silver = 1.15f; 18 | Gold = 1.23f; 19 | break; 20 | case CrownPreset.Alternate: 21 | Mini = 0.9f; 22 | Silver = 1.1f; 23 | Gold = 1.2f; 24 | break; 25 | case CrownPreset.Savage: 26 | Mini = 0.99f; 27 | Silver = 1.14f; 28 | Gold = 1.2f; 29 | break; 30 | case CrownPreset.Rajang: 31 | Mini = 0.9f; 32 | Silver = 1.11f; 33 | Gold = 1.18f; 34 | break; 35 | default: 36 | throw new InvalidEnumArgumentException(nameof(crownPreset), (int)crownPreset, typeof(CrownPreset)); 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /SmartHunter/Game/Config/MonsterPartConfig.cs: -------------------------------------------------------------------------------- 1 | namespace SmartHunter.Game.Config 2 | { 3 | public class MonsterPartConfig 4 | { 5 | public string GroupId; 6 | public string StringId; 7 | public bool IsRemovable; 8 | 9 | public MonsterPartConfig(string groupId, string stringId, bool isRemovable = false) 10 | { 11 | GroupId = groupId; 12 | StringId = stringId; 13 | IsRemovable = isRemovable; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /SmartHunter/Game/Config/MonsterStatusEffectConfig.cs: -------------------------------------------------------------------------------- 1 | namespace SmartHunter.Game.Config 2 | { 3 | public class MonsterStatusEffectConfig 4 | { 5 | public string GroupId; 6 | public string NameStringId; 7 | 8 | public bool InvertBuildup; 9 | public bool InvertDuration; 10 | 11 | public MonsterStatusEffectConfig(string groupId, string nameStringId, bool invertBuildup = false, bool invertDuration = true) 12 | { 13 | GroupId = groupId; 14 | NameStringId = nameStringId; 15 | 16 | InvertBuildup = invertBuildup; 17 | InvertDuration = invertDuration; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /SmartHunter/Game/Config/MonsterWidgetConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Text.RegularExpressions; 2 | using SmartHunter.Core.Config; 3 | 4 | namespace SmartHunter.Game.Config 5 | { 6 | public class MonsterWidgetConfig : WidgetConfig 7 | { 8 | // em[0-9]|ems[0-9]|gm[0-9] 9 | public string IncludeMonsterIdRegex = "em[0-9]"; 10 | public string IncludePartGroupIdRegex = ".*"; 11 | public string IncludeStatusEffectGroupIdRegex = ".*"; 12 | public bool ShowUnchangedMonsters = true; 13 | public float HideMonstersAfterSeconds = 999f; 14 | public bool ShowUnchangedParts = false; 15 | public float HidePartsAfterSeconds = 12f; 16 | public bool ShowUnchangedStatusEffects = false; 17 | public float HideStatusEffectsAfterSeconds = 12f; 18 | 19 | public bool ShowSize = false; 20 | public bool ShowCrown = true; 21 | public bool ShowBars = true; 22 | public bool ShowNumbers = true; 23 | public bool ShowPercents = false; 24 | public bool UseAnimations = false; 25 | public bool ShowOnlySelectedMonster = false; 26 | 27 | public MonsterWidgetConfig(float x, float y) : base(x, y) 28 | { 29 | } 30 | 31 | public bool MatchIncludeMonsterIdRegex(string monsterId) 32 | { 33 | return new Regex(IncludeMonsterIdRegex).IsMatch(monsterId); 34 | } 35 | 36 | public bool MatchIncludePartGroupIdRegex(string groupId) 37 | { 38 | return new Regex(IncludePartGroupIdRegex).IsMatch(groupId); 39 | } 40 | 41 | public bool MatchIncludeStatusEffectGroupIdRegex(string groupId) 42 | { 43 | return new Regex(IncludeStatusEffectGroupIdRegex).IsMatch(groupId); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /SmartHunter/Game/Config/OverlayConfig.cs: -------------------------------------------------------------------------------- 1 | namespace SmartHunter.Game.Config 2 | { 3 | public class OverlayConfig 4 | { 5 | public float ScaleMin = 0.5f; 6 | public float ScaleMax = 2f; 7 | public float ScaleStep = 0.1f; 8 | public bool HideWhenGameWindowIsInactive = false; 9 | public int UpdatesPerSecond = 20; 10 | 11 | public TeamWidgetConfig TeamWidget = new TeamWidgetConfig(220, 220); 12 | public MonsterWidgetConfig MonsterWidget = new MonsterWidgetConfig(320, 120); 13 | public PlayerWidgetConfig PlayerWidget = new PlayerWidgetConfig(120, 320); 14 | public DebugWidgetConfig DebugWidget = new DebugWidgetConfig(120, 320); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /SmartHunter/Game/Config/PlayerWidgetConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Text.RegularExpressions; 2 | using SmartHunter.Core.Config; 3 | 4 | namespace SmartHunter.Game.Config 5 | { 6 | public class PlayerWidgetConfig : WidgetConfig 7 | { 8 | public string IncludeStatusEffectGroupIdRegex = ".*"; 9 | 10 | public PlayerWidgetConfig(float x, float y) : base(x, y) 11 | { 12 | } 13 | 14 | public bool MatchIncludeStatusEffectGroupIdRegex(string groupId) 15 | { 16 | return new Regex(IncludeStatusEffectGroupIdRegex).IsMatch(groupId); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /SmartHunter/Game/Config/StatusEffectConfig.cs: -------------------------------------------------------------------------------- 1 | using SmartHunter.Game.Data; 2 | 3 | namespace SmartHunter.Game.Config 4 | { 5 | public partial class StatusEffectConfig 6 | { 7 | 8 | public string GroupId; 9 | public string NameStringId; 10 | public string TimerOffset; 11 | public MemorySource Source; 12 | public MemoryConditionConfig[] Conditions; 13 | public WeaponType WeaponType; 14 | 15 | public StatusEffectConfig() { } 16 | 17 | public StatusEffectConfig(string groupId, string nameStringId, MemorySource source, string timerOffset, params MemoryConditionConfig[] conditions) 18 | { 19 | GroupId = groupId; 20 | NameStringId = nameStringId; 21 | Source = source; 22 | TimerOffset = timerOffset; 23 | Conditions = conditions; 24 | } 25 | 26 | public StatusEffectConfig(string groupId, string nameStringId, MemorySource source, string timerOffset, WeaponType weaponType) 27 | { 28 | GroupId = groupId; 29 | NameStringId = nameStringId; 30 | Source = source; 31 | TimerOffset = timerOffset; 32 | WeaponType = weaponType; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /SmartHunter/Game/Config/TeamWidgetConfig.cs: -------------------------------------------------------------------------------- 1 | using SmartHunter.Core.Config; 2 | 3 | namespace SmartHunter.Game.Config 4 | { 5 | public class TeamWidgetConfig : WidgetConfig 6 | { 7 | public bool DontShowIfAlone = false; 8 | public bool ShowBars = true; 9 | public bool ShowNumbers = true; 10 | public bool ShowPercents = true; 11 | 12 | public TeamWidgetConfig(float x, float y) : base(x, y) 13 | { 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /SmartHunter/Game/Data/Game.cs: -------------------------------------------------------------------------------- 1 | using SmartHunter.Core.Data; 2 | 3 | namespace SmartHunter.Game.Data 4 | { 5 | public class Game : Bindable 6 | { 7 | public bool IsValid = false; 8 | 9 | string m_SessionHostPlayerName = ""; 10 | public string SessionHostPlayerName 11 | { 12 | get { return m_SessionHostPlayerName; } 13 | set 14 | { 15 | if (SetProperty(ref m_SessionHostPlayerName, value)) 16 | { 17 | NotifyPropertyChanged(nameof(SessionHostPlayerName)); 18 | } 19 | } 20 | } 21 | 22 | string m_LobbyHostPlayerName = ""; 23 | public string LobbyHostPlayerName 24 | { 25 | get { return m_LobbyHostPlayerName; } 26 | set 27 | { 28 | if (SetProperty(ref m_LobbyHostPlayerName, value)) 29 | { 30 | NotifyPropertyChanged(nameof(LobbyHostPlayerName)); 31 | } 32 | } 33 | } 34 | 35 | string m_SessionID = ""; 36 | public string SessionID 37 | { 38 | get { return m_SessionID; } 39 | set 40 | { 41 | if (SetProperty(ref m_SessionID, value)) 42 | { 43 | NotifyPropertyChanged(nameof(SessionID)); 44 | } 45 | } 46 | } 47 | 48 | string m_LobbyID = ""; 49 | public string LobbyID 50 | { 51 | get { return m_LobbyID; } 52 | set 53 | { 54 | if (SetProperty(ref m_LobbyID, value)) 55 | { 56 | NotifyPropertyChanged(nameof(LobbyID)); 57 | } 58 | } 59 | } 60 | 61 | string m_CurrentPlayerName = ""; 62 | public string CurrentPlayerName 63 | { 64 | get { return m_CurrentPlayerName; } 65 | set 66 | { 67 | if (SetProperty(ref m_CurrentPlayerName, value)) 68 | { 69 | NotifyPropertyChanged(nameof(CurrentPlayerName)); 70 | } 71 | } 72 | } 73 | 74 | string m_CurrentWeaponString = ""; 75 | public string CurrentWeaponString 76 | { 77 | get { return m_CurrentWeaponString; } 78 | set 79 | { 80 | if (SetProperty(ref m_CurrentWeaponString, value)) 81 | { 82 | NotifyPropertyChanged(nameof(CurrentWeaponString)); 83 | NotifyPropertyChanged(nameof(EquippedWeaponType)); 84 | } 85 | } 86 | } 87 | public WeaponType EquippedWeaponType 88 | { 89 | get 90 | { 91 | return CurrentEquippedWeaponType(); 92 | } 93 | } 94 | 95 | public int LobbyPlayerCount 96 | { 97 | get 98 | { 99 | return ViewModels.OverlayViewModel.Instance.TeamWidget.Context.Players.Count; 100 | } 101 | } 102 | 103 | public bool IsPlayerOnline() 104 | { 105 | return SessionID.Length > 0; 106 | } 107 | 108 | public bool IsPlayerInLobby() 109 | { 110 | return LobbyID.Length > 0; 111 | } 112 | 113 | public bool IsCurrentPlayerSessionHost() 114 | { 115 | return CurrentPlayerName.Equals(SessionHostPlayerName) || SessionHostPlayerName.Length == 0 || CurrentPlayerName.Length == 0; 116 | } 117 | 118 | public bool IsCurrentPlayerLobbyHost() 119 | { 120 | return CurrentPlayerName.Equals(LobbyHostPlayerName) || LobbyHostPlayerName.Length == 0 || CurrentPlayerName.Length == 0; 121 | } 122 | 123 | public bool IsPlayerAlone() 124 | { 125 | return LobbyPlayerCount == 1 || !IsPlayerOnline(); 126 | } 127 | 128 | public WeaponType CurrentEquippedWeaponType() 129 | { 130 | if (CurrentWeaponString.Equals("")) 131 | { 132 | return WeaponType.NO_WEAPON; 133 | } 134 | if (CurrentWeaponString.Contains("wp11") || CurrentWeaponString.Contains("bow")) 135 | { 136 | return WeaponType.BOW; 137 | } 138 | if (CurrentWeaponString.Contains("wp09") || CurrentWeaponString.Contains("caxe")) 139 | { 140 | return WeaponType.CHARGE_BLADE; 141 | } 142 | if (CurrentWeaponString.Contains("wp07") || CurrentWeaponString.Contains("gun")) 143 | { 144 | return WeaponType.GUNLANCE; 145 | } 146 | if (CurrentWeaponString.Contains("wp04") || CurrentWeaponString.Contains("ham")) 147 | { 148 | return WeaponType.HAMMER; 149 | } 150 | if (CurrentWeaponString.Contains("wp12") || CurrentWeaponString.Contains("hbg")) 151 | { 152 | return WeaponType.HEAVY_BOWGUN; 153 | } 154 | if (CurrentWeaponString.Contains("wp05") || CurrentWeaponString.Contains("hue")) 155 | { 156 | return WeaponType.HUNTING_HORN; 157 | } 158 | if (CurrentWeaponString.Contains("wp06") || CurrentWeaponString.Contains("lan")) 159 | { 160 | return WeaponType.LANCE; 161 | } 162 | if (CurrentWeaponString.Contains("wp13") || CurrentWeaponString.Contains("lbg")) 163 | { 164 | return WeaponType.LIGHT_BOWGUN; 165 | } 166 | if (CurrentWeaponString.Contains("wp10") || CurrentWeaponString.Contains("rod")) 167 | { 168 | return WeaponType.INSECT_GLAIVE; 169 | } 170 | if (CurrentWeaponString.Contains("mus")) 171 | { 172 | return WeaponType.KINSECT; 173 | } 174 | if (CurrentWeaponString.Contains("wp01") || CurrentWeaponString.Contains("one")) 175 | { 176 | return WeaponType.SWORD_AND_SHIELD; 177 | } 178 | if (CurrentWeaponString.Contains("wp08") || CurrentWeaponString.Contains("saxe")) 179 | { 180 | return WeaponType.SWITCH_AXE; 181 | } 182 | if (CurrentWeaponString.Contains("wp02") || CurrentWeaponString.Contains("sou")) 183 | { 184 | return WeaponType.DUAL_BLADES; 185 | } 186 | if (CurrentWeaponString.Contains("wp03") || CurrentWeaponString.Contains("swo")) 187 | { 188 | return WeaponType.LONG_SWORD; 189 | } 190 | if (CurrentWeaponString.Contains("wp00") || CurrentWeaponString.Contains("two")) 191 | { 192 | return WeaponType.GREAT_SWORD; 193 | } 194 | if (CurrentWeaponString.Contains("slg")) 195 | { 196 | return WeaponType.SLINGER; 197 | } 198 | return WeaponType.WEAPON_UNKNOWN; 199 | } 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /SmartHunter/Game/Data/Monster.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.ObjectModel; 3 | using System.Linq; 4 | using SmartHunter.Core; 5 | using SmartHunter.Core.Data; 6 | using SmartHunter.Game.Helpers; 7 | 8 | namespace SmartHunter.Game.Data 9 | { 10 | public class Monster : TimedVisibility 11 | { 12 | public ulong Address { get; private set; } 13 | 14 | string m_Id; 15 | public string Id 16 | { 17 | get { return m_Id; } 18 | set 19 | { 20 | if (SetProperty(ref m_Id, value)) 21 | { 22 | NotifyPropertyChanged(nameof(IsVisible)); 23 | UpdateLocalization(); 24 | } 25 | } 26 | } 27 | 28 | public bool isElder => ConfigHelper.MonsterData.Values.Monsters.TryGetValue(Id, out var config) ? config.isElder : false; 29 | 30 | public string Name => LocalizationHelper.GetMonsterName(Id); 31 | 32 | float m_SizeScale; 33 | public float SizeScale 34 | { 35 | get => m_SizeScale; 36 | set 37 | { 38 | if (SetProperty(ref m_SizeScale, value)) 39 | { 40 | NotifyPropertyChanged(nameof(ModifiedSizeScale)); 41 | NotifyPropertyChanged(nameof(Size)); 42 | NotifyPropertyChanged(nameof(Crown)); 43 | } 44 | } 45 | } 46 | 47 | float m_ScaleModifier; 48 | public float ScaleModifier 49 | { 50 | get => m_ScaleModifier; 51 | set 52 | { 53 | if (SetProperty(ref m_ScaleModifier, value)) 54 | { 55 | NotifyPropertyChanged(nameof(ModifiedSizeScale)); 56 | NotifyPropertyChanged(nameof(Size)); 57 | NotifyPropertyChanged(nameof(Crown)); 58 | } 59 | } 60 | } 61 | 62 | public float ModifiedSizeScale => (float)Math.Round((decimal)(SizeScale / ScaleModifier), 2); 63 | 64 | public float Size => ConfigHelper.MonsterData.Values.Monsters.TryGetValue(Id, out var config) ? config.BaseSize * ModifiedSizeScale : 0; 65 | 66 | public MonsterCrown Crown 67 | { 68 | get 69 | { 70 | if (ConfigHelper.MonsterData.Values.Monsters.TryGetValue(Id, out var config) && config.Crowns != null) 71 | { 72 | var modifiedSizeScale = ModifiedSizeScale; 73 | 74 | if (modifiedSizeScale <= config.Crowns.Mini) 75 | { 76 | return MonsterCrown.Mini; 77 | } 78 | else if (modifiedSizeScale >= config.Crowns.Gold) 79 | { 80 | return MonsterCrown.Gold; 81 | } 82 | else if (modifiedSizeScale >= config.Crowns.Silver) 83 | { 84 | return MonsterCrown.Silver; 85 | } 86 | } 87 | return MonsterCrown.None; 88 | } 89 | } 90 | 91 | public Progress Health { get; private set; } 92 | public ObservableCollection Parts { get; private set; } 93 | public ObservableCollection StatusEffects { get; private set; } 94 | 95 | public bool IsVisible => IsIncluded(Id) && IsTimeVisible(ConfigHelper.Main.Values.Overlay.MonsterWidget.ShowUnchangedMonsters, ConfigHelper.Main.Values.Overlay.MonsterWidget.HideMonstersAfterSeconds); 96 | 97 | public Monster(ulong address, string id, float maxHealth, float currentHealth, float sizeScale, float scaleModifier) 98 | { 99 | Address = address; 100 | m_Id = id; 101 | Health = new Progress(maxHealth, currentHealth); 102 | m_SizeScale = sizeScale; 103 | m_ScaleModifier = scaleModifier; 104 | 105 | Parts = new ObservableCollection(); 106 | StatusEffects = new ObservableCollection(); 107 | } 108 | 109 | public MonsterPart UpdateAndGetPart(ulong address, bool isRemovable, float maxHealth, float currentHealth, int timesBrokenCount) 110 | { 111 | var part = Parts.SingleOrDefault(collectionPart => collectionPart.Address == address); 112 | if (part != null) 113 | { 114 | part.IsRemovable = isRemovable; 115 | part.Health.Max = maxHealth; 116 | part.Health.Current = currentHealth; 117 | part.TimesBrokenCount = timesBrokenCount; 118 | } 119 | else 120 | { 121 | part = new MonsterPart(this, address, isRemovable, maxHealth, currentHealth, timesBrokenCount); 122 | part.Changed += PartOrStatusEffect_Changed; 123 | 124 | Parts.Add(part); 125 | } 126 | 127 | part.NotifyPropertyChanged(nameof(MonsterPart.IsVisible)); 128 | 129 | return part; 130 | } 131 | 132 | public MonsterStatusEffect UpdateAndGetStatusEffect(ulong address, int index, float maxBuildup, float currentBuildup, float maxDuration, float currentDuration, int timesActivatedCount) 133 | { 134 | var statusEffect = StatusEffects.SingleOrDefault(collectionStatusEffect => collectionStatusEffect.Index == index); // TODO: check address??? 135 | 136 | if (statusEffect != null) 137 | { 138 | //statusEffect.Address = Address; 139 | statusEffect.Duration.Max = maxDuration; 140 | statusEffect.Duration.Current = currentDuration; 141 | statusEffect.Buildup.Max = maxBuildup; 142 | statusEffect.Buildup.Current = currentBuildup; 143 | statusEffect.TimesActivatedCount = timesActivatedCount; 144 | } 145 | else 146 | { 147 | statusEffect = new MonsterStatusEffect(this, address, index, maxBuildup, currentBuildup, maxDuration, currentDuration, timesActivatedCount); 148 | statusEffect.Changed += PartOrStatusEffect_Changed; 149 | 150 | StatusEffects.Add(statusEffect); 151 | } 152 | 153 | statusEffect.NotifyPropertyChanged(nameof(MonsterStatusEffect.IsVisible)); 154 | 155 | return statusEffect; 156 | } 157 | 158 | public void UpdateLocalization() 159 | { 160 | NotifyPropertyChanged(nameof(Name)); 161 | 162 | foreach (var part in Parts) 163 | { 164 | part.NotifyPropertyChanged(nameof(MonsterPart.Name)); 165 | } 166 | foreach (var statusEffect in StatusEffects) 167 | { 168 | statusEffect.NotifyPropertyChanged(nameof(MonsterStatusEffect.Name)); 169 | } 170 | } 171 | 172 | public static bool IsIncluded(string monsterId) => ConfigHelper.Main.Values.Overlay.MonsterWidget.MatchIncludeMonsterIdRegex(monsterId); 173 | 174 | private void PartOrStatusEffect_Changed(object sender, GenericEventArgs e) => UpdateLastChangedTime(); 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /SmartHunter/Game/Data/MonsterCrown.cs: -------------------------------------------------------------------------------- 1 | namespace SmartHunter.Game.Data 2 | { 3 | public enum MonsterCrown 4 | { 5 | None, 6 | Mini, 7 | Silver, 8 | Gold 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /SmartHunter/Game/Data/MonsterPart.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Linq; 3 | using SmartHunter.Core.Data; 4 | using SmartHunter.Game.Helpers; 5 | 6 | namespace SmartHunter.Game.Data 7 | { 8 | public class MonsterPart : TimedVisibility 9 | { 10 | Monster m_Owner; 11 | public ulong Address { get; private set; } 12 | 13 | bool m_IsRemovable; 14 | public bool IsRemovable 15 | { 16 | get { return m_IsRemovable; } 17 | set { SetProperty(ref m_IsRemovable, value); } 18 | } 19 | 20 | public Progress Health { get; private set; } 21 | 22 | int m_TimesBrokenCount; 23 | public int TimesBrokenCount 24 | { 25 | get { return m_TimesBrokenCount; } 26 | set { SetProperty(ref m_TimesBrokenCount, value); } 27 | } 28 | 29 | public string Name 30 | { 31 | get 32 | { 33 | return LocalizationHelper.GetMonsterPartName(m_Owner.Id, m_Owner.Parts.Where(part => part.IsRemovable == IsRemovable).ToList().IndexOf(this), IsRemovable); 34 | } 35 | } 36 | 37 | public string GroupId 38 | { 39 | get 40 | { 41 | return GetGroupIdFromIndex(m_Owner.Id, m_Owner.Parts.Where(part => part.IsRemovable == IsRemovable).ToList().IndexOf(this), IsRemovable); 42 | } 43 | } 44 | 45 | public bool IsVisible 46 | { 47 | get 48 | { 49 | return IsIncluded(GroupId) && IsTimeVisible(ConfigHelper.Main.Values.Overlay.MonsterWidget.ShowUnchangedParts, ConfigHelper.Main.Values.Overlay.MonsterWidget.HidePartsAfterSeconds); 50 | } 51 | } 52 | 53 | public MonsterPart(Monster owner, ulong address, bool isRemovable, float maxHealth, float currentHealth, int timesBrokenCount) 54 | { 55 | m_Owner = owner; 56 | Address = address; 57 | m_IsRemovable = isRemovable; 58 | Health = new Progress(maxHealth, currentHealth); 59 | m_TimesBrokenCount = timesBrokenCount; 60 | 61 | PropertyChanged += MonsterPart_PropertyChanged; 62 | Health.PropertyChanged += Health_PropertyChanged; 63 | } 64 | 65 | private void MonsterPart_PropertyChanged(object sender, PropertyChangedEventArgs e) 66 | { 67 | if (e.PropertyName == nameof(TimesBrokenCount)) 68 | { 69 | UpdateLastChangedTime(); 70 | } 71 | } 72 | 73 | private void Health_PropertyChanged(object sender, PropertyChangedEventArgs e) 74 | { 75 | if (e.PropertyName == nameof(Progress.Current)) 76 | { 77 | UpdateLastChangedTime(); 78 | } 79 | } 80 | 81 | public static string GetGroupIdFromIndex(string monsterId, int index, bool isRemovable) 82 | { 83 | if (ConfigHelper.MonsterData.Values.Monsters.TryGetValue(monsterId, out var monsterConfig)) 84 | { 85 | var parts = monsterConfig.Parts.Where(part => part.IsRemovable == isRemovable); 86 | if (parts.Count() > index) 87 | { 88 | return parts.ElementAt(index).GroupId; 89 | } 90 | } 91 | 92 | return ""; 93 | } 94 | 95 | public static bool IsIncluded(string groupId) 96 | { 97 | return ConfigHelper.Main.Values.Overlay.MonsterWidget.MatchIncludePartGroupIdRegex(groupId); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /SmartHunter/Game/Data/MonsterStatusEffect.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using SmartHunter.Core.Data; 3 | using SmartHunter.Game.Helpers; 4 | 5 | namespace SmartHunter.Game.Data 6 | { 7 | public class MonsterStatusEffect : TimedVisibility 8 | { 9 | Monster m_Owner; 10 | 11 | int m_Index; 12 | public int Index 13 | { 14 | get { return m_Index; } 15 | set 16 | { 17 | if (SetProperty(ref m_Index, value)) 18 | { 19 | NotifyPropertyChanged(nameof(GroupId)); 20 | NotifyPropertyChanged(nameof(Name)); 21 | NotifyPropertyChanged(nameof(IsVisible)); 22 | } 23 | } 24 | } 25 | 26 | public ulong Address; 27 | 28 | public string GroupId 29 | { 30 | get 31 | { 32 | return GetGroupIdFromIndex(Index); 33 | } 34 | } 35 | 36 | public Progress Buildup { get; private set; } 37 | public Progress Duration { get; private set; } 38 | 39 | int m_TimesActivatedCount; 40 | public int TimesActivatedCount 41 | { 42 | get { return m_TimesActivatedCount; } 43 | set { SetProperty(ref m_TimesActivatedCount, value); } 44 | } 45 | 46 | public string Name 47 | { 48 | get 49 | { 50 | return LocalizationHelper.GetMonsterStatusEffectName(Index); 51 | } 52 | } 53 | 54 | public bool IsVisible 55 | { 56 | get 57 | { 58 | return IsIncluded(GroupId) && IsTimeVisible(ConfigHelper.Main.Values.Overlay.MonsterWidget.ShowUnchangedStatusEffects, ConfigHelper.Main.Values.Overlay.MonsterWidget.HideStatusEffectsAfterSeconds); 59 | } 60 | } 61 | 62 | public MonsterStatusEffect(Monster owner, ulong address, int index, float maxBuildup, float currentBuildup, float maxDuration, float currentDuration, int timesActivatedCount) 63 | { 64 | m_Owner = owner; 65 | Address = address; 66 | m_Index = index; 67 | Buildup = new Progress(maxBuildup, currentBuildup, true); 68 | Duration = new Progress(maxDuration, currentDuration, true); 69 | m_TimesActivatedCount = timesActivatedCount; 70 | 71 | PropertyChanged += MonsterStatusEffect_PropertyChanged; 72 | Buildup.PropertyChanged += Bar_PropertyChanged; 73 | Duration.PropertyChanged += Bar_PropertyChanged; 74 | } 75 | 76 | private void MonsterStatusEffect_PropertyChanged(object sender, PropertyChangedEventArgs e) 77 | { 78 | if (e.PropertyName == nameof(TimesActivatedCount)) 79 | { 80 | UpdateLastChangedTime(); 81 | } 82 | } 83 | 84 | private void Bar_PropertyChanged(object sender, PropertyChangedEventArgs e) 85 | { 86 | UpdateLastChangedTime(); 87 | } 88 | 89 | public static string GetGroupIdFromIndex(int index) 90 | { 91 | return ConfigHelper.MonsterData.Values.StatusEffects[index].GroupId; 92 | } 93 | 94 | public static bool IsIncluded(string groupId) 95 | { 96 | return ConfigHelper.Main.Values.Overlay.MonsterWidget.MatchIncludeStatusEffectGroupIdRegex(groupId); 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /SmartHunter/Game/Data/Player.cs: -------------------------------------------------------------------------------- 1 | using SmartHunter.Core.Data; 2 | 3 | namespace SmartHunter.Game.Data 4 | { 5 | public class Player : Bindable 6 | { 7 | int m_Index; 8 | 9 | public int Index 10 | { 11 | get { return m_Index; } 12 | set { SetProperty(ref m_Index, value); } 13 | } 14 | 15 | string m_Name; 16 | public string Name 17 | { 18 | get { return m_Name; } 19 | set { SetProperty(ref m_Name, value); } 20 | } 21 | 22 | int m_Damage; 23 | public int Damage 24 | { 25 | get { return m_Damage; } 26 | set { SetProperty(ref m_Damage, value); } 27 | } 28 | 29 | float m_DamageFraction; 30 | public float DamageFraction 31 | { 32 | get { return m_DamageFraction; } 33 | set { SetProperty(ref m_DamageFraction, value); } 34 | } 35 | 36 | float m_BarFraction; 37 | public float BarFraction 38 | { 39 | get { return m_BarFraction; } 40 | set { SetProperty(ref m_BarFraction, value); } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /SmartHunter/Game/Data/PlayerStatusEffect.cs: -------------------------------------------------------------------------------- 1 | using SmartHunter.Core.Data; 2 | using SmartHunter.Game.Helpers; 3 | 4 | namespace SmartHunter.Game.Data 5 | { 6 | public class PlayerStatusEffect : Bindable 7 | { 8 | int m_Index; 9 | public int Index 10 | { 11 | get { return m_Index; } 12 | set 13 | { 14 | if (SetProperty(ref m_Index, value)) 15 | { 16 | NotifyPropertyChanged(nameof(GroupId)); 17 | NotifyPropertyChanged(nameof(Name)); 18 | NotifyPropertyChanged(nameof(IsVisible)); 19 | } 20 | } 21 | } 22 | 23 | public Progress Time { get; private set; } 24 | 25 | bool m_IsConditionPassed; 26 | public bool IsConditionPassed 27 | { 28 | get { return m_IsConditionPassed; } 29 | set 30 | { 31 | if (SetProperty(ref m_IsConditionPassed, value)) 32 | { 33 | NotifyPropertyChanged(nameof(IsVisible)); 34 | } 35 | } 36 | } 37 | 38 | public string GroupId 39 | { 40 | get 41 | { 42 | return GetGroupIdFromIndex(Index); 43 | } 44 | } 45 | 46 | public string Name 47 | { 48 | get 49 | { 50 | return LocalizationHelper.GetPlayerStatusEffectName(Index); 51 | } 52 | } 53 | 54 | public bool IsVisible 55 | { 56 | get 57 | { 58 | return IsIncluded(GroupId) && IsConditionPassed; 59 | } 60 | } 61 | 62 | public PlayerStatusEffect(int index, float? maxTime, float? currentTime, bool isConditionPassed) 63 | { 64 | m_Index = index; 65 | 66 | if (maxTime.HasValue && currentTime.HasValue) 67 | { 68 | Time = new Progress(maxTime.Value, currentTime.Value); 69 | } 70 | 71 | m_IsConditionPassed = isConditionPassed; 72 | } 73 | 74 | public static string GetGroupIdFromIndex(int index) 75 | { 76 | return ConfigHelper.PlayerData.Values.StatusEffects[index].GroupId; 77 | } 78 | 79 | public static bool IsIncluded(string groupId) 80 | { 81 | return ConfigHelper.Main.Values.Overlay.PlayerWidget.MatchIncludeStatusEffectGroupIdRegex(groupId); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /SmartHunter/Game/Data/ViewModels/ConsoleViewModel.cs: -------------------------------------------------------------------------------- 1 | using SmartHunter.Core; 2 | using SmartHunter.Core.Data; 3 | 4 | namespace SmartHunter.Game.Data.ViewModels 5 | { 6 | public class ConsoleViewModel : Bindable 7 | { 8 | static ConsoleViewModel s_Instance = null; 9 | public static ConsoleViewModel Instance 10 | { 11 | get 12 | { 13 | if (s_Instance == null) 14 | { 15 | s_Instance = new ConsoleViewModel(); 16 | } 17 | 18 | return s_Instance; 19 | } 20 | } 21 | 22 | string m_Output; 23 | public string Output 24 | { 25 | get { return m_Output; } 26 | set { SetProperty(ref m_Output, value); } 27 | } 28 | 29 | public ConsoleViewModel() 30 | { 31 | Log.LineReceived += Log_LineReceived; 32 | } 33 | 34 | void Log_LineReceived(object sender, GenericEventArgs e) 35 | { 36 | Output += $"{e.Value}\r\n"; 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /SmartHunter/Game/Data/ViewModels/OverlayViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using SmartHunter.Core.Data; 3 | using SmartHunter.Game.Data.WidgetContexts; 4 | using SmartHunter.Game.Helpers; 5 | 6 | namespace SmartHunter.Game.Data.ViewModels 7 | { 8 | public class OverlayViewModel : Bindable 9 | { 10 | static OverlayViewModel s_Instance = null; 11 | public static OverlayViewModel Instance 12 | { 13 | get 14 | { 15 | if (s_Instance == null) 16 | { 17 | s_Instance = new OverlayViewModel(); 18 | 19 | bool isDesignInstance = LicenseManager.UsageMode == LicenseUsageMode.Designtime; 20 | if (isDesignInstance || ConfigHelper.Main.Values.Debug.UseSampleData) 21 | { 22 | s_Instance.GenerateSampleData(); 23 | } 24 | } 25 | 26 | return s_Instance; 27 | } 28 | } 29 | 30 | public ContextualWidget TeamWidget { get; private set; } 31 | public ContextualWidget MonsterWidget { get; private set; } 32 | public ContextualWidget PlayerWidget { get; private set; } 33 | public ContextualWidget DebugWidget { get; private set; } 34 | 35 | bool m_CanManipulateWindows; 36 | public bool CanManipulateWindows 37 | { 38 | get { return m_CanManipulateWindows; } 39 | set { SetProperty(ref m_CanManipulateWindows, value); } 40 | } 41 | 42 | bool m_HideWidgetsRequested; 43 | public bool HideWidgetsRequested 44 | { 45 | get { return m_HideWidgetsRequested; } 46 | set 47 | { 48 | if (SetProperty(ref m_HideWidgetsRequested, value)) 49 | { 50 | NotifyPropertyChanged(nameof(IsVisible)); 51 | } 52 | } 53 | } 54 | 55 | bool m_IsGameActive = false; 56 | public bool IsGameActive 57 | { 58 | get { return m_IsGameActive; } 59 | set 60 | { 61 | if (SetProperty(ref m_IsGameActive, value)) 62 | { 63 | NotifyPropertyChanged(nameof(IsVisible)); 64 | } 65 | } 66 | } 67 | 68 | public bool IsVisible 69 | { 70 | get 71 | { 72 | return IsGameActive && !HideWidgetsRequested; 73 | } 74 | } 75 | 76 | public OverlayViewModel() 77 | { 78 | TeamWidget = new ContextualWidget(ConfigHelper.Main.Values.Overlay.TeamWidget, new TeamWidgetContext()); 79 | MonsterWidget = new ContextualWidget(ConfigHelper.Main.Values.Overlay.MonsterWidget, new MonsterWidgetContext()); 80 | PlayerWidget = new ContextualWidget(ConfigHelper.Main.Values.Overlay.PlayerWidget, new PlayerWidgetContext()); 81 | DebugWidget = new ContextualWidget(ConfigHelper.Main.Values.Overlay.DebugWidget, new DebugWidgetContext()); 82 | } 83 | 84 | void GenerateSampleData() 85 | { 86 | /* 87 | TeamWidget.Context.UpdateAndGetPlayer(0, "Jade", 3244); 88 | TeamWidget.Context.UpdateAndGetPlayer(1, "Kabuto", 2182); 89 | TeamWidget.Context.UpdateAndGetPlayer(2, "mike the father", 569); 90 | TeamWidget.Context.UpdateAndGetPlayer(3, "SlashMaster", 2966); 91 | 92 | TeamWidget.Context.UpdateFractions(); 93 | 94 | var monster1 = MonsterWidget.Context.UpdateAndGetMonster(0, "em113_00", 6150, 6150, 1.25f); 95 | MonsterWidget.Context.UpdateAndGetMonster(0, "em113_00", 6150, 2733, 1.45f); 96 | MonsterWidget.Context.UpdateAndGetMonster(1, "em114_00", 5700, 5700, 0.45f); 97 | MonsterWidget.Context.UpdateAndGetMonster(2, "em118_00", 9191, 9191, 1.35f); 98 | 99 | monster1.UpdateAndGetPart(0, false, 480, 480, 3); 100 | monster1.UpdateAndGetPart(0, false, 480, 109, 3); 101 | 102 | monster1.UpdateAndGetPart(1, false, 100, 100, 2); 103 | 104 | monster1.UpdateAndGetPart(2, false, 384, 384, 1); 105 | monster1.UpdateAndGetPart(2, false, 384, 322, 1); 106 | 107 | monster1.UpdateAndGetPart(3, false, 432, 432, 0); 108 | monster1.UpdateAndGetPart(3, false, 432, 419, 0); 109 | 110 | monster1.UpdateAndGetPart(4, false, 150, 150, 1); 111 | monster1.UpdateAndGetPart(4, false, 150, 100, 1); 112 | 113 | monster1.UpdateAndGetPart(4, false, 432, 432, 1); 114 | monster1.UpdateAndGetPart(4, false, 432, 403, 1); 115 | 116 | monster1.UpdateAndGetPart(0, true, 864, 864, 0); 117 | monster1.UpdateAndGetPart(0, true, 864, 811, 0); 118 | 119 | monster1.UpdateAndGetStatusEffect(5, 50, 50, 50, 0, 1); 120 | monster1.UpdateAndGetStatusEffect(5, 50, 40, 50, 0, 1); 121 | 122 | monster1.UpdateAndGetStatusEffect(2, 100, 100, 7, 0, 0); 123 | monster1.UpdateAndGetStatusEffect(2, 100, 0, 7, 3, 0); 124 | 125 | monster1.UpdateAndGetStatusEffect(13, 50, 50, 50, 0, 1); 126 | monster1.UpdateAndGetStatusEffect(13, 50, 30, 50, 20, 1); 127 | 128 | monster1.UpdateAndGetStatusEffect(10, 50, 50, 50, 0, 1); 129 | monster1.UpdateAndGetStatusEffect(10, 50, 30, 50, 20, 1); 130 | 131 | PlayerWidget.Context.UpdateAndGetPlayerStatusEffect(1, 20, true); 132 | PlayerWidget.Context.UpdateAndGetPlayerStatusEffect(1, 15.5f, true); 133 | 134 | PlayerWidget.Context.UpdateAndGetPlayerStatusEffect(45, 120, true); 135 | PlayerWidget.Context.UpdateAndGetPlayerStatusEffect(45, 33.43f, true); 136 | 137 | PlayerWidget.Context.UpdateAndGetPlayerStatusEffect(80, null, true); 138 | PlayerWidget.Context.UpdateAndGetPlayerStatusEffect(82, null, true); 139 | PlayerWidget.Context.UpdateAndGetPlayerStatusEffect(83, 40, true); 140 | PlayerWidget.Context.UpdateAndGetPlayerStatusEffect(83, 30, true); 141 | 142 | PlayerWidget.Context.UpdateAndGetPlayerStatusEffect(69, 20, true); 143 | PlayerWidget.Context.UpdateAndGetPlayerStatusEffect(69, 11.98f, true); 144 | 145 | PlayerWidget.Context.UpdateAndGetPlayerStatusEffect(90, 120, true); 146 | PlayerWidget.Context.UpdateAndGetPlayerStatusEffect(90, 111.5f, true); 147 | 148 | //// PROMO DATA 149 | //TeamWidget.Context.UpdateAndGetPlayer(0, "Jade", 1185); 150 | //TeamWidget.Context.UpdateAndGetPlayer(1, "Kabuto", 838); 151 | //TeamWidget.Context.UpdateAndGetPlayer(2, "mike the father", 632); 152 | //TeamWidget.Context.UpdateAndGetPlayer(3, "SlashMaster", 134); 153 | //TeamWidget.Context.UpdateFractions(); 154 | 155 | //// Legiana 156 | //var monster1 = MonsterWidget.Context.UpdateAndGetMonster(0, "em111_00", 6060, 6060, 1.25f); 157 | //MonsterWidget.Context.UpdateAndGetMonster(0, "em111_00", 6060, 3271, 1.25f); 158 | 159 | //monster1.UpdateAndGetPart(0, false, 480, 208, 3); 160 | //monster1.UpdateAndGetPart(0, false, 480, 207, 3); 161 | 162 | //monster1.UpdateAndGetPart(1, false, 480, 154, 1); 163 | //monster1.UpdateAndGetPart(1, false, 480, 153, 1); 164 | 165 | //monster1.UpdateAndGetPart(2, false, 384, 323, 0); 166 | //monster1.UpdateAndGetPart(2, false, 384, 322, 0); 167 | 168 | //monster1.UpdateAndGetStatusEffect(4, 110, 57, 50, 0, 0); 169 | //monster1.UpdateAndGetStatusEffect(4, 110, 55, 50, 0, 0); 170 | 171 | //monster1.UpdateAndGetStatusEffect(13, 50, 31, 100, 68, 1); 172 | //monster1.UpdateAndGetStatusEffect(13, 50, 30, 100, 68, 1); 173 | 174 | //// Iceblight 175 | //PlayerWidget.Context.UpdateAndGetPlayerStatusEffect(61, 60, true); 176 | //PlayerWidget.Context.UpdateAndGetPlayerStatusEffect(61, 20, true); 177 | 178 | //// Might Seed 179 | //PlayerWidget.Context.UpdateAndGetPlayerStatusEffect(74, 180, true); 180 | //PlayerWidget.Context.UpdateAndGetPlayerStatusEffect(74, 97, true); 181 | 182 | //// Mega Armorskin 183 | //PlayerWidget.Context.UpdateAndGetPlayerStatusEffect(82, null, true); 184 | 185 | //// Mega Demondrug 186 | //PlayerWidget.Context.UpdateAndGetPlayerStatusEffect(80, null, true); 187 | */ 188 | } 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /SmartHunter/Game/Data/WeaponType.cs: -------------------------------------------------------------------------------- 1 | namespace SmartHunter.Game.Data 2 | { 3 | public enum WeaponType 4 | { 5 | NO_WEAPON, 6 | WEAPON_UNKNOWN, 7 | BOW, 8 | CHARGE_BLADE, 9 | GUNLANCE, 10 | HAMMER, 11 | HEAVY_BOWGUN, 12 | HUNTING_HORN, 13 | LANCE, 14 | LIGHT_BOWGUN, 15 | INSECT_GLAIVE, 16 | KINSECT, 17 | SWORD_AND_SHIELD, 18 | SWITCH_AXE, 19 | DUAL_BLADES, 20 | LONG_SWORD, 21 | GREAT_SWORD, 22 | SLINGER 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /SmartHunter/Game/Data/WidgetContexts/DebugWidgetContext.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.ObjectModel; 2 | using System.Linq; 3 | using SmartHunter.Core.Data; 4 | using SmartHunter.Game.Data; 5 | 6 | namespace SmartHunter.Game.Data.WidgetContexts 7 | { 8 | public class DebugWidgetContext : WidgetContext 9 | { 10 | public Game CurrentGame { get; set; } 11 | 12 | public void UpdateCurrentGame(string playerName, string weaponString, string sessionID, string sessionHostName, string lobbyID, string lobbyHostName) 13 | { 14 | CurrentGame.CurrentPlayerName = playerName; 15 | CurrentGame.CurrentWeaponString = weaponString; 16 | CurrentGame.SessionID = sessionID; 17 | CurrentGame.SessionHostPlayerName = sessionHostName; 18 | CurrentGame.LobbyID = lobbyID; 19 | CurrentGame.LobbyHostPlayerName = lobbyHostName; 20 | CurrentGame.IsValid = true; 21 | } 22 | public DebugWidgetContext() 23 | { 24 | CurrentGame = new Game(); 25 | } 26 | 27 | public override void UpdateFromConfig() 28 | { 29 | base.UpdateFromConfig(); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /SmartHunter/Game/Data/WidgetContexts/MonsterWidgetContext.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.ObjectModel; 2 | using System.Linq; 3 | using SmartHunter.Core.Data; 4 | using SmartHunter.Game.Helpers; 5 | 6 | namespace SmartHunter.Game.Data.WidgetContexts 7 | { 8 | public class MonsterWidgetContext : WidgetContext 9 | { 10 | public ObservableCollection Monsters { get; private set; } 11 | 12 | bool m_ShowSize = false; 13 | public bool ShowSize 14 | { 15 | get { return m_ShowSize; } 16 | set { SetProperty(ref m_ShowSize, value); } 17 | } 18 | 19 | bool m_ShowCrown = true; 20 | public bool ShowCrown 21 | { 22 | get { return m_ShowCrown; } 23 | set { SetProperty(ref m_ShowCrown, value); } 24 | } 25 | 26 | bool m_ShowBars = true; 27 | public bool ShowBars 28 | { 29 | get { return m_ShowBars; } 30 | set { SetProperty(ref m_ShowBars, value); } 31 | } 32 | 33 | bool m_ShowNumbers = true; 34 | public bool ShowNumbers 35 | { 36 | get { return m_ShowNumbers; } 37 | set { SetProperty(ref m_ShowNumbers, value); } 38 | } 39 | 40 | bool m_ShowPercents = true; 41 | public bool ShowPercents 42 | { 43 | get { return m_ShowPercents; } 44 | set { SetProperty(ref m_ShowPercents, value); } 45 | } 46 | 47 | bool m_UseAnimations = true; 48 | public bool UseAnimations 49 | { 50 | get { return m_UseAnimations; } 51 | set { SetProperty(ref m_UseAnimations, value); } 52 | } 53 | 54 | public MonsterWidgetContext() 55 | { 56 | Monsters = new ObservableCollection(); 57 | 58 | UpdateFromConfig(); 59 | } 60 | 61 | public Monster UpdateAndGetMonster(ulong address, string id, float maxHealth, float currentHealth, float sizeScale, float scaleModifier) 62 | { 63 | Monster monster = null; 64 | 65 | monster = Monsters.FirstOrDefault(existingMonster => existingMonster.Address == address); 66 | if (monster != null) 67 | { 68 | monster.Id = id; 69 | monster.Health.Max = maxHealth; 70 | monster.Health.Current = currentHealth; 71 | monster.SizeScale = sizeScale; 72 | monster.ScaleModifier = scaleModifier; 73 | } 74 | else 75 | { 76 | monster = new Monster(address, id, maxHealth, currentHealth, sizeScale, scaleModifier); 77 | Monsters.Add(monster); 78 | } 79 | 80 | monster.NotifyPropertyChanged(nameof(Monster.IsVisible)); 81 | 82 | return monster; 83 | } 84 | 85 | public override void UpdateFromConfig() 86 | { 87 | base.UpdateFromConfig(); 88 | 89 | ShowSize = ConfigHelper.Main.Values.Overlay.MonsterWidget.ShowSize; 90 | ShowCrown = ConfigHelper.Main.Values.Overlay.MonsterWidget.ShowCrown; 91 | ShowBars = ConfigHelper.Main.Values.Overlay.MonsterWidget.ShowBars; 92 | ShowNumbers = ConfigHelper.Main.Values.Overlay.MonsterWidget.ShowNumbers; 93 | ShowPercents = ConfigHelper.Main.Values.Overlay.MonsterWidget.ShowPercents; 94 | UseAnimations = ConfigHelper.Main.Values.Overlay.MonsterWidget.UseAnimations; 95 | 96 | foreach (var monster in Monsters) 97 | { 98 | monster.NotifyPropertyChanged(nameof(Monster.IsVisible)); 99 | } 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /SmartHunter/Game/Data/WidgetContexts/PlayerWidgetContext.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.ObjectModel; 2 | using System.Linq; 3 | using SmartHunter.Core.Data; 4 | 5 | namespace SmartHunter.Game.Data.WidgetContexts 6 | { 7 | public class PlayerWidgetContext : WidgetContext 8 | { 9 | public ObservableCollection StatusEffects { get; private set; } 10 | 11 | public PlayerWidgetContext() 12 | { 13 | StatusEffects = new ObservableCollection(); 14 | } 15 | 16 | public PlayerStatusEffect UpdateAndGetPlayerStatusEffect(int index, float? currentTime, bool isConditionPassed) 17 | { 18 | PlayerStatusEffect playerStatusEffect = StatusEffects.SingleOrDefault(statusEffect => statusEffect.Index == index); 19 | if (playerStatusEffect == null && isConditionPassed) 20 | { 21 | playerStatusEffect = new PlayerStatusEffect(index, currentTime, currentTime, isConditionPassed); 22 | StatusEffects.Add(playerStatusEffect); 23 | } 24 | else if (playerStatusEffect != null) 25 | { 26 | if (currentTime.HasValue) 27 | { 28 | playerStatusEffect.Time.Current = currentTime.Value; 29 | } 30 | 31 | playerStatusEffect.IsConditionPassed = isConditionPassed; 32 | } 33 | 34 | return playerStatusEffect; 35 | } 36 | 37 | public override void UpdateFromConfig() 38 | { 39 | base.UpdateFromConfig(); 40 | 41 | foreach (var statusEffect in StatusEffects) 42 | { 43 | statusEffect.NotifyPropertyChanged(nameof(PlayerStatusEffect.IsVisible)); 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /SmartHunter/Game/Data/WidgetContexts/TeamWidgetContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.ObjectModel; 3 | using System.Linq; 4 | using SmartHunter.Core.Data; 5 | using SmartHunter.Game.Helpers; 6 | 7 | namespace SmartHunter.Game.Data.WidgetContexts 8 | { 9 | public class TeamWidgetContext : WidgetContext 10 | { 11 | public Collection Players { get; private set; } 12 | public ObservableCollection Fake_Players { get; private set; } // TODO: Can dis be done inside the xaml file? 13 | 14 | bool m_DontShowIfAlone = false; 15 | public bool DontShowIfAlone 16 | { 17 | get { return m_DontShowIfAlone; } 18 | set { SetProperty(ref m_DontShowIfAlone, value); } 19 | } 20 | 21 | bool m_ShowBars = true; 22 | public bool ShowBars 23 | { 24 | get { return m_ShowBars; } 25 | set { SetProperty(ref m_ShowBars, value); } 26 | } 27 | 28 | bool m_ShowNumbers = true; 29 | public bool ShowNumbers 30 | { 31 | get { return m_ShowNumbers; } 32 | set { SetProperty(ref m_ShowNumbers, value); } 33 | } 34 | 35 | bool m_ShowPercents = false; 36 | public bool ShowPercents 37 | { 38 | get { return m_ShowPercents; } 39 | set { SetProperty(ref m_ShowPercents, value); } 40 | } 41 | 42 | public TeamWidgetContext() 43 | { 44 | Players = new Collection(); 45 | Fake_Players = new ObservableCollection(); 46 | 47 | UpdateFromConfig(); 48 | } 49 | 50 | public Player UpdateAndGetPlayer(int index, string name, int damage) 51 | { 52 | if (string.IsNullOrEmpty(name) && damage == 0) 53 | { 54 | if (index < Players.Count) 55 | { 56 | Players.RemoveAt(index); 57 | if (DontShowIfAlone && Players.Count() <= 1) 58 | { 59 | Fake_Players.Clear(); 60 | } 61 | else 62 | { 63 | Fake_Players.RemoveAt(index); 64 | } 65 | } 66 | return null; 67 | } 68 | 69 | while (index >= Players.Count) 70 | { 71 | Players.Add(new Player() { Index = Players.Count, Name = LocalizationHelper.GetString(LocalizationHelper.UnknownPlayerStringId) }); 72 | 73 | if (DontShowIfAlone && Players.Count() <= 1) 74 | { 75 | Fake_Players.Clear(); 76 | } 77 | else 78 | { 79 | Fake_Players.Add(Players[Players.Count() - 1]); 80 | } 81 | } 82 | 83 | var player = Players[index]; 84 | if (!string.IsNullOrEmpty(name)) 85 | { 86 | player.Name = name; 87 | } 88 | else if (string.IsNullOrEmpty(player.Name)) 89 | { 90 | player.Name = LocalizationHelper.GetString(LocalizationHelper.UnknownPlayerStringId); 91 | } 92 | 93 | player.Damage = damage; 94 | 95 | return player; 96 | } 97 | 98 | public void UpdateFractions() 99 | { 100 | var playersWithDamage = Players.Where(player => player.Damage > 0); 101 | if (!playersWithDamage.Any()) 102 | { 103 | foreach (var player in Players) 104 | { 105 | player.DamageFraction = 0; 106 | player.BarFraction = 0; 107 | } 108 | 109 | return; 110 | } 111 | 112 | var highestDamagePlayers = Players.OrderByDescending(player => player.Damage).Take(1); 113 | if (highestDamagePlayers.Any()) 114 | { 115 | int totalDamage = Players.Sum(player => player.Damage); 116 | 117 | var highestDamagePlayer = highestDamagePlayers.First(); 118 | highestDamagePlayer.DamageFraction = (float)highestDamagePlayer.Damage / (float)totalDamage; 119 | highestDamagePlayer.BarFraction = 1; 120 | 121 | foreach (var otherPlayer in Players.Except(highestDamagePlayers)) 122 | { 123 | otherPlayer.DamageFraction = (float)otherPlayer.Damage / (float)totalDamage; 124 | otherPlayer.BarFraction = (float)otherPlayer.Damage / (float)highestDamagePlayer.Damage; 125 | } 126 | } 127 | } 128 | 129 | public void ClearPlayers() 130 | { 131 | Players.Clear(); 132 | Fake_Players.Clear(); 133 | } 134 | 135 | public override void UpdateFromConfig() 136 | { 137 | base.UpdateFromConfig(); 138 | 139 | DontShowIfAlone = ConfigHelper.Main.Values.Overlay.TeamWidget.DontShowIfAlone; 140 | ShowBars = ConfigHelper.Main.Values.Overlay.TeamWidget.ShowBars; 141 | ShowNumbers = ConfigHelper.Main.Values.Overlay.TeamWidget.ShowNumbers; 142 | ShowPercents = ConfigHelper.Main.Values.Overlay.TeamWidget.ShowPercents; 143 | } 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /SmartHunter/Game/Helpers/ConfigHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartHunter.Config; 3 | using SmartHunter.Core.Config; 4 | using SmartHunter.Game.Config; 5 | 6 | namespace SmartHunter.Game.Helpers 7 | { 8 | public static class ConfigHelper 9 | { 10 | static readonly string s_MainFileName = "Config.json"; 11 | 12 | static ConfigContainer s_Main; 13 | static ConfigContainer s_Localization; 14 | static ConfigContainer s_MonsterData; 15 | static ConfigContainer s_PlayerData; 16 | static ConfigContainer s_Memory; 17 | 18 | public static ConfigContainer Main 19 | { 20 | get 21 | { 22 | if (s_Main == null) 23 | { 24 | s_Main = new ConfigContainer(s_MainFileName); 25 | s_Main.Changed += Main_Loaded; 26 | } 27 | 28 | return s_Main; 29 | } 30 | } 31 | 32 | public static ConfigContainer Localization 33 | { 34 | get 35 | { 36 | if (s_Localization == null) 37 | { 38 | s_Localization = new ConfigContainer(Main.Values.LocalizationFileName); 39 | } 40 | 41 | return s_Localization; 42 | } 43 | } 44 | 45 | public static ConfigContainer MonsterData 46 | { 47 | get 48 | { 49 | if (s_MonsterData == null) 50 | { 51 | s_MonsterData = new ConfigContainer(Main.Values.MonsterDataFileName); 52 | } 53 | 54 | return s_MonsterData; 55 | } 56 | } 57 | 58 | public static ConfigContainer PlayerData 59 | { 60 | get 61 | { 62 | if (s_PlayerData == null) 63 | { 64 | s_PlayerData = new ConfigContainer(Main.Values.PlayerDataFileName); 65 | } 66 | 67 | return s_PlayerData; 68 | } 69 | } 70 | 71 | public static ConfigContainer Memory 72 | { 73 | get 74 | { 75 | if (s_Memory == null) 76 | { 77 | s_Memory = new ConfigContainer(Main.Values.MemoryFileName); 78 | } 79 | 80 | return s_Memory; 81 | } 82 | } 83 | 84 | // Ensures configs are loaded 85 | public static void EnsureConfigs() 86 | { 87 | _ = Main; 88 | _ = Localization; 89 | _ = MonsterData; 90 | _ = PlayerData; 91 | _ = Memory; 92 | } 93 | 94 | static void Main_Loaded(object sender, EventArgs e) 95 | { 96 | Localization.TryChangeFileName(Main.Values.LocalizationFileName); 97 | MonsterData.TryChangeFileName(Main.Values.MonsterDataFileName); 98 | PlayerData.TryChangeFileName(Main.Values.PlayerDataFileName); 99 | Memory.TryChangeFileName(Main.Values.MemoryFileName); 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /SmartHunter/Game/Helpers/LocalizationHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using SmartHunter.Core; 3 | 4 | namespace SmartHunter.Game.Helpers 5 | { 6 | public static class LocalizationHelper 7 | { 8 | public static readonly string MissingStringId = "LOC_MISSING"; 9 | public static readonly string UnknownMonsterStringId = "LOC_MONSTER_UKNOWN"; 10 | public static readonly string UnknownPartStringId = "LOC_PART_UKNOWN"; 11 | public static readonly string UnknownRemovablePartStringId = "LOC_REMOVABLE_PART_UKNOWN"; 12 | public static readonly string UnknownMonsterStatusEffectStringId = "LOC_STATUS_EFFECT_UKNOWN"; 13 | public static readonly string UnknownPlayerStatusEffectStringId = "LOC_STATUS_EFFECT_UKNOWN"; 14 | public static readonly string UnknownPlayerStringId = "LOC_UNKNOWN_PLAYER"; 15 | 16 | public static string GetString(string stringId) 17 | { 18 | if (ConfigHelper.Localization.Values.Strings.TryGetValue(stringId, out var value)) 19 | { 20 | return value; 21 | } 22 | 23 | Log.WriteLine($"Localization: '{stringId}' does not exist in {ConfigHelper.Localization.FileName}"); 24 | 25 | return stringId; 26 | } 27 | 28 | public static string GetMonsterName(string monsterId) 29 | { 30 | if (ConfigHelper.MonsterData.Values.Monsters.TryGetValue(monsterId, out var monsterConfig)) 31 | { 32 | return GetString(monsterConfig.NameStringId); 33 | } 34 | 35 | Log.WriteLine($"Localization: Monster '{monsterId}' not found in {ConfigHelper.MonsterData.FileName}"); 36 | 37 | return GetString(UnknownMonsterStringId); 38 | } 39 | 40 | public static string GetMonsterPartName(string monsterId, int partIndex, bool isRemovable) 41 | { 42 | if (ConfigHelper.MonsterData.Values.Monsters.TryGetValue(monsterId, out var monsterConfig)) 43 | { 44 | var parts = monsterConfig.Parts.Where(part => part.IsRemovable == isRemovable); 45 | if (parts.Count() > partIndex) 46 | { 47 | return GetString(parts.ElementAt(partIndex).StringId); 48 | } 49 | else if (!isRemovable) 50 | { 51 | Log.WriteLine($"Localization: Monster '{monsterId}' part '{partIndex}' not found in {ConfigHelper.MonsterData.FileName}"); 52 | } 53 | else 54 | { 55 | Log.WriteLine($"Localization: Monster '{monsterId}' removable part '{partIndex}' not found in {ConfigHelper.MonsterData.FileName}"); 56 | } 57 | } 58 | else 59 | { 60 | Log.WriteLine($"Localization: Monster '{monsterId}' not found in {ConfigHelper.MonsterData.FileName}"); 61 | } 62 | 63 | if (!isRemovable) 64 | { 65 | return GetString(UnknownPartStringId); 66 | } 67 | 68 | return GetString(UnknownRemovablePartStringId); 69 | } 70 | 71 | public static string GetMonsterStatusEffectName(int index) 72 | { 73 | if (ConfigHelper.MonsterData.Values.StatusEffects.Length > index) 74 | { 75 | return GetString(ConfigHelper.MonsterData.Values.StatusEffects[index].NameStringId); 76 | } 77 | 78 | Log.WriteLine($"Localization: Monster status effect with index '{index}' not found in {ConfigHelper.MonsterData.FileName}"); 79 | 80 | return GetString(UnknownMonsterStatusEffectStringId); 81 | } 82 | 83 | public static string GetPlayerStatusEffectName(int index) 84 | { 85 | if (ConfigHelper.PlayerData.Values.StatusEffects.Length > index) 86 | { 87 | return GetString(ConfigHelper.PlayerData.Values.StatusEffects[index].NameStringId); 88 | } 89 | 90 | Log.WriteLine($"Localization: Player status effect with index '{index}' not found in {ConfigHelper.PlayerData.FileName}"); 91 | 92 | return GetString(UnknownPlayerStatusEffectStringId); 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /SmartHunter/Game/InputControl.cs: -------------------------------------------------------------------------------- 1 | namespace SmartHunter.Game 2 | { 3 | public enum InputControl 4 | { 5 | ManipulateWidget, 6 | HideWidgets, 7 | ToggleWidgests, 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /SmartHunter/Game/MhwOverlay.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Linq; 4 | using System.Windows; 5 | using System.Windows.Input; 6 | using SmartHunter.Core; 7 | using SmartHunter.Core.Helpers; 8 | using SmartHunter.Core.Windows; 9 | using SmartHunter.Game.Data.ViewModels; 10 | using SmartHunter.Game.Helpers; 11 | 12 | namespace SmartHunter.Game 13 | { 14 | public class MhwOverlay : Overlay 15 | { 16 | private readonly MhwMemoryUpdater _memoryUpdater; 17 | private readonly Stopwatch _stopwatch; 18 | 19 | public MhwOverlay(Window mainWindow, params WidgetWindow[] widgetWindows) : base(mainWindow, widgetWindows) 20 | { 21 | ConfigHelper.Main.Loaded += (s, e) => { UpdateWidgetsFromConfig(); }; 22 | ConfigHelper.Localization.Loaded += (s, e) => { RefreshWidgetsLayout(); }; 23 | ConfigHelper.MonsterData.Loaded += (s, e) => { RefreshWidgetsLayout(); }; 24 | ConfigHelper.PlayerData.Loaded += (s, e) => { RefreshWidgetsLayout(); }; 25 | _memoryUpdater = !ConfigHelper.Main.Values.Debug.UseSampleData ? _memoryUpdater = new MhwMemoryUpdater() : null; 26 | _stopwatch = new Stopwatch(); 27 | _stopwatch.Start(); 28 | } 29 | 30 | protected override void InputReceived(Key key, bool isDown) 31 | { 32 | foreach (var controlKeyPair in ConfigHelper.Main.Values.Keybinds.Where(keybind => keybind.Value == key)) 33 | { 34 | HandleControl(controlKeyPair.Key, isDown); 35 | } 36 | } 37 | 38 | private void HandleControl(InputControl control, bool isDown) 39 | { 40 | if (control == InputControl.ManipulateWidget && isDown && !OverlayViewModel.Instance.CanManipulateWindows) 41 | { 42 | OverlayViewModel.Instance.CanManipulateWindows = true; 43 | 44 | // Make all the windows selectable 45 | foreach (var widgetWindow in WidgetWindows) 46 | { 47 | WindowHelper.SetTopMostSelectable(widgetWindow as Window); 48 | } 49 | } 50 | else if (control == InputControl.ManipulateWidget && !isDown && OverlayViewModel.Instance.CanManipulateWindows) 51 | { 52 | OverlayViewModel.Instance.CanManipulateWindows = false; 53 | 54 | bool canSaveConfig = false; 55 | 56 | // Return all windows to their click through state 57 | foreach (var widgetWindow in WidgetWindows) 58 | { 59 | WindowHelper.SetTopMostTransparent(widgetWindow as Window); 60 | 61 | if (widgetWindow.Widget.CanSaveConfig) 62 | { 63 | canSaveConfig = true; 64 | widgetWindow.Widget.CanSaveConfig = false; 65 | } 66 | } 67 | 68 | if (canSaveConfig) 69 | { 70 | ConfigHelper.Main.Save(); 71 | } 72 | } 73 | else if (control == InputControl.HideWidgets) 74 | { 75 | OverlayViewModel.Instance.HideWidgetsRequested = isDown; 76 | } 77 | else if (control == InputControl.ToggleWidgests) 78 | { 79 | if (_stopwatch.Elapsed < TimeSpan.FromSeconds(2)) 80 | return; 81 | 82 | OverlayViewModel.Instance.HideWidgetsRequested = !OverlayViewModel.Instance.HideWidgetsRequested; 83 | _stopwatch.Restart(); 84 | } 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /SmartHunter/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using System.Windows; 3 | using System.Windows.Media; 4 | 5 | [assembly: DisableDpiAwareness] 6 | 7 | [assembly: ComVisible(false)] 8 | [assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)] -------------------------------------------------------------------------------- /SmartHunter/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // Il codice è stato generato da uno strumento. 4 | // Versione runtime:4.0.30319.42000 5 | // 6 | // Le modifiche apportate a questo file possono provocare un comportamento non corretto e andranno perse se 7 | // il codice viene rigenerato. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace SmartHunter.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// Classe di risorse fortemente tipizzata per la ricerca di stringhe localizzate e così via. 17 | /// 18 | // Questa classe è stata generata automaticamente dalla classe StronglyTypedResourceBuilder. 19 | // tramite uno strumento quale ResGen o Visual Studio. 20 | // Per aggiungere o rimuovere un membro, modificare il file con estensione ResX ed eseguire nuovamente ResGen 21 | // con l'opzione /str oppure ricompilare il progetto VS. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Restituisce l'istanza di ResourceManager nella cache utilizzata da questa classe. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SmartHunter.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Esegue l'override della proprietà CurrentUICulture del thread corrente per tutte le 51 | /// ricerche di risorse eseguite utilizzando questa classe di risorse fortemente tipizzata. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /SmartHunter/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /SmartHunter/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // Il codice è stato generato da uno strumento. 4 | // Versione runtime:4.0.30319.42000 5 | // 6 | // Le modifiche apportate a questo file possono provocare un comportamento non corretto e andranno perse se 7 | // il codice viene rigenerato. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace SmartHunter.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.4.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /SmartHunter/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /SmartHunter/SmartHunter.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | {F5F99CEF-1C16-48E6-A88B-1A66D3B53998} 4 | WinExe 5 | net461 6 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 7 | true 8 | false 9 | latest 10 | SmartHunter 11 | false 12 | 1.6.1.0 13 | 1.6.1.0 14 | bin\$(Configuration) 15 | true 16 | false 17 | 18 | 19 | full 20 | 21 | 22 | pdbonly 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /SmartHunter/Ui/Converters/AngleToIsLargeArcConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows.Data; 4 | 5 | namespace SmartHunter.Ui.Converters 6 | { 7 | class AngleToIsLargeArcConverter : IValueConverter 8 | { 9 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 10 | { 11 | return (float)value > 180; 12 | } 13 | 14 | public object ConvertBack(object value, Type targetTypes, object parameter, CultureInfo culture) 15 | { 16 | throw new NotImplementedException(); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /SmartHunter/Ui/Converters/AngleToPointConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows; 4 | using System.Windows.Data; 5 | 6 | namespace SmartHunter.Ui.Converters 7 | { 8 | public class AngleToPointConverter : IValueConverter 9 | { 10 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 11 | { 12 | if (float.TryParse(parameter as string, out var radius)) 13 | { 14 | float angle = (float)value; 15 | 16 | float radians = angle * (float)Math.PI / 180; 17 | 18 | float px = (float)Math.Sin(radians) * radius + radius; 19 | float py = (float)-Math.Cos(radians) * radius + radius; 20 | 21 | return new Point(px, py); 22 | } 23 | 24 | return Binding.DoNothing; 25 | } 26 | 27 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 28 | { 29 | throw new NotImplementedException(); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /SmartHunter/Ui/Converters/BoolToVisibilityConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows; 4 | using System.Windows.Data; 5 | 6 | namespace SmartHunter.Ui.Converters 7 | { 8 | public class BoolToVisibilityConverter : IValueConverter 9 | { 10 | public Visibility TrueValue { get; set; } = Visibility.Visible; 11 | public Visibility FalseValue { get; set; } = Visibility.Collapsed; 12 | 13 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 14 | { 15 | bool invert = parameter != null; 16 | 17 | if (value is bool) 18 | { 19 | if ((bool)value) 20 | { 21 | return !invert ? TrueValue : FalseValue; 22 | } 23 | else 24 | { 25 | return !invert ? FalseValue : TrueValue; 26 | } 27 | } 28 | 29 | return Binding.DoNothing; 30 | } 31 | 32 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 33 | { 34 | throw new NotImplementedException(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /SmartHunter/Ui/Converters/ColorTransformConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows.Data; 4 | using System.Windows.Media; 5 | 6 | namespace SmartHunter.Ui.Converters 7 | { 8 | public class ColorTransformConverter : IValueConverter 9 | { 10 | public double SaturationAdjustment { get; set; } = 0f; 11 | public double BrightnessAdjustment { get; set; } = 0f; 12 | public double? OpacityOverride { get; set; } = null; 13 | 14 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 15 | { 16 | Color? color = null; 17 | 18 | if (value is Color) 19 | { 20 | color = (Color)value; 21 | } 22 | else if (value is SolidColorBrush) 23 | { 24 | color = ((SolidColorBrush)value).Color; 25 | } 26 | 27 | if (color != null) 28 | { 29 | double hsvHue; 30 | double hsvSaturation; 31 | double hsvValue; 32 | ColorToHsv(color.Value, out hsvHue, out hsvSaturation, out hsvValue); 33 | 34 | double saturationDifference = hsvSaturation; 35 | if (SaturationAdjustment > 0) 36 | { 37 | saturationDifference = 1 - hsvSaturation; 38 | } 39 | double newSaturation = hsvSaturation + SaturationAdjustment / (1 / saturationDifference); 40 | 41 | double valueDifference = hsvValue; 42 | if (BrightnessAdjustment > 0) 43 | { 44 | saturationDifference = 1 - hsvSaturation; 45 | } 46 | double newValue = hsvValue + BrightnessAdjustment / (1 / valueDifference); 47 | 48 | var newColor = HsvToColor(hsvHue, newSaturation, newValue); 49 | 50 | if (OpacityOverride.HasValue) 51 | { 52 | newColor.A = (byte)(255f * OpacityOverride.Value); 53 | } 54 | 55 | if (value is Color) 56 | { 57 | return newColor; 58 | } 59 | else if (value is SolidColorBrush) 60 | { 61 | return new SolidColorBrush(newColor); 62 | } 63 | 64 | return HsvToColor(hsvHue, newSaturation, newValue); 65 | } 66 | 67 | return Binding.DoNothing; 68 | } 69 | 70 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 71 | { 72 | throw new NotImplementedException(); 73 | } 74 | 75 | static Color HsvToColor(double hue, double saturation, double value) 76 | { 77 | if (hue < 0) 78 | { 79 | hue = 0; 80 | } 81 | else if (hue > 360) 82 | { 83 | hue = 360; 84 | } 85 | 86 | if (saturation < 0) 87 | { 88 | saturation = 0; 89 | } 90 | else if (saturation > 1) 91 | { 92 | saturation = 1; 93 | } 94 | 95 | if (value < 0) 96 | { 97 | value = 0; 98 | } 99 | else if (value > 1) 100 | { 101 | value = 1; 102 | } 103 | 104 | double hh, p, q, t, ff; 105 | long i; 106 | 107 | double r; 108 | double g; 109 | double b; 110 | 111 | hh = hue; 112 | 113 | if (hh >= 360.0) 114 | { 115 | hh = 0.0; 116 | } 117 | 118 | hh /= 60.0; 119 | 120 | i = (long)hh; 121 | 122 | ff = hh - i; 123 | 124 | p = value * (1.0 - saturation); 125 | q = value * (1.0 - (saturation * ff)); 126 | t = value * (1.0 - (saturation * (1.0 - ff))); 127 | 128 | switch (i) 129 | { 130 | case 0: 131 | r = value; 132 | g = t; 133 | b = p; 134 | break; 135 | case 1: 136 | r = q; 137 | g = value; 138 | b = p; 139 | break; 140 | case 2: 141 | r = p; 142 | g = value; 143 | b = t; 144 | break; 145 | case 3: 146 | r = p; 147 | g = q; 148 | b = value; 149 | break; 150 | case 4: 151 | r = t; 152 | g = p; 153 | b = value; 154 | break; 155 | case 5: 156 | default: 157 | r = value; 158 | g = p; 159 | b = q; 160 | break; 161 | } 162 | 163 | return Color.FromRgb((byte)(r * 255f), (byte)(g * 255f), (byte)(b * 255f)); 164 | } 165 | 166 | static void ColorToHsv(Color color, out double hue, out double saturation, out double value) 167 | { 168 | double r = color.R / 255.0; 169 | double g = color.G / 255.0; 170 | double b = color.B / 255.0; 171 | 172 | double min = r < g ? r: g; 173 | min = min < b? min : b; 174 | 175 | double max = r > g ? r: g; 176 | max = max > b? max : b; 177 | 178 | value = max; 179 | 180 | double delta = max - min; 181 | 182 | if (delta < 0.00001) 183 | { 184 | saturation = 0; 185 | hue = 0; 186 | return; 187 | } 188 | else if (max > 0) 189 | { 190 | saturation = delta / max; 191 | } 192 | else 193 | { 194 | saturation = 0; 195 | hue = double.NaN; 196 | return; 197 | } 198 | 199 | if (r >= max) 200 | { 201 | hue = (g - b) / delta; 202 | } 203 | else if (g >= max) 204 | { 205 | hue = 2.0 + (b - r) / delta; 206 | } 207 | else 208 | { 209 | hue = 4.0 + (r - g) / delta; 210 | } 211 | 212 | hue *= 60; 213 | if (hue < 0) 214 | { 215 | hue += 360; 216 | } 217 | } 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /SmartHunter/Ui/Converters/EnumComparisonConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows.Data; 4 | 5 | namespace SmartHunter.Ui.Converters 6 | { 7 | public class EnumComparisonConverter : IValueConverter 8 | { 9 | public bool Invert { get; set; } = false; 10 | 11 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 12 | { 13 | bool result = false; 14 | 15 | if (value == null && parameter != null) 16 | { 17 | result = false; 18 | } 19 | else if (value != null && parameter == null) 20 | { 21 | result = false; 22 | } 23 | else if (value == null && parameter == null) 24 | { 25 | result = true; 26 | } 27 | else if (value.GetType().IsEnum && value.GetType() == parameter.GetType()) 28 | { 29 | result = (int)value == (int)parameter; 30 | } 31 | else 32 | { 33 | result = (int)value == (int)parameter; 34 | } 35 | 36 | if (Invert) 37 | { 38 | result = !result; 39 | } 40 | 41 | return result; 42 | } 43 | 44 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 45 | { 46 | throw new NotImplementedException(); 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /SmartHunter/Ui/Converters/FractionToPercentageConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows.Data; 4 | 5 | namespace SmartHunter.Ui.Converters 6 | { 7 | public class FractionToPercentageConverter : IValueConverter 8 | { 9 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 10 | { 11 | if (value is float) 12 | { 13 | var f = (float)value; 14 | return string.Format("{0:0}%", f * 100); 15 | } 16 | 17 | return Binding.DoNothing; 18 | } 19 | 20 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 21 | { 22 | throw new NotImplementedException(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /SmartHunter/Ui/Converters/LocalizerConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows.Data; 4 | using SmartHunter.Core; 5 | using SmartHunter.Game.Helpers; 6 | 7 | namespace SmartHunter.Ui.Converters 8 | { 9 | public class LocalizerConverter : IValueConverter 10 | { 11 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 12 | { 13 | string stringId = null; 14 | if (value != null && value is string) 15 | { 16 | stringId = value as string; 17 | } 18 | else if (parameter != null && parameter is string) 19 | { 20 | stringId = parameter as string; 21 | } 22 | else 23 | { 24 | Log.WriteLine($"Localization Error: No string id provided"); 25 | return LocalizationHelper.MissingStringId; 26 | } 27 | 28 | return LocalizationHelper.GetString(stringId); 29 | } 30 | 31 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 32 | { 33 | throw new NotImplementedException(); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /SmartHunter/Ui/Converters/NumberComparisonConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows.Data; 4 | 5 | namespace SmartHunter.Ui.Converters 6 | { 7 | public class NumberComparisonConverter : IValueConverter 8 | { 9 | public enum NumberComparison 10 | { 11 | Equal, 12 | Less, 13 | LessOrEqual, 14 | Greater, 15 | GreaterOrEqual, 16 | NotEqual 17 | } 18 | 19 | public bool Invert { get; set; } = false; 20 | public NumberComparison Comparison { get; set; } = NumberComparison.Equal; 21 | 22 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 23 | { 24 | bool result = false; 25 | 26 | if (value is int) 27 | { 28 | int first = (int)value; 29 | int second = 0; 30 | 31 | if (parameter != null) 32 | { 33 | var str = parameter as string; 34 | if (!int.TryParse(str, out second)) 35 | { 36 | return Binding.DoNothing; 37 | } 38 | } 39 | 40 | if (Comparison == NumberComparison.Equal && first == second) 41 | { 42 | result = true; 43 | } 44 | else if (Comparison == NumberComparison.Less && first < second) 45 | { 46 | result = true; 47 | } 48 | else if (Comparison == NumberComparison.LessOrEqual && first <= second) 49 | { 50 | result = true; 51 | } 52 | else if (Comparison == NumberComparison.Greater && first > second) 53 | { 54 | result = true; 55 | } 56 | else if (Comparison == NumberComparison.GreaterOrEqual && first >= second) 57 | { 58 | result = true; 59 | } 60 | else if (Comparison == NumberComparison.NotEqual && first != second) 61 | { 62 | result = true; 63 | } 64 | 65 | if (Invert) 66 | { 67 | result = !result; 68 | } 69 | } 70 | else if (value is float) 71 | { 72 | float first = (float)value; 73 | float second = 0; 74 | 75 | if (parameter != null) 76 | { 77 | var str = parameter as string; 78 | if (!float.TryParse(str, out second)) 79 | { 80 | return Binding.DoNothing; 81 | } 82 | } 83 | 84 | if (Comparison == NumberComparison.Equal && first == second) 85 | { 86 | result = true; 87 | } 88 | else if (Comparison == NumberComparison.Less && first < second) 89 | { 90 | result = true; 91 | } 92 | else if (Comparison == NumberComparison.LessOrEqual && first <= second) 93 | { 94 | result = true; 95 | } 96 | else if (Comparison == NumberComparison.Greater && first > second) 97 | { 98 | result = true; 99 | } 100 | else if (Comparison == NumberComparison.GreaterOrEqual && first >= second) 101 | { 102 | result = true; 103 | } 104 | else if (Comparison == NumberComparison.NotEqual && first != second) 105 | { 106 | result = true; 107 | } 108 | 109 | if (Invert) 110 | { 111 | result = !result; 112 | } 113 | } 114 | 115 | return result; 116 | } 117 | 118 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 119 | { 120 | throw new NotImplementedException(); 121 | } 122 | } 123 | } -------------------------------------------------------------------------------- /SmartHunter/Ui/Converters/NumberToCenteredMarginConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows; 4 | using System.Windows.Data; 5 | 6 | namespace SmartHunter.Ui.Converters 7 | { 8 | public class NumberToCenteredMarginConverter : IValueConverter 9 | { 10 | public static int Width { get { return 300; } } 11 | public static int Spacing { get { return 46; } } 12 | public static int MaxMonstersCount { get { return 3; } } 13 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 14 | { 15 | if (value is int) 16 | { 17 | if ((int)value <= MaxMonstersCount) 18 | { 19 | return new Thickness(((Width + Spacing) * (MaxMonstersCount - (int)value)) / ((int)value + 1), 0, Spacing, 0); 20 | } 21 | } 22 | return new Thickness(0, 0, Spacing, 0); 23 | } 24 | 25 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 26 | { 27 | throw new NotImplementedException(); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /SmartHunter/Ui/Converters/PlayerToPlayerIndexConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows.Data; 4 | using SmartHunter.Game.Data; 5 | using SmartHunter.Game.Data.ViewModels; 6 | 7 | namespace SmartHunter.Ui.Converters 8 | { 9 | public class PlayerToPlayerIndexConverter : IValueConverter 10 | { 11 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 12 | { 13 | var player = value as Player; 14 | 15 | if (OverlayViewModel.Instance.TeamWidget.Context.Players.Contains(player)) 16 | { 17 | return OverlayViewModel.Instance.TeamWidget.Context.Players.IndexOf(player); 18 | } 19 | 20 | return Binding.DoNothing; 21 | } 22 | 23 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 24 | { 25 | throw new NotImplementedException(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /SmartHunter/Ui/Converters/StringArrayContainsConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Linq; 4 | using System.Windows.Data; 5 | 6 | namespace SmartHunter.Ui.Converters 7 | { 8 | public class StringArrayContainsConverter : IValueConverter 9 | { 10 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 11 | { 12 | if (value is string[]) 13 | { 14 | var stringArray = (string[])value; 15 | return stringArray.Contains(parameter as string); 16 | } 17 | 18 | return Binding.DoNothing; 19 | } 20 | 21 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 22 | { 23 | throw new NotImplementedException(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /SmartHunter/Ui/Converters/StringFormatConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows.Data; 4 | 5 | namespace SmartHunter.Ui.Converters 6 | { 7 | public class StringFormatConverter : IMultiValueConverter 8 | { 9 | public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 10 | { 11 | if (parameter != null) 12 | { 13 | return String.Format(parameter.ToString(), values); 14 | } 15 | 16 | return Binding.DoNothing; 17 | } 18 | 19 | public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 20 | { 21 | throw new NotImplementedException(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /SmartHunter/Ui/Converters/WeaponTypeToNameConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows.Data; 4 | using SmartHunter.Game.Data; 5 | 6 | namespace SmartHunter.Ui.Converters 7 | { 8 | public class WeaponTypeToNameConverter : IValueConverter 9 | { 10 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 11 | { 12 | if (value is WeaponType) 13 | { 14 | if ((WeaponType)value == WeaponType.NO_WEAPON) 15 | { 16 | return ""; 17 | } 18 | if ((WeaponType)value == WeaponType.BOW) 19 | { 20 | return "Bow"; 21 | }if ((WeaponType)value == WeaponType.CHARGE_BLADE) 22 | { 23 | return "Charge Blade"; 24 | } 25 | if ((WeaponType)value == WeaponType.DUAL_BLADES) 26 | { 27 | return "Dual Blades"; 28 | } 29 | if ((WeaponType)value == WeaponType.GREAT_SWORD) 30 | { 31 | return "Great Sword"; 32 | } 33 | if ((WeaponType)value == WeaponType.GUNLANCE) 34 | { 35 | return "Gunlance"; 36 | } 37 | if ((WeaponType)value == WeaponType.HAMMER) 38 | { 39 | return "Hammer"; 40 | } 41 | if ((WeaponType)value == WeaponType.HEAVY_BOWGUN) 42 | { 43 | return "Heavy Bowgun"; 44 | } 45 | if ((WeaponType)value == WeaponType.HUNTING_HORN) 46 | { 47 | return "Hunting Horn"; 48 | } 49 | if ((WeaponType)value == WeaponType.INSECT_GLAIVE) 50 | { 51 | return "Insect Glaive"; 52 | } 53 | if ((WeaponType)value == WeaponType.KINSECT) 54 | { 55 | return "Kinsect"; 56 | } 57 | if ((WeaponType)value == WeaponType.LANCE) 58 | { 59 | return "Lance"; 60 | } 61 | if ((WeaponType)value == WeaponType.LIGHT_BOWGUN) 62 | { 63 | return "Light Bowgun"; 64 | } 65 | if ((WeaponType)value == WeaponType.LONG_SWORD) 66 | { 67 | return "Long Sword"; 68 | } 69 | if ((WeaponType)value == WeaponType.SLINGER) 70 | { 71 | return "Slinger"; 72 | } 73 | if ((WeaponType)value == WeaponType.SWITCH_AXE) 74 | { 75 | return "Switch Axe"; 76 | } 77 | if ((WeaponType)value == WeaponType.SWORD_AND_SHIELD) 78 | { 79 | return "Sword and Shield"; 80 | } 81 | } 82 | return "Unkown Weapon"; 83 | } 84 | 85 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 86 | { 87 | throw new NotImplementedException(); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /SmartHunter/Ui/Fonts/Roboto-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sir-wilhelm/SmartHunter/47b6f514916b823f9c05e6b3a1bb023b2bd27bf0/SmartHunter/Ui/Fonts/Roboto-Bold.ttf -------------------------------------------------------------------------------- /SmartHunter/Ui/Fonts/Roboto-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sir-wilhelm/SmartHunter/47b6f514916b823f9c05e6b3a1bb023b2bd27bf0/SmartHunter/Ui/Fonts/Roboto-Medium.ttf -------------------------------------------------------------------------------- /SmartHunter/Ui/Windows/ConsoleWindow.xaml: -------------------------------------------------------------------------------- 1 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /SmartHunter/Ui/Windows/ConsoleWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using SmartHunter.Game.Data.ViewModels; 3 | 4 | namespace SmartHunter.Ui.Windows 5 | { 6 | public partial class ConsoleWindow : Window 7 | { 8 | public ConsoleWindow() 9 | { 10 | InitializeComponent(); 11 | 12 | LogsTab.DataContext = ConsoleViewModel.Instance; 13 | SettingsTab.DataContext = SettingsViewModel.Instance; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /SmartHunter/Ui/Windows/DebugWidgetWindow.xaml: -------------------------------------------------------------------------------- 1 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /SmartHunter/Ui/Windows/DebugWidgetWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using SmartHunter.Core.Windows; 2 | using SmartHunter.Game.Data.ViewModels; 3 | using SmartHunter.Game.Helpers; 4 | 5 | namespace SmartHunter.Ui.Windows 6 | { 7 | public partial class DebugWidgetWindow : WidgetWindow 8 | { 9 | protected override float ScaleMax { get { return ConfigHelper.Main.Values.Overlay.ScaleMax; } } 10 | protected override float ScaleMin { get { return ConfigHelper.Main.Values.Overlay.ScaleMin; } } 11 | protected override float ScaleStep { get { return ConfigHelper.Main.Values.Overlay.ScaleStep; } } 12 | 13 | public DebugWidgetWindow() : base(OverlayViewModel.Instance.DebugWidget) 14 | { 15 | InitializeComponent(); 16 | 17 | DataContext = OverlayViewModel.Instance; 18 | 19 | 20 | } 21 | /* 22 | protected override void OnLoad(EventArgs e) 23 | { 24 | base.OnLoad(e); 25 | 26 | //Variable to hold the handle for the form 27 | var helper = new WindowInteropHelper(this).Handle; 28 | //Performing some magic to hide the form from Alt+Tab 29 | SetWindowLong(helper, GWL_EX_STYLE, (GetWindowLong(helper, GWL_EX_STYLE) | WS_EX_TOOLWINDOW) & ~WS_EX_APPWINDOW); 30 | } 31 | */ 32 | 33 | 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /SmartHunter/Ui/Windows/MonsterWidgetWindow.xaml: -------------------------------------------------------------------------------- 1 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /SmartHunter/Ui/Windows/MonsterWidgetWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using SmartHunter.Core.Windows; 2 | using SmartHunter.Game.Data.ViewModels; 3 | using SmartHunter.Game.Helpers; 4 | 5 | namespace SmartHunter.Ui.Windows 6 | { 7 | public partial class MonsterWidgetWindow : WidgetWindow 8 | { 9 | protected override float ScaleMax { get { return ConfigHelper.Main.Values.Overlay.ScaleMax; } } 10 | protected override float ScaleMin { get { return ConfigHelper.Main.Values.Overlay.ScaleMin; } } 11 | protected override float ScaleStep { get { return ConfigHelper.Main.Values.Overlay.ScaleStep; } } 12 | 13 | public MonsterWidgetWindow() : base(OverlayViewModel.Instance.MonsterWidget) 14 | { 15 | InitializeComponent(); 16 | 17 | DataContext = OverlayViewModel.Instance; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /SmartHunter/Ui/Windows/PlayerWidgetWindow.xaml: -------------------------------------------------------------------------------- 1 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /SmartHunter/Ui/Windows/PlayerWidgetWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using SmartHunter.Core.Windows; 2 | using SmartHunter.Game.Data.ViewModels; 3 | using SmartHunter.Game.Helpers; 4 | 5 | namespace SmartHunter.Ui.Windows 6 | { 7 | public partial class PlayerWidgetWindow : WidgetWindow 8 | { 9 | protected override float ScaleMax { get { return ConfigHelper.Main.Values.Overlay.ScaleMax; } } 10 | protected override float ScaleMin { get { return ConfigHelper.Main.Values.Overlay.ScaleMin; } } 11 | protected override float ScaleStep { get { return ConfigHelper.Main.Values.Overlay.ScaleStep; } } 12 | 13 | public PlayerWidgetWindow() : base(OverlayViewModel.Instance.PlayerWidget) 14 | { 15 | InitializeComponent(); 16 | 17 | DataContext = OverlayViewModel.Instance; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /SmartHunter/Ui/Windows/TeamWidgetWindow.xaml: -------------------------------------------------------------------------------- 1 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /SmartHunter/Ui/Windows/TeamWidgetWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using SmartHunter.Core.Windows; 2 | using SmartHunter.Game.Data.ViewModels; 3 | using SmartHunter.Game.Helpers; 4 | 5 | namespace SmartHunter.Ui.Windows 6 | { 7 | public partial class TeamWidgetWindow : WidgetWindow 8 | { 9 | protected override float ScaleMax { get { return ConfigHelper.Main.Values.Overlay.ScaleMax; } } 10 | protected override float ScaleMin { get { return ConfigHelper.Main.Values.Overlay.ScaleMin; } } 11 | protected override float ScaleStep { get { return ConfigHelper.Main.Values.Overlay.ScaleStep; } } 12 | 13 | public TeamWidgetWindow() : base(OverlayViewModel.Instance.TeamWidget) 14 | { 15 | InitializeComponent(); 16 | 17 | DataContext = OverlayViewModel.Instance; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /build/PackageRelease.ps1: -------------------------------------------------------------------------------- 1 | param([string]$Configuration="release") 2 | 3 | #Requires -Version 5.1 4 | $scriptPath = Split-Path $MyInvocation.MyCommand.Path 5 | $release = Join-Path $scriptPath "..\SmartHunter\bin\$Configuration\" 6 | $zip = Join-Path $release "SmartHunter.zip" 7 | 8 | $fileList = 9 | "SmartHunter.exe", 10 | "Newtonsoft.Json.dll", 11 | "Default.xaml" 12 | 13 | $Error.Clear() 14 | 15 | Push-Location $release 16 | Compress-Archive -LiteralPath $fileList -DestinationPath $zip -Force 17 | Pop-Location 18 | 19 | if($Error) 20 | { 21 | exit 1 22 | } 23 | 24 | exit 0 25 | -------------------------------------------------------------------------------- /build/build.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | dotnet build ..\ -c release 4 | 5 | REM publish command for self contained .exe 6 | REM dotnet publish ..\ -r win-x64 -c release 7 | -------------------------------------------------------------------------------- /doc/Config.json.md: -------------------------------------------------------------------------------- 1 | # `Config.json` documentation 2 | 3 | SmartHunter can be customized from the `Config.json` file (generated after first launch). 4 | Blelow are common settings that people might want to change. 5 | 6 | ## Global configurations 7 | `"LocalizationFileName": "en-US.json",` 8 | Changes the localization file used, defaults to `en-US.json`. 9 | 10 | `"AutomaticallyCheckAndDownloadUpdates": true,` 11 | defaults to `true`, set to `false` to disable. 12 | 13 | `"UpdatesPerSecond": 20,` 14 | The number time to check memory every second defaults to `20`, supports `1 to 60`. 15 | Increase to improve performance. 16 | 17 | ### Overlay configurations 18 | ## TeamWidget 19 | `"ShowNumbers": true,` 20 | defaults to `true`, set to `false` to disable. 21 | 22 | `"ShowPercents": true,` 23 | defaults to `true`, set to `false` to disable. 24 | 25 | `"IsVisible": true,` 26 | defaults to `true`, set to `false` to disable. 27 | 28 | ## MonsterWidget 29 | `"IncludePartGroupIdRegex": ".*",` 30 | Available options: Part, Removable 31 | 32 | `"IncludeStatusEffectGroupIdRegex": ".*",` 33 | Available options: StatusEffect, Rage, Stamina, and Fatigue. 34 | 35 | `"IsVisible": true,` 36 | defaults to `true`, set to `false` to disable. 37 | 38 | ## PlayerWidget 39 | `"IncludeStatusEffectGroupIdRegex": ".*",` 40 | Availalbe options: Horn, Coral, Debuff, Buff, Equipment, and Weapon 41 | 42 | `"IsVisible": true,` 43 | defaults to `true`, set to `false` to disable. 44 | 45 | # Example Config.json file 46 | ```json 47 | { 48 | "LocalizationFileName": "en-US.json", 49 | "SkinFileName": "Default.xaml", 50 | "MonsterDataFileName": "MonsterData.json", 51 | "PlayerDataFileName": "PlayerData.json", 52 | "MemoryFileName": "Memory.json", 53 | "ShutdownWhenProcessExits": false, 54 | "UseCustomData": false, 55 | "AutomaticallyCheckAndDownloadUpdates": true, 56 | "Overlay": { 57 | "ScaleMin": 0.5, 58 | "ScaleMax": 2, 59 | "ScaleStep": 0.1, 60 | "HideWhenGameWindowIsInactive": false, 61 | "UpdatesPerSecond": 20, 62 | "TeamWidget": { 63 | "DontShowIfAlone": false, 64 | "ShowBars": true, 65 | "ShowNumbers": true, 66 | "ShowPercents": true, 67 | "IsVisible": true, 68 | "X": 2276, 69 | "Y": 1064, 70 | "Scale": 1 71 | }, 72 | "MonsterWidget": { 73 | "IncludeMonsterIdRegex": "em[0-9]", 74 | "IncludePartGroupIdRegex": ".*", 75 | "IncludeStatusEffectGroupIdRegex": ".*", 76 | "ShowUnchangedMonsters": true, 77 | "HideMonstersAfterSeconds": 999, 78 | "ShowUnchangedParts": false, 79 | "HidePartsAfterSeconds": 12, 80 | "ShowUnchangedStatusEffects": false, 81 | "HideStatusEffectsAfterSeconds": 12, 82 | "ShowSize": false, 83 | "ShowCrown": true, 84 | "ShowBars": true, 85 | "ShowNumbers": true, 86 | "ShowPercents": true, 87 | "UseAnimations": false, 88 | "ShowOnlySelectedMonster": false, 89 | "IsVisible": true, 90 | "X": 945, 91 | "Y": 1, 92 | "Scale": 1 93 | }, 94 | "PlayerWidget": { 95 | "IncludeStatusEffectGroupIdRegex": ".*", 96 | "IsVisible": true, 97 | "X": -14, 98 | "Y": 446, 99 | "Scale": 1 100 | }, 101 | "DebugWidget": { 102 | "IsVisible": false, 103 | "X": 120, 104 | "Y": 320, 105 | "Scale": 1 106 | } 107 | }, 108 | "Keybinds": { 109 | "ManipulateWidget": "LeftAlt", 110 | "HideWidgets": "F1" 111 | }, 112 | "Debug": { 113 | "UseInternalSkin": false, 114 | "UseSampleData": false, 115 | "TraceUniquePointers": false, 116 | "ShowWeirdRemovableParts": false 117 | } 118 | } 119 | ``` 120 | --------------------------------------------------------------------------------