diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 31e896e9..da200cda 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -3,7 +3,7 @@ "isRoot": true, "tools": { "cake.tool": { - "version": "2.0.0", + "version": "4.0.0", "commands": [ "dotnet-cake" ] diff --git a/.editorconfig b/.editorconfig index fc9200a9..480efd97 100644 --- a/.editorconfig +++ b/.editorconfig @@ -37,9 +37,9 @@ dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggesti csharp_style_var_for_built_in_types = true:suggestion csharp_style_var_when_type_is_apparent = true:suggestion csharp_style_var_elsewhere = true:suggestion -csharp_style_expression_bodied_methods = false:suggestion -csharp_style_expression_bodied_constructors = false:suggestion -csharp_style_expression_bodied_operators = false:suggestion +csharp_style_expression_bodied_methods = when_on_single_line:suggestion +csharp_style_expression_bodied_constructors = when_on_single_line:suggestion +csharp_style_expression_bodied_operators = when_on_single_line:suggestion csharp_style_expression_bodied_properties = true:suggestion csharp_style_expression_bodied_indexers = true:suggestion csharp_style_expression_bodied_accessors = true:suggestion @@ -71,3 +71,75 @@ csharp_space_between_method_call_parameter_list_parentheses = false csharp_space_between_parentheses = false csharp_preserve_single_line_statements = true csharp_preserve_single_line_blocks = true +csharp_using_directive_placement = outside_namespace:silent +csharp_prefer_simple_using_statement = true:warning +csharp_style_namespace_declarations = block_scoped:silent +csharp_style_prefer_method_group_conversion = true:silent +csharp_style_prefer_top_level_statements = true:silent +csharp_style_expression_bodied_lambdas = when_on_single_line:silent +csharp_style_expression_bodied_local_functions = when_on_single_line:silent +csharp_style_prefer_primary_constructors = true:suggestion + +[*.{cs,vb}] +#### Naming styles #### + +# Naming rules + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +# Symbol specifications + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +# Naming styles + +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion +dotnet_style_prefer_auto_properties = true:silent +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_prefer_simplified_boolean_expressions = true:suggestion +dotnet_style_prefer_conditional_expression_over_assignment = true:silent +dotnet_style_prefer_conditional_expression_over_return = true:silent +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_operator_placement_when_wrapping = beginning_of_line +tab_width = 3 +indent_size = 3 +dotnet_style_allow_statement_immediately_after_block_experimental = true:silent diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3b15f21d..f4e846d4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,34 +1,53 @@ name: Build -on: [push, pull_request] +on: + push: + branches: + - "**" + pull_request: + workflow_dispatch: + +env: + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + DOTNET_NOLOGO: 1 jobs: test: runs-on: windows-latest steps: - - uses: actions/checkout@v1 - - uses: actions/setup-dotnet@v1 + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup dotnet + uses: actions/setup-dotnet@v4 with: - dotnet-version: | - 3.1.x - 6.0.300 + dotnet-version: | + 3.x + 5.x + 6.x + 7.x + 8.x + - name: Log dotnet info run: dotnet --info + - name: Run test run: ./build.ps1 --target=Test + build: runs-on: windows-latest if: github.ref == 'refs/heads/master' needs: test steps: - - uses: actions/checkout@v1 - - - uses: actions/setup-dotnet@v1 + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup dotnet + uses: actions/setup-dotnet@v4 with: - dotnet-version: | - 3.1.x - 6.0.300 + dotnet-version: '8.x' - name: Make repo pushable env: @@ -49,9 +68,11 @@ jobs: - name: Get target file id: getfilename shell: bash - run: echo "::set-output name=file::$(ls ./Harmony/bin/Release/HarmonyX*.nupkg)" - - - uses: actions/upload-artifact@v1 + run: | + echo "file=$(ls ./Harmony/bin/Release/HarmonyX*.nupkg)" >> "$GITHUB_OUTPUT" + + - name: Upload HarmonyX nupkg + uses: actions/upload-artifact@v4 with: - path: ${{ steps.getfilename.outputs.file }} name: HarmonyX + path: ${{ steps.getfilename.outputs.file }} diff --git a/.github/workflows/publish_release.yml b/.github/workflows/publish_release.yml index e2decbf1..e7e62be3 100644 --- a/.github/workflows/publish_release.yml +++ b/.github/workflows/publish_release.yml @@ -5,46 +5,47 @@ on: tags: - 'v*' +env: + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + DOTNET_NOLOGO: 1 + +permissions: + contents: write + jobs: build: runs-on: windows-latest steps: - - uses: actions/checkout@v1 - - uses: actions/setup-dotnet@v1 - with: - dotnet-version: | - 3.1.x - 6.0.300 + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup dotnet + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.x' + - name: Get Version id: get_version shell: bash run: | tag=${GITHUB_REF##*/} echo Current branch: ${tag:1} - echo ::set-output name=version_num::${tag:1} + echo "version_num=${tag:1}" >> "$GITHUB_OUTPUT" + - name: Run build script run: ./build.ps1 --target=Build shell: powershell + - name: Create Release - id: create_release - uses: actions/create-release@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + uses: softprops/action-gh-release@v2 with: - tag_name: ${{ github.ref }} - release_name: Release ${{ github.ref }} + name: Release ${{ github.ref }} body: "" draft: false prerelease: false - - name: Upload Release Asset - id: upload-release-asset - uses: actions/upload-release-asset@v1.0.1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ./Harmony/bin/Release/HarmonyX.${{ steps.get_version.outputs.version_num }}.nupkg - asset_name: HarmonyX.${{ steps.get_version.outputs.version_num }}.nupkg - asset_content_type: application/zip + token: ${{ secrets.GITHUB_TOKEN }} + files: | + ./Harmony/bin/Release/HarmonyX.${{ steps.get_version.outputs.version_num }}.nupkg diff --git a/.gitignore b/.gitignore index 7ed0fc89..6f806069 100644 --- a/.gitignore +++ b/.gitignore @@ -1,51 +1,99 @@ -## CakeBuild -/tools/ +/Harmony/Harmony.zip +# Build results +/Harmony/build +# Documentation +/Harmony/Documentation/api/.manifest +/Harmony/Documentation/api/*.html +/Harmony/Documentation/api/*.yml +/Harmony/Documentation/Documentation.dll + ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. +## +## Get latest from `dotnet new gitignore` + +# dotenv files +.env + # User-specific files +*.rsuser *.suo *.user *.userosscache *.sln.docstates + # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs + +# Mono auto generated files +mono_crash.* + # Build results -/Harmony/build [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ -[Xx]64/ -[Xx]86/ -[Bb]uild/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ bld/ [Bb]in/ [Oo]bj/ -# Visual Studio 2015 cache/options directory +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* -# NUNIT + +# NUnit *.VisualState.xml TestResult.xml +nunit-*.xml + # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ dlldata.c -# DNX + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET project.lock.json +project.fragment.lock.json artifacts/ + +# Tye +.tye/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio *_i.c *_p.c -*_i.h +*_h.h *.ilk *.meta *.obj +*.iobj *.pch *.pdb +*.ipdb *.pgc *.pgd *.rsp @@ -55,15 +103,19 @@ artifacts/ *.tlh *.tmp *.tmp_proj +*_wpftmp.csproj *.log +*.tlog *.vspscc *.vssscc .builds *.pidb *.svclog *.scc + # Chutzpah Test files _Chutzpah* + # Visual C++ cache files ipch/ *.aps @@ -73,36 +125,62 @@ ipch/ *.sdf *.cachefile *.VC.db +*.VC.VC.opendb + # Visual Studio profiler *.psess *.vsp *.vspx *.sap + +# Visual Studio Trace Files +*.e2e + # TFS 2012 Local Workspace $tf/ + # Guidance Automation Toolkit *.gpState + # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user -# JustCode is a .NET coding add-in -.JustCode + # TeamCity is a build add-in _TeamCity* + # DotCover is a Code Coverage Tool *.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + # NCrunch _NCrunch_* .*crunch*.local.xml nCrunchTemp_* + # MightyMoose *.mm.* AutoTest.Net/ + # Web workbench (sass) .sass-cache/ + # Installshield output folder [Ee]xpress/ + # DocProject is a documentation generator add-in DocProject/buildhelp/ DocProject/Help/*.HxT @@ -112,54 +190,82 @@ DocProject/Help/*.hhk DocProject/Help/*.hhp DocProject/Help/Html2 DocProject/Help/html + # Click-Once directory publish/ + # Publish Web Output *.[Pp]ublish.xml *.azurePubxml -# TODO: Un-comment the next line if you do not want to checkin -# your web deploy settings because they may include unencrypted -# passwords -#*.pubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml *.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + # NuGet Packages *.nupkg +# NuGet Symbol Packages +*.snupkg # The packages folder can be ignored because of Package Restore -**/packages/* +**/[Pp]ackages/* # except build/, which is used as an MSBuild target. -!**/packages/build/ +!**/[Pp]ackages/build/ # Uncomment if necessary however generally it will be regenerated when needed -#!**/packages/repositories.config -# NuGet v3's project.json files produces more ignoreable files +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files *.nuget.props *.nuget.targets + # Microsoft Azure Build Output csx/ *.build.csdef + # Microsoft Azure Emulator ecf/ rcf/ -# Windows Store app package directory + +# Windows Store app package directories and files AppPackages/ BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache -!*.[Cc]ache/ +!?*.[Cc]ache/ + # Others ClientBin/ -[Ss]tyle[Cc]op.* ~$* *~ *.dbmdl *.dbproj.schemaview +*.jfm *.pfx *.publishsettings -node_modules/ orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + # RIA/Silverlight projects Generated_Code/ + # Backup & report files from converting an old project file # to a newer Visual Studio version. Backup files are not needed, # because we have git ;-) @@ -167,23 +273,53 @@ _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + # SQL Server files *.mdf *.ldf +*.ndf + # Business Intelligence projects *.rdl.data *.bim.layout *.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + # Microsoft Fakes FakesAssemblies/ + # GhostDoc plugin setting file *.GhostDoc.xml + # Node.js Tools for Visual Studio .ntvs_analysis.dat +node_modules/ + # Visual Studio 6 build log *.plg + # Visual Studio 6 workspace options file *.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + # Visual Studio LightSwitch build output **/*.HTMLClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts @@ -191,17 +327,167 @@ FakesAssemblies/ **/*.Server/GeneratedArtifacts **/*.Server/ModelManifest.xml _Pvt_Extensions -# LightSwitch generated files -GeneratedArtifacts/ -ModelManifest.xml + # Paket dependency manager .paket/paket.exe +paket-files/ + # FAKE - F# Make .fake/ -/Harmony/Harmony.zip -# Documentation -/Harmony/Documentation/api/.manifest -/Harmony/Documentation/api/*.html -/Harmony/Documentation/api/*.yml -/Harmony/Documentation/Documentation.dll -.idea/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +tools/** +!tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml +.idea + +## +## Visual studio for Mac +## + + +# globs +Makefile.in +*.userprefs +*.usertasks +config.make +config.status +aclocal.m4 +install-sh +autom4te.cache/ +*.tar.gz +tarballs/ +test-results/ + +# Mac bundle stuff +*.dmg +*.app + +# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# Vim temporary swap files +*.swp diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 00000000..c2219f32 --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,10 @@ + + + + 2.12.0 + 2.12.0.0 + + 25.1.1 + + + diff --git a/Harmony.sln b/Harmony.sln index da7f0016..56087deb 100644 --- a/Harmony.sln +++ b/Harmony.sln @@ -1,7 +1,7 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29509.3 +# Visual Studio Version 17 +VisualStudioVersion = 17.8.34525.116 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{887FC7DA-9A29-4130-92E7-66E21E76CAC4}" ProjectSection(SolutionItems) = preProject @@ -9,27 +9,40 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution .gitattributes = .gitattributes .gitignore = .gitignore LICENSE = LICENSE + Directory.Build.props = Directory.Build.props README.md = README.md + build.cake = build.cake EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Harmony", "Harmony\Harmony.csproj", "{69AEE16A-B6E7-4642-8081-3928B32455DF}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HarmonyTests", "HarmonyTests\HarmonyTests.csproj", "{DEE74EFC-29A8-4704-8536-7DA38D3999F7}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestLibrary", "TestLibrary\TestLibrary.csproj", "{11F828EC-7C50-48F4-A30D-9BED06837F3A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU + ReleaseRef|Any CPU = ReleaseRef|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {69AEE16A-B6E7-4642-8081-3928B32455DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {69AEE16A-B6E7-4642-8081-3928B32455DF}.Debug|Any CPU.Build.0 = Debug|Any CPU {69AEE16A-B6E7-4642-8081-3928B32455DF}.Release|Any CPU.ActiveCfg = Release|Any CPU {69AEE16A-B6E7-4642-8081-3928B32455DF}.Release|Any CPU.Build.0 = Release|Any CPU + {69AEE16A-B6E7-4642-8081-3928B32455DF}.ReleaseRef|Any CPU.ActiveCfg = ReleaseRef|Any CPU + {69AEE16A-B6E7-4642-8081-3928B32455DF}.ReleaseRef|Any CPU.Build.0 = ReleaseRef|Any CPU {DEE74EFC-29A8-4704-8536-7DA38D3999F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {DEE74EFC-29A8-4704-8536-7DA38D3999F7}.Debug|Any CPU.Build.0 = Debug|Any CPU {DEE74EFC-29A8-4704-8536-7DA38D3999F7}.Release|Any CPU.ActiveCfg = Release|Any CPU {DEE74EFC-29A8-4704-8536-7DA38D3999F7}.Release|Any CPU.Build.0 = Release|Any CPU + {DEE74EFC-29A8-4704-8536-7DA38D3999F7}.ReleaseRef|Any CPU.ActiveCfg = Release|Any CPU + {11F828EC-7C50-48F4-A30D-9BED06837F3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {11F828EC-7C50-48F4-A30D-9BED06837F3A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {11F828EC-7C50-48F4-A30D-9BED06837F3A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {11F828EC-7C50-48F4-A30D-9BED06837F3A}.Release|Any CPU.Build.0 = Release|Any CPU + {11F828EC-7C50-48F4-A30D-9BED06837F3A}.ReleaseRef|Any CPU.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Harmony/Documentation/Harmony.afphoto b/Harmony/Documentation/Harmony.afphoto deleted file mode 100644 index 746a4877..00000000 Binary files a/Harmony/Documentation/Harmony.afphoto and /dev/null differ diff --git a/Harmony/Documentation/filterConfig.yml b/Harmony/Documentation/filterConfig.yml deleted file mode 100644 index b6604203..00000000 --- a/Harmony/Documentation/filterConfig.yml +++ /dev/null @@ -1,3 +0,0 @@ -apiRules: -- exclude: - uidRegex: ^HarmonyLib\.Code\. diff --git a/Harmony/Extras/DelegateTypeFactory.cs b/Harmony/Extras/DelegateTypeFactory.cs index 5b3042ec..7656b53f 100644 --- a/Harmony/Extras/DelegateTypeFactory.cs +++ b/Harmony/Extras/DelegateTypeFactory.cs @@ -15,11 +15,10 @@ namespace HarmonyLib public class DelegateTypeFactory { private static int counter; - private static readonly Dictionary> TypeCache = - new Dictionary>(); + private static readonly Dictionary> TypeCache = new(); private static readonly MethodBase CallingConvAttr = AccessTools.Constructor( typeof(UnmanagedFunctionPointerAttribute), - new[] {typeof(CallingConvention)}); + [typeof(CallingConvention)]); /// /// Instance for the delegate type factory @@ -27,7 +26,7 @@ public class DelegateTypeFactory /// /// Exists for API compatibility with Harmony /// - public static readonly DelegateTypeFactory instance = new DelegateTypeFactory(); + public static readonly DelegateTypeFactory instance = new(); /// /// Creates a delegate type for a method @@ -35,10 +34,7 @@ public class DelegateTypeFactory /// Type of the return value /// Types of the arguments /// The new delegate type for the given type info - public Type CreateDelegateType(Type returnType, Type[] argTypes) - { - return CreateDelegateType(returnType, argTypes, null); - } + public Type CreateDelegateType(Type returnType, Type[] argTypes) => CreateDelegateType(returnType, argTypes, null); /// /// Creates a delegate type for a method @@ -95,10 +91,7 @@ public Type CreateDelegateType(Type returnType, Type[] argTypes, CallingConventi /// Creates a delegate type for a method /// The method /// The new delegate type - public Type CreateDelegateType(MethodInfo method) - { - return CreateDelegateType(method, null); - } + public Type CreateDelegateType(MethodInfo method) => CreateDelegateType(method, null); /// Creates a delegate type for a method /// The method @@ -112,7 +105,7 @@ public Type CreateDelegateType(MethodInfo method, CallingConvention? convention) return entry.delegateType; if (entries == null) - TypeCache[method] = entries = new List(); + TypeCache[method] = entries = []; entry = new DelegateEntry { diff --git a/Harmony/Extras/FastAccess.cs b/Harmony/Extras/FastAccess.cs index 49a3d1d8..e58d4bb3 100644 --- a/Harmony/Extras/FastAccess.cs +++ b/Harmony/Extras/FastAccess.cs @@ -43,7 +43,7 @@ public static InstantiationHandler CreateInstantiationHandler() { var constructorInfo = typeof(T).GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, - new Type[0], null); + [], null); if (constructorInfo is null) { throw new ApplicationException(string.Format( @@ -110,11 +110,11 @@ public static GetterHandler CreateFieldGetter(params string[] names) foreach (var name in names) { var field = typeof(T).GetField(name, AccessTools.all); - if (field is object) + if (field is not null) return CreateGetterHandler(field); var property = typeof(T).GetProperty(name, AccessTools.all); - if (property is object) + if (property is not null) return CreateGetterHandler(property); } @@ -162,14 +162,8 @@ public static SetterHandler CreateSetterHandler(FieldInfo fieldInfo) return (SetterHandler)dynamicSet.Generate().CreateDelegate(typeof(SetterHandler)); } - static DynamicMethodDefinition CreateGetDynamicMethod(Type type) - { - return new DynamicMethodDefinition($"DynamicGet_{type.Name}", typeof(S), new Type[] { typeof(T) }); - } + static DynamicMethodDefinition CreateGetDynamicMethod(Type type) => new($"DynamicGet_{type.Name}", typeof(S), [typeof(T)]); - static DynamicMethodDefinition CreateSetDynamicMethod(Type type) - { - return new DynamicMethodDefinition($"DynamicSet_{type.Name}", typeof(void), new Type[] { typeof(T), typeof(S) }); - } + static DynamicMethodDefinition CreateSetDynamicMethod(Type type) => new($"DynamicSet_{type.Name}", typeof(void), [typeof(T), typeof(S)]); } } diff --git a/Harmony/Extras/MethodInvoker.cs b/Harmony/Extras/MethodInvoker.cs index b97311de..e1fbc2c4 100644 --- a/Harmony/Extras/MethodInvoker.cs +++ b/Harmony/Extras/MethodInvoker.cs @@ -49,7 +49,7 @@ public static class MethodInvoker /// public static FastInvokeHandler GetHandler(MethodInfo methodInfo, bool directBoxValueAccess = false) { - var dynamicMethod = new DynamicMethodDefinition($"FastInvoke_{methodInfo.Name}_{(directBoxValueAccess ? "direct" : "indirect")}", typeof(object), new Type[] { typeof(object), typeof(object[]) }); + var dynamicMethod = new DynamicMethodDefinition($"FastInvoke_{methodInfo.Name}_{(directBoxValueAccess ? "direct" : "indirect")}", typeof(object), [typeof(object), typeof(object[])]); var il = dynamicMethod.GetILGenerator(); if (!methodInfo.IsStatic) @@ -144,20 +144,11 @@ public static FastInvokeHandler GetHandler(MethodInfo methodInfo, bool directBox return invoder; } - internal static void Emit(ILGenerator il, OpCode opcode) - { - il.Emit(opcode); - } + internal static void Emit(ILGenerator il, OpCode opcode) => il.Emit(opcode); - internal static void Emit(ILGenerator il, OpCode opcode, Type type) - { - il.Emit(opcode, type); - } + internal static void Emit(ILGenerator il, OpCode opcode, Type type) => il.Emit(opcode, type); - internal static void EmitCall(ILGenerator il, OpCode opcode, MethodInfo methodInfo) - { - il.EmitCall(opcode, methodInfo, null); - } + internal static void EmitCall(ILGenerator il, OpCode opcode, MethodInfo methodInfo) => il.EmitCall(opcode, methodInfo, null); static void EmitUnboxIfNeeded(ILGenerator il, Type type) { diff --git a/Harmony/Extras/RefResult.cs b/Harmony/Extras/RefResult.cs new file mode 100644 index 00000000..c0cbe395 --- /dev/null +++ b/Harmony/Extras/RefResult.cs @@ -0,0 +1,5 @@ +namespace HarmonyLib; + +/// Delegate type for "ref return" injections +/// Return type of the original method, without ref modifier +public delegate ref T RefResult(); diff --git a/Harmony/ForwardingAttributes/Mono.Cecil.Cil.cs b/Harmony/ForwardingAttributes/Mono.Cecil.Cil.cs new file mode 100644 index 00000000..23b2e22e --- /dev/null +++ b/Harmony/ForwardingAttributes/Mono.Cecil.Cil.cs @@ -0,0 +1,46 @@ +#if NETFRAMEWORK || NETSTANDARD +using System.Runtime.CompilerServices; + +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.Code))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.ConstantDebugInformation))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.CustomDebugInformation))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.CustomDebugInformationKind))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.DebugInformation))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.Document))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.DocumentHashAlgorithm))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.DocumentLanguage))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.DocumentLanguageVendor))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.DocumentType))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.ExceptionHandler))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.ExceptionHandlerType))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.FlowControl))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.ILProcessor))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.ImageDebugDirectory))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.ImageDebugHeader))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.ImageDebugHeaderEntry))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.ImageDebugType))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.ImportDebugInformation))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.ImportTarget))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.ImportTargetKind))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.Instruction))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.InstructionOffset))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.ISymbolReader))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.ISymbolReaderProvider))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.ISymbolWriter))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.ISymbolWriterProvider))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.MethodBody))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.MethodDebugInformation))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.OpCode))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.OpCodes))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.OpCodeType))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.OperandType))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.ScopeDebugInformation))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.SequencePoint))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.StackBehaviour))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.SymbolsNotFoundException))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.SymbolsNotMatchingException))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.VariableAttributes))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.VariableDebugInformation))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.VariableDefinition))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.VariableReference))] +#endif diff --git a/Harmony/ForwardingAttributes/Mono.Cecil.Mdb.cs b/Harmony/ForwardingAttributes/Mono.Cecil.Mdb.cs new file mode 100644 index 00000000..24a23087 --- /dev/null +++ b/Harmony/ForwardingAttributes/Mono.Cecil.Mdb.cs @@ -0,0 +1,5 @@ +#if NETFRAMEWORK || NETSTANDARD +using System.Runtime.CompilerServices; + +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Mdb.MdbReader))] +#endif diff --git a/Harmony/ForwardingAttributes/Mono.Cecil.Pdb.cs b/Harmony/ForwardingAttributes/Mono.Cecil.Pdb.cs new file mode 100644 index 00000000..87ddb933 --- /dev/null +++ b/Harmony/ForwardingAttributes/Mono.Cecil.Pdb.cs @@ -0,0 +1,6 @@ +#if NETFRAMEWORK || NETSTANDARD +using System.Runtime.CompilerServices; + +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Pdb.NativePdbReader))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Pdb.NativePdbWriter))] +#endif diff --git a/Harmony/ForwardingAttributes/Mono.Cecil.Rocks.cs b/Harmony/ForwardingAttributes/Mono.Cecil.Rocks.cs new file mode 100644 index 00000000..f280f013 --- /dev/null +++ b/Harmony/ForwardingAttributes/Mono.Cecil.Rocks.cs @@ -0,0 +1,8 @@ +#if NETFRAMEWORK || NETSTANDARD +using System.Runtime.CompilerServices; + +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Rocks.IILVisitor))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Rocks.ILParser))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Rocks.ModuleDefinitionRocks))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Rocks.TypeDefinitionRocks))] +#endif diff --git a/Harmony/ForwardingAttributes/Mono.Cecil.cs b/Harmony/ForwardingAttributes/Mono.Cecil.cs new file mode 100644 index 00000000..f1989313 --- /dev/null +++ b/Harmony/ForwardingAttributes/Mono.Cecil.cs @@ -0,0 +1,89 @@ +#if NETFRAMEWORK || NETSTANDARD +using System.Runtime.CompilerServices; + +[assembly: TypeForwardedTo(typeof(Mono.Cecil.AssemblyAttributes))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.AssemblyDefinition))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.AssemblyHashAlgorithm))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.AssemblyNameDefinition))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.AssemblyNameReference))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.AssemblyResolutionException))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.ByReferenceType))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.CallSite))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.CustomAttribute))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.CustomAttributeArgument))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.CustomAttributeNamedArgument))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.EventAttributes))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.EventDefinition))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.EventReference))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.ExportedType))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.FieldAttributes))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.FieldDefinition))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.FieldReference))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.GenericInstanceMethod))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.GenericInstanceType))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.GenericParameter))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.GenericParameterAttributes))] +#if NET452_OR_GREATER || NETSTANDARD +[assembly: TypeForwardedTo(typeof(Mono.Cecil.GenericParameterConstraint))] +#endif +[assembly: TypeForwardedTo(typeof(Mono.Cecil.GenericParameterType))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.IAssemblyResolver))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.ICustomAttributeProvider))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.IGenericParameterProvider))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.IMemberDefinition))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.IMetadataImporter))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.IMetadataImporterProvider))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.IMetadataResolver))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.IMetadataScope))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.IMetadataTokenProvider))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.IMethodSignature))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.InterfaceImplementation))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.IReflectionImporter))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.IReflectionImporterProvider))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.ManifestResourceAttributes))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.MarshalInfo))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.MemberReference))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.MetadataKind))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.MetadataScopeType))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.MetadataToken))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.MetadataType))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.MethodAttributes))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.MethodCallingConvention))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.MethodDefinition))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.MethodImplAttributes))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.MethodReference))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.MethodReturnType))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.MethodSemanticsAttributes))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.ModuleAttributes))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.ModuleCharacteristics))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.ModuleDefinition))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.ModuleKind))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.ModuleParameters))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.ModuleReference))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.NativeType))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.ParameterAttributes))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.ParameterDefinition))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.ParameterReference))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.PInvokeAttributes))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.PInvokeInfo))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.PropertyAttributes))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.PropertyDefinition))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.PropertyReference))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.ReaderParameters))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.ReadingMode))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.ResolutionException))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.Resource))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.ResourceType))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.SecurityAction))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.SecurityAttribute))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.SecurityDeclaration))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.TargetArchitecture))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.TargetRuntime))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.TokenType))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.TypeAttributes))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.TypeDefinition))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.TypeReference))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.TypeSpecification))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.TypeSystem))] +[assembly: TypeForwardedTo(typeof(Mono.Cecil.WriterParameters))] +#endif diff --git a/Harmony/ForwardingAttributes/Mono.Collections.Generic.cs b/Harmony/ForwardingAttributes/Mono.Collections.Generic.cs new file mode 100644 index 00000000..ee777f6d --- /dev/null +++ b/Harmony/ForwardingAttributes/Mono.Collections.Generic.cs @@ -0,0 +1,5 @@ +#if NETFRAMEWORK || NETSTANDARD +using System.Runtime.CompilerServices; + +[assembly: TypeForwardedTo(typeof(Mono.Collections.Generic.Collection<>))] +#endif diff --git a/Harmony/ForwardingAttributes/Mono.CompilerServices.SymbolWriter.cs b/Harmony/ForwardingAttributes/Mono.CompilerServices.SymbolWriter.cs new file mode 100644 index 00000000..6c334824 --- /dev/null +++ b/Harmony/ForwardingAttributes/Mono.CompilerServices.SymbolWriter.cs @@ -0,0 +1,18 @@ +#if NETFRAMEWORK || NETSTANDARD +using System.Runtime.CompilerServices; + +[assembly: TypeForwardedTo(typeof(Mono.CompilerServices.SymbolWriter.AnonymousScopeEntry))] +[assembly: TypeForwardedTo(typeof(Mono.CompilerServices.SymbolWriter.CapturedScope))] +[assembly: TypeForwardedTo(typeof(Mono.CompilerServices.SymbolWriter.CapturedVariable))] +[assembly: TypeForwardedTo(typeof(Mono.CompilerServices.SymbolWriter.CodeBlockEntry))] +[assembly: TypeForwardedTo(typeof(Mono.CompilerServices.SymbolWriter.CompileUnitEntry))] +[assembly: TypeForwardedTo(typeof(Mono.CompilerServices.SymbolWriter.LineNumberEntry))] +[assembly: TypeForwardedTo(typeof(Mono.CompilerServices.SymbolWriter.LineNumberTable))] +[assembly: TypeForwardedTo(typeof(Mono.CompilerServices.SymbolWriter.LocalVariableEntry))] +[assembly: TypeForwardedTo(typeof(Mono.CompilerServices.SymbolWriter.MethodEntry))] +[assembly: TypeForwardedTo(typeof(Mono.CompilerServices.SymbolWriter.MonoSymbolFile))] +[assembly: TypeForwardedTo(typeof(Mono.CompilerServices.SymbolWriter.NamespaceEntry))] +[assembly: TypeForwardedTo(typeof(Mono.CompilerServices.SymbolWriter.OffsetTable))] +[assembly: TypeForwardedTo(typeof(Mono.CompilerServices.SymbolWriter.ScopeVariable))] +[assembly: TypeForwardedTo(typeof(Mono.CompilerServices.SymbolWriter.SourceFileEntry))] +#endif diff --git a/Harmony/ForwardingAttributes/MonoMod.Utils.Cil.cs b/Harmony/ForwardingAttributes/MonoMod.Utils.Cil.cs new file mode 100644 index 00000000..cd4aaf58 --- /dev/null +++ b/Harmony/ForwardingAttributes/MonoMod.Utils.Cil.cs @@ -0,0 +1,6 @@ +#if NETFRAMEWORK || NETSTANDARD +using System.Runtime.CompilerServices; + +[assembly: TypeForwardedTo(typeof(MonoMod.Utils.Cil.CecilILGenerator))] +[assembly: TypeForwardedTo(typeof(MonoMod.Utils.Cil.ILGeneratorShim))] +#endif diff --git a/Harmony/ForwardingAttributes/MonoMod.Utils.cs b/Harmony/ForwardingAttributes/MonoMod.Utils.cs new file mode 100644 index 00000000..ca6a4a1c --- /dev/null +++ b/Harmony/ForwardingAttributes/MonoMod.Utils.cs @@ -0,0 +1,11 @@ +#if NETFRAMEWORK || NETSTANDARD +using System.Runtime.CompilerServices; + +[assembly: TypeForwardedTo(typeof(MonoMod.Utils.DMDEmitDynamicMethodGenerator))] +[assembly: TypeForwardedTo(typeof(MonoMod.Utils.DMDGenerator<>))] +[assembly: TypeForwardedTo(typeof(MonoMod.Utils.DynamicMethodDefinition))] +[assembly: TypeForwardedTo(typeof(MonoMod.Utils.Extensions))] +[assembly: TypeForwardedTo(typeof(MonoMod.Utils.ICallSiteGenerator))] +[assembly: TypeForwardedTo(typeof(MonoMod.Utils.ReflectionHelper))] +[assembly: TypeForwardedTo(typeof(MonoMod.Utils.Relinker))] +#endif diff --git a/Harmony/GlobalSuppressions.cs b/Harmony/GlobalSuppressions.cs index 6e05a539..bc560d54 100644 --- a/Harmony/GlobalSuppressions.cs +++ b/Harmony/GlobalSuppressions.cs @@ -1,18 +1,25 @@ using System.Diagnostics.CodeAnalysis; -[assembly: SuppressMessage("Performance", "CA1825:Avoid zero-length array allocations.")] -[assembly: SuppressMessage("Performance", "CA1813:Avoid unsealed attributes")] -[assembly: SuppressMessage("Performance", "CA1810:Initialize reference type static fields inline")] -[assembly: SuppressMessage("Performance", "CA1822:Mark members as static")] -[assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types")] -[assembly: SuppressMessage("Design", "CA1018:Mark attributes with AttributeUsageAttribute")] -[assembly: SuppressMessage("Usage", "CA2211:Non-constant fields should not be visible")] -[assembly: SuppressMessage("Style", "IDE0057:Use range operator")] +[assembly: SuppressMessage("Performance", "CA1813")] +[assembly: SuppressMessage("Performance", "CA1810")] +[assembly: SuppressMessage("Performance", "CA1822")] +[assembly: SuppressMessage("Performance", "CA1825")] -[assembly: SuppressMessage("Code Quality", "IDE0051:Remove unused private members", Justification = "", Scope = "member", Target = "~F:HarmonyLib.Sandbox.SomeStruct_Net.b1")] -[assembly: SuppressMessage("Code Quality", "IDE0051:Remove unused private members", Justification = "", Scope = "member", Target = "~F:HarmonyLib.Sandbox.SomeStruct_Net.b2")] -[assembly: SuppressMessage("Code Quality", "IDE0051:Remove unused private members", Justification = "", Scope = "member", Target = "~F:HarmonyLib.Sandbox.SomeStruct_Net.b3")] -[assembly: SuppressMessage("Code Quality", "IDE0051:Remove unused private members", Justification = "", Scope = "member", Target = "~F:HarmonyLib.Sandbox.SomeStruct_Mono.b1")] -[assembly: SuppressMessage("Code Quality", "IDE0051:Remove unused private members", Justification = "", Scope = "member", Target = "~F:HarmonyLib.Sandbox.SomeStruct_Mono.b2")] -[assembly: SuppressMessage("Code Quality", "IDE0051:Remove unused private members", Justification = "", Scope = "member", Target = "~F:HarmonyLib.Sandbox.SomeStruct_Mono.b3")] -[assembly: SuppressMessage("Code Quality", "IDE0051:Remove unused private members", Justification = "", Scope = "member", Target = "~F:HarmonyLib.Sandbox.SomeStruct_Mono.b4")] +[assembly: SuppressMessage("Design", "CA1031")] +[assembly: SuppressMessage("Design", "CA1018")] + +[assembly: SuppressMessage("CodeQuality", "IDE0051")] +[assembly: SuppressMessage("CodeQuality", "IDE0057")] +[assembly: SuppressMessage("CodeQuality", "IDE0079")] + +[assembly: SuppressMessage("", "IDE0251")] +[assembly: SuppressMessage("Style", "IDE0270")] +[assembly: SuppressMessage("Usage", "CA2211")] +[assembly: SuppressMessage("GeneratedRegex", "SYSLIB1045")] + +[assembly: SuppressMessage("Reliability", "CA2020:Prevent from behavioral change", Justification = "", Scope = "member", Target = "~M:HarmonyLib.FileLog.LogBytes(System.Int64,System.Int32)")] +[assembly: SuppressMessage("Performance", "CA1850:Prefer static 'HashData' method over 'ComputeHash'", Justification = "", Scope = "member", Target = "~M:HarmonyLib.FileLog.LogBytes(System.Int64,System.Int32)")] + +#if NET8_0_OR_GREATER +[assembly: SuppressMessage("Maintainability", "CA1510")] +#endif diff --git a/Harmony/Harmony.csproj b/Harmony/Harmony.csproj index 3fe85012..00d4f1b9 100644 --- a/Harmony/Harmony.csproj +++ b/Harmony/Harmony.csproj @@ -1,55 +1,47 @@ - net35;net45;netstandard2.0 + net35;net452;netstandard2.0 true HarmonyX BepInEx Copyright © BepInEx 2022 - A library for patching, replacing and decorating .NET and Mono methods during runtime powered by MonoMod. + A general non-destructive patch library for .NET and Mono modules HarmonyX Andreas Pardeike, Geoffrey Horsington, ManlyMarco et al. 0Harmony true - 2.12.0 LICENSE https://github.com/BepInEx/HarmonyX false Harmony,Mono,Patch,Patching,Runtime,Detour,Detours,Aspect,Aspects - 2.12.0.0 - 2.12.0.0 logo_mini.png https://raw.githubusercontent.com/BepInEx/HarmonyX/master/logo_mini.png true true latest $(DefaultItemExcludes);Documentation/** + true + false + $(HarmonyXVersion) + $(HarmonyXVersionFull) + $(HarmonyXVersionFull) + $(HarmonyXVersion)$(HarmonyXVersionSuffix) + $(HarmonyXVersion)$(HarmonyXVersionSuffix) + $(NoWarn);SYSLIB0011;NU5131 + Debug;Release + true + true + $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb + True HarmonyLib - - - - - - - true - - - - - false - true - - - + + - - + false @@ -60,20 +52,27 @@ true - none - false + portable + true - + - - - - - + + - - - + + + + + + + + + + + + + @@ -86,15 +85,23 @@ - - - + + + + + + - - - - - - + + + + + + + + + + + diff --git a/Harmony/Internal/AccessCache.cs b/Harmony/Internal/AccessCache.cs index 4b43f212..ed8c4046 100644 --- a/Harmony/Internal/AccessCache.cs +++ b/Harmony/Internal/AccessCache.cs @@ -14,20 +14,20 @@ internal enum MemberType } const BindingFlags BasicFlags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty; - static readonly Dictionary declaredOnlyBindingFlags = new Dictionary() + static readonly Dictionary declaredOnlyBindingFlags = new() { { MemberType.Any, BasicFlags | BindingFlags.Instance | BindingFlags.Static }, { MemberType.Instance, BasicFlags | BindingFlags.Instance }, { MemberType.Static, BasicFlags | BindingFlags.Static } }; - readonly Dictionary> declaredFields = new Dictionary>(); - readonly Dictionary> declaredProperties = new Dictionary>(); - readonly Dictionary>> declaredMethods = new Dictionary>>(); + readonly Dictionary> declaredFields = []; + readonly Dictionary> declaredProperties = []; + readonly Dictionary>> declaredMethods = []; - readonly Dictionary> inheritedFields = new Dictionary>(); - readonly Dictionary> inheritedProperties = new Dictionary>(); - readonly Dictionary>> inheritedMethods = new Dictionary>>(); + readonly Dictionary> inheritedFields = []; + readonly Dictionary> inheritedProperties = []; + readonly Dictionary>> inheritedMethods = []; static T Get(Dictionary> dict, Type type, string name, Func fetcher) { @@ -35,7 +35,7 @@ static T Get(Dictionary> dict, Type type, string { if (dict.TryGetValue(type, out var valuesByName) is false) { - valuesByName = new Dictionary(); + valuesByName = []; dict[type] = valuesByName; } if (valuesByName.TryGetValue(name, out var value) is false) @@ -53,12 +53,12 @@ static T Get(Dictionary>> dict, T { if (dict.TryGetValue(type, out var valuesByName) is false) { - valuesByName = new Dictionary>(); + valuesByName = []; dict[type] = valuesByName; } if (valuesByName.TryGetValue(name, out var valuesByArgument) is false) { - valuesByArgument = new Dictionary(); + valuesByArgument = []; valuesByName[name] = valuesByArgument; } var argumentsHash = AccessTools.CombinedHashCode(arguments); diff --git a/Harmony/Internal/PatchArgumentExtensions.cs b/Harmony/Internal/PatchArgumentExtensions.cs index 71d62c96..8f091a7f 100644 --- a/Harmony/Internal/PatchArgumentExtensions.cs +++ b/Harmony/Internal/PatchArgumentExtensions.cs @@ -14,7 +14,7 @@ static HarmonyArgument[] AllHarmonyArguments(object[] attributes) if (attr.GetType().Name != nameof(HarmonyArgument)) return null; return AccessTools.MakeDeepCopy(attr); }) - .Where(harg => harg is object) + .Where(harg => harg is not null) .ToArray(); } @@ -67,7 +67,7 @@ static string GetOriginalArgumentName(HarmonyArgument[] attributes, string name, if (string.IsNullOrEmpty(attribute.OriginalName) is false) return attribute.OriginalName; - if (originalParameterNames is object && attribute.Index >= 0 && attribute.Index < originalParameterNames.Length) + if (originalParameterNames is not null && attribute.Index >= 0 && attribute.Index < originalParameterNames.Length) return originalParameterNames[attribute.Index]; return null; @@ -78,11 +78,11 @@ static string GetOriginalArgumentName(this MethodInfo method, string[] originalP string argumentName; argumentName = GetOriginalArgumentName(method?.GetArgumentAttributes(), name, originalParameterNames); - if (argumentName is object) + if (argumentName is not null) return argumentName; argumentName = GetOriginalArgumentName(method?.DeclaringType?.GetArgumentAttributes(), name, originalParameterNames); - if (argumentName is object) + if (argumentName is not null) return argumentName; return name; @@ -94,11 +94,11 @@ internal static int GetArgumentIndex(this MethodInfo patch, string[] originalPar return Array.IndexOf(originalParameterNames, patchParam.Name); var originalName = patchParam.GetOriginalArgumentName(originalParameterNames); - if (originalName is object) + if (originalName is not null) return Array.IndexOf(originalParameterNames, originalName); originalName = patch.GetOriginalArgumentName(originalParameterNames, patchParam.Name); - if (originalName is object) + if (originalName is not null) return Array.IndexOf(originalParameterNames, originalName); return -1; diff --git a/Harmony/Internal/PatchFunctions.cs b/Harmony/Internal/PatchFunctions.cs index 6bde474f..b0ae3618 100644 --- a/Harmony/Internal/PatchFunctions.cs +++ b/Harmony/Internal/PatchFunctions.cs @@ -4,6 +4,7 @@ using System.Reflection; using System.Reflection.Emit; using HarmonyLib.Internal.Patching; +using HarmonyLib.Internal.RuntimeFixes; using HarmonyLib.Internal.Util; using HarmonyLib.Public.Patching; using HarmonyLib.Tools; @@ -25,10 +26,7 @@ internal static class PatchFunctions /// Use debug mode /// The sorted patch methods /// - internal static List GetSortedPatchMethods(MethodBase original, Patch[] patches, bool debug) - { - return new PatchSorter(patches, debug).Sort(original); - } + internal static List GetSortedPatchMethods(MethodBase original, Patch[] patches, bool debug) => new PatchSorter(patches, debug).Sort(original); /// Sorts patch methods by their priority rules /// The original method @@ -36,10 +34,7 @@ internal static List GetSortedPatchMethods(MethodBase original, Patc /// Use debug mode /// The sorted patch methods /// - internal static Patch[] GetSortedPatchMethodsAsPatches(MethodBase original, Patch[] patches, bool debug) - { - return new PatchSorter(patches, debug).SortAsPatches(original); - } + internal static Patch[] GetSortedPatchMethodsAsPatches(MethodBase original, Patch[] patches, bool debug) => new PatchSorter(patches, debug).SortAsPatches(original); /// Creates new replacement method with the latest patches and detours the original method /// The original method @@ -105,7 +100,10 @@ static void PrintInfo(StringBuilder sb, ICollection methods, string }, debug); MethodBody patchBody = null; - var hook = new ILHook(standin.method, ctx => +#pragma warning disable CA2000 // pinned with PatchTools.RememberObject later + var hook = new ILHook( +#pragma warning restore CA2000 + standin.method, ctx => { if (!(original is MethodInfo mi)) return; @@ -132,6 +130,8 @@ static void PrintInfo(StringBuilder sb, ICollection methods, string HarmonyManipulator.ApplyManipulators(ctx, original, ilmanipulators, null); + StackTraceFixes.FixStackTrace(ctx); + // Normalize rets in case they get removed Instruction retIns = null; foreach (var instruction in ctx.Instrs.Where(i => i.OpCode == OpCodes.Ret)) @@ -158,7 +158,7 @@ static void PrintInfo(StringBuilder sb, ICollection methods, string } var replacement = hook.Method as MethodInfo; - PatchTools.RememberObject(standin.method, replacement); + PatchTools.RememberObject(standin.method, (replacement, hook)); return replacement; } @@ -188,20 +188,14 @@ internal static void UnpatchConditional(Func executionCondition) var originals = PatchProcessor.GetAllPatchedMethods().ToList(); // keep as is to avoid "Collection was modified" foreach (var original in originals) { - var hasBody = original.HasMethodBody(); var info = PatchProcessor.GetPatchInfo(original); var patchProcessor = new PatchProcessor(null, original); - if (hasBody) - { - info.Postfixes.DoIf(executionCondition, patchInfo => patchProcessor.Unpatch(patchInfo.PatchMethod)); - info.Prefixes.DoIf(executionCondition, patchInfo => patchProcessor.Unpatch(patchInfo.PatchMethod)); - } - + info.Postfixes.DoIf(executionCondition, patchInfo => patchProcessor.Unpatch(patchInfo.PatchMethod)); + info.Prefixes.DoIf(executionCondition, patchInfo => patchProcessor.Unpatch(patchInfo.PatchMethod)); info.ILManipulators.DoIf(executionCondition, patchInfo => patchProcessor.Unpatch(patchInfo.PatchMethod)); info.Transpilers.DoIf(executionCondition, patchInfo => patchProcessor.Unpatch(patchInfo.PatchMethod)); - if (hasBody) - info.Finalizers.DoIf(executionCondition, patchInfo => patchProcessor.Unpatch(patchInfo.PatchMethod)); + info.Finalizers.DoIf(executionCondition, patchInfo => patchProcessor.Unpatch(patchInfo.PatchMethod)); } } } diff --git a/Harmony/Internal/PatchModels.cs b/Harmony/Internal/PatchModels.cs index 4c479aef..b24042e4 100644 --- a/Harmony/Internal/PatchModels.cs +++ b/Harmony/Internal/PatchModels.cs @@ -14,11 +14,11 @@ internal class Job { internal MethodBase original; internal T replacement; - internal List prefixes = new List(); - internal List postfixes = new List(); - internal List transpilers = new List(); - internal List finalizers = new List(); - internal List ilmanipulators = new List(); + internal List prefixes = []; + internal List postfixes = []; + internal List transpilers = []; + internal List finalizers = []; + internal List ilmanipulators = []; internal void AddPatch(AttributePatch patch) { @@ -43,7 +43,7 @@ internal void AddPatch(AttributePatch patch) } } - internal Dictionary state = new Dictionary(); + internal Dictionary state = []; internal Job GetJob(MethodBase method) { @@ -67,24 +67,21 @@ internal List GetJobs() ).ToList(); } - internal List GetReplacements() - { - return state.Values.Select(job => job.replacement).ToList(); - } + internal List GetReplacements() => state.Values.Select(job => job.replacement).ToList(); } // AttributePatch contains all information for a patch defined by attributes // internal class AttributePatch { - static readonly HarmonyPatchType[] allPatchTypes = new[] { + static readonly HarmonyPatchType[] allPatchTypes = [ HarmonyPatchType.Prefix, HarmonyPatchType.Postfix, HarmonyPatchType.Transpiler, HarmonyPatchType.Finalizer, HarmonyPatchType.ReversePatch, HarmonyPatchType.ILManipulator, - }; + ]; internal HarmonyMethod info; internal HarmonyPatchType? type; @@ -105,7 +102,7 @@ internal static IEnumerable Create(MethodInfo patch, bool collec throw new ArgumentException("Patch method " + patch.FullDescription() + " must be static"); var list = allAttributes - .Where(attr => attr.GetType().BaseType.FullName == harmonyAttributeName) + .Where(attr => attr.GetType().BaseType.FullName == PatchTools.harmonyAttributeFullName) .Select(attr => { var f_info = AccessTools.Field(attr.GetType(), nameof(HarmonyAttribute.info)); @@ -116,8 +113,8 @@ internal static IEnumerable Create(MethodInfo patch, bool collec var completeMethods = new List(); - static bool Same(HarmonyMethod m1, HarmonyMethod m2) => m1.GetDeclaringType() == m2.GetDeclaringType() && m1.methodName == m2.methodName && m1.GetArgumentList().SequenceEqual(m2.GetArgumentList()); - static bool IsComplete(HarmonyMethod m, bool collectIncomplete) => (collectIncomplete || m.GetDeclaringType() != null) && m.methodName != null; + static bool Same(HarmonyMethod m1, HarmonyMethod m2) => m1.declaringType == m2.declaringType && m1.methodName == m2.methodName && m1.GetArgumentList().SequenceEqual(m2.GetArgumentList()); + static bool IsComplete(HarmonyMethod m, bool collectIncomplete) => (collectIncomplete || m.declaringType != null) && m.methodName != null; var groupedAttributes = list.ToLookup(m => IsComplete(m, collectIncomplete)); var incomplete = groupedAttributes[false].ToList(); diff --git a/Harmony/Internal/PatchSorter.cs b/Harmony/Internal/PatchSorter.cs index 0bf5ded7..0e3dc1cc 100644 --- a/Harmony/Internal/PatchSorter.cs +++ b/Harmony/Internal/PatchSorter.cs @@ -39,10 +39,8 @@ internal PatchSorter(Patch[] patches, bool debug = false) /// After first run the result is provided from the cache. /// The original method /// The sorted patch methods - internal List Sort(MethodBase original) - { - return SortAsPatches(original).Select(x => x.GetMethod(original)).ToList(); - } + internal List Sort(MethodBase original) => + SortAsPatches(original).Select(x => x.GetMethod(original)).ToList(); /// Sorts internal PatchSortingWrapper collection and caches the results. /// After first run the result is provided from the cache. @@ -51,11 +49,11 @@ internal List Sort(MethodBase original) internal Patch[] SortAsPatches(MethodBase original) { // Check if cache exists and the method was used before. - if (sortedPatchArray is object) return sortedPatchArray; + if (sortedPatchArray is not null) return sortedPatchArray; // Initialize internal structures used for sorting. - handledPatches = new HashSet(); - waitingList = new List(); + handledPatches = []; + waitingList = []; result = new List(patches.Count); var queue = new Queue(patches); @@ -101,7 +99,7 @@ internal Patch[] SortAsPatches(MethodBase original) internal bool ComparePatchLists(Patch[] patches) { if (sortedPatchArray is null) _ = Sort(null); - return patches is object && sortedPatchArray.Length == patches.Length + return patches is not null && sortedPatchArray.Length == patches.Length && sortedPatchArray.All(x => patches.Contains(x, new PatchDetailedComparer())); } @@ -175,8 +173,8 @@ class PatchSortingWrapper : IComparable internal PatchSortingWrapper(Patch patch) { innerPatch = patch; - before = new HashSet(); - after = new HashSet(); + before = []; + after = []; } /// Determines how patches sort @@ -191,17 +189,11 @@ public int CompareTo(object obj) /// Determines whether patches are equal /// The other patch /// true if equal - public override bool Equals(object obj) - { - return obj is PatchSortingWrapper wrapper && innerPatch.PatchMethod == wrapper.innerPatch.PatchMethod; - } + public override bool Equals(object obj) => obj is PatchSortingWrapper wrapper && innerPatch.PatchMethod == wrapper.innerPatch.PatchMethod; /// Hash function /// A hash code - public override int GetHashCode() - { - return innerPatch.PatchMethod.GetHashCode(); - } + public override int GetHashCode() => innerPatch.PatchMethod.GetHashCode(); /// Bidirectionally registers Patches as after dependencies /// List of dependencies to register @@ -246,16 +238,13 @@ internal class PatchDetailedComparer : IEqualityComparer { public bool Equals(Patch x, Patch y) { - return y is object && x is object && x.owner == y.owner && x.PatchMethod == y.PatchMethod && x.index == y.index + return y is not null && x is not null && x.owner == y.owner && x.PatchMethod == y.PatchMethod && x.index == y.index && x.priority == y.priority && x.before.Length == y.before.Length && x.after.Length == y.after.Length && x.before.All(y.before.Contains) && x.after.All(y.after.Contains); } - public int GetHashCode(Patch obj) - { - return obj.GetHashCode(); - } + public int GetHashCode(Patch obj) => obj.GetHashCode(); } } } diff --git a/Harmony/Internal/PatchTools.cs b/Harmony/Internal/PatchTools.cs index 65355073..9469c74f 100644 --- a/Harmony/Internal/PatchTools.cs +++ b/Harmony/Internal/PatchTools.cs @@ -1,3 +1,4 @@ +using MonoMod.Utils; using System; using System.Collections.Generic; using System.Linq; @@ -8,6 +9,10 @@ namespace HarmonyLib { internal static class PatchTools { + internal static readonly string harmonyMethodFullName = typeof(HarmonyMethod).FullName; + internal static readonly string harmonyAttributeFullName = typeof(HarmonyAttribute).FullName; + internal static readonly string harmonyPatchAllFullName = typeof(HarmonyPatchAll).FullName; + // Note: Even though this Dictionary is only stored to and never read from, it still needs to be thread-safe: // https://stackoverflow.com/a/33153868 // ThreadStatic has pitfalls (see RememberObject below), but since we must support net35, it's the best available option. @@ -21,6 +26,20 @@ internal static void RememberObject(object key, object value) objectReferences[key] = value; } + public static MethodInfo CreateMethod(string name, Type returnType, List> parameters, Action generator) + { + var parameterTypes = parameters.Select(p => p.Value).ToArray(); + var dynamicMethod = new DynamicMethodDefinition(name, returnType, parameterTypes); + + for (var i = 0; i < parameters.Count; i++) + dynamicMethod.Definition.Parameters[i].Name = parameters[i].Key; + + var il = dynamicMethod.GetILGenerator(); + generator(il); + + return dynamicMethod.Generate(); + } + internal static MethodInfo GetPatchMethod(Type patchType, string attributeName) { var method = patchType.GetMethods(AccessTools.all) @@ -37,7 +56,7 @@ internal static MethodInfo GetPatchMethod(Type patchType, string attributeName) internal static AssemblyBuilder DefineDynamicAssembly(string name) { var assemblyName = new AssemblyName(name); -#if NETCOREAPP2_0 || NETCOREAPP3_0 || NETCOREAPP3_1 || NETSTANDARD2_0 || NET6_0 +#if NETCOREAPP || NETSTANDARD return AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); #else return AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); @@ -47,8 +66,8 @@ internal static AssemblyBuilder DefineDynamicAssembly(string name) internal static List GetPatchMethods(Type type, bool collectIncomplete = false) { return AccessTools.GetDeclaredMethods(type) - .SelectMany(m => AttributePatch.Create(m, collectIncomplete)) - .Where(attributePatch => attributePatch is object) + .SelectMany(method => AttributePatch.Create(method, collectIncomplete)) + .Where(attributePatch => attributePatch is not null) .ToList(); } @@ -61,7 +80,7 @@ internal static MethodBase GetOriginalMethod(this HarmonyMethod attr) case MethodType.Normal: if (attr.methodName is null) return null; - return AccessTools.DeclaredMethod(attr.GetDeclaringType(), attr.methodName, attr.argumentTypes); + return AccessTools.DeclaredMethod(attr.declaringType, attr.methodName, attr.argumentTypes); case MethodType.Getter: if (attr.methodName is null) @@ -74,23 +93,25 @@ internal static MethodBase GetOriginalMethod(this HarmonyMethod attr) return AccessTools.DeclaredProperty(attr.declaringType, attr.methodName)?.GetSetMethod(true); case MethodType.Constructor: - return AccessTools.DeclaredConstructor(attr.GetDeclaringType(), attr.argumentTypes); + return AccessTools.DeclaredConstructor(attr.declaringType, attr.argumentTypes); case MethodType.StaticConstructor: return AccessTools - .GetDeclaredConstructors(attr.GetDeclaringType()) + .GetDeclaredConstructors(attr.declaringType) .FirstOrDefault(c => c.IsStatic); case MethodType.Enumerator: if (attr.methodName is null) return null; - return AccessTools.EnumeratorMoveNext(AccessTools.DeclaredMethod(attr.GetDeclaringType(), + return AccessTools.EnumeratorMoveNext(AccessTools.DeclaredMethod(attr.declaringType, attr.methodName, attr.argumentTypes)); +#if NET452_OR_GREATER || NETSTANDARD || NETCOREAPP case MethodType.Async: if (attr.methodName is null) return null; - return AccessTools.AsyncMoveNext(AccessTools.DeclaredMethod(attr.GetDeclaringType(), attr.methodName, attr.argumentTypes)); + return AccessTools.AsyncMoveNext(AccessTools.DeclaredMethod(attr.declaringType, attr.methodName, attr.argumentTypes)); +#endif } } catch (AmbiguousMatchException ex) diff --git a/Harmony/Internal/Util/MonoModHacks.cs b/Harmony/Internal/Util/MonoModHacks.cs new file mode 100644 index 00000000..f3bfe95d --- /dev/null +++ b/Harmony/Internal/Util/MonoModHacks.cs @@ -0,0 +1,30 @@ +using MonoMod.RuntimeDetour; +using System.Reflection; + +namespace HarmonyLib.Internal.Util; + +internal static class MonoModHacks +{ + // ReSharper disable once InconsistentNaming + private static readonly AccessTools.FieldRef ManagedDetourState_EndOfChain_Ref = + AccessTools.FieldRefAccess(AccessTools.DeclaredField( + typeof(DetourManager).GetNestedType("ManagedDetourState", AccessTools.all), + "EndOfChain" + )); + + // ReSharper disable once InconsistentNaming + private static readonly AccessTools.FieldRef MethodDetourInfo_State_Ref = + AccessTools.FieldRefAccess("state"); + + // ReSharper disable once InconsistentNaming + private static readonly AccessTools.FieldRef ILHook_State_Ref = + AccessTools.FieldRefAccess("state"); + + internal static MethodBase GetEndOfChain(this ILHook self) => + ManagedDetourState_EndOfChain_Ref(ILHook_State_Ref(self)); + + internal static MethodBase GetEndOfChain(this MethodDetourInfo self) => + ManagedDetourState_EndOfChain_Ref(MethodDetourInfo_State_Ref(self)); + + +} diff --git a/Harmony/Internal/Util/ReflectionTools.cs b/Harmony/Internal/Util/ReflectionTools.cs index 6ab96349..87a7d586 100644 --- a/Harmony/Internal/Util/ReflectionTools.cs +++ b/Harmony/Internal/Util/ReflectionTools.cs @@ -8,6 +8,8 @@ namespace HarmonyLib.Internal.Util { internal class ReflectionTools { + internal static readonly bool isWindows = Environment.OSVersion.Platform.Equals(PlatformID.Win32NT); + internal struct TypeAndName { internal Type type; @@ -56,7 +58,7 @@ internal static FieldRef FieldRefAccess(FieldInfo fieldInfo, bool ne var declaringType = fieldInfo.DeclaringType; var dm = new DynamicMethodDefinition($"__refget_{delegateInstanceType.Name}_fi_{fieldInfo.Name}", - typeof(F).MakeByRefType(), new[] { delegateInstanceType }); + typeof(F).MakeByRefType(), [delegateInstanceType]); var il = dm.GetILGenerator(); // Backwards compatibility: This supports static fields, even those defined in structs. @@ -86,7 +88,7 @@ internal static StructFieldRef StructFieldRefAccess(FieldInfo fieldI ValidateFieldType(fieldInfo); var dm = new DynamicMethodDefinition($"__refget_{typeof(T).Name}_struct_fi_{fieldInfo.Name}", - typeof(F).MakeByRefType(), new[] { typeof(T).MakeByRefType() }); + typeof(F).MakeByRefType(), [typeof(T).MakeByRefType()]); var il = dm.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); @@ -103,7 +105,7 @@ internal static FieldRef StaticFieldRefAccess(FieldInfo fieldInfo) ValidateFieldType(fieldInfo); var dm = new DynamicMethodDefinition($"__refget_{fieldInfo.DeclaringType?.Name ?? "null"}_static_fi_{fieldInfo.Name}", - typeof(F).MakeByRefType(), new Type[0]); + typeof(F).MakeByRefType(), []); var il = dm.GetILGenerator(); il.Emit(OpCodes.Ldsflda, fieldInfo); diff --git a/Harmony/Internal/Util/StackTraceFixes.cs b/Harmony/Internal/Util/StackTraceFixes.cs index 93d13b39..68b1d560 100644 --- a/Harmony/Internal/Util/StackTraceFixes.cs +++ b/Harmony/Internal/Util/StackTraceFixes.cs @@ -1,92 +1,93 @@ +using HarmonyLib.Internal.Util; +using HarmonyLib.Public.Patching; +using Mono.Cecil; +using Mono.Cecil.Cil; +using MonoMod.Cil; using System; -using System.Collections.Generic; using System.Diagnostics; using System.Reflection; -using HarmonyLib.Tools; using MonoMod.Core.Platforms; using MonoMod.RuntimeDetour; +using MonoMod.Utils; using System.Linq; namespace HarmonyLib.Internal.RuntimeFixes { /// /// Patching methods potentially messes up the stack. - /// Especially calls to GetExecutingAssembly won't turn in correct methods /// internal static class StackTraceFixes { private static bool _applied; - private static readonly Dictionary RealMethodMap = - new Dictionary(); - - private static Hook getAssemblyHookManaged; - private static NativeHook getAssemblyHookNative; - private static Hook getMethodHook; - public static void Install() { if (_applied) return; - try - { - DetourManager.ILHookApplied += OnILChainRefresh; - DetourManager.ILHookUndone += OnILChainRefresh; - - var getAssemblyMethod = AccessTools.DeclaredMethod(typeof(Assembly), nameof(Assembly.GetExecutingAssembly), EmptyType.NoArgs); - if (getAssemblyMethod.HasMethodBody()) - { - getAssemblyHookManaged = new Hook(getAssemblyMethod, GetAssemblyFix); - } - else - { - getAssemblyHookNative = new NativeHook(PlatformTriple.Current.GetNativeMethodBody(getAssemblyMethod), GetAssemblyFix); - } + DetourManager.ILHookApplied += OnILChainRefresh; + DetourManager.ILHookUndone += OnILChainRefresh; - getMethodHook = new Hook(AccessTools.DeclaredMethod(typeof(StackFrame), nameof(StackFrame.GetMethod), EmptyType.NoArgs), GetMethodFix); - } - catch (Exception e) - { - Logger.LogText(Logger.LogChannel.Error, $"Failed to apply stack trace fix: ({e.GetType().FullName}) {e.Message}"); - } _applied = true; } - delegate Assembly GetAssemblyDelegate(); - - // We need to force GetExecutingAssembly make use of stack trace - // This is to fix cases where calling assembly is actually the patch - // This solves issues with code where it uses the method to get current filepath etc - private static Assembly GetAssemblyFix(GetAssemblyDelegate orig) + // Helper to save the detour info after patch is complete + private static void OnILChainRefresh(ILHookInfo self) { - var entry = getAssemblyHookManaged?.DetourInfo.Entry ?? getAssemblyHookNative.DetourInfo.Entry; - var method = new StackTrace().GetFrames()!.Select(f => f.GetMethod()).SkipWhile(method => method != entry).Skip(1).First(); - return method.Module.Assembly; + PatchManager.AddReplacementOriginal( + PlatformTriple.Current.GetIdentifiable(self.Method.Method), + PlatformTriple.Current.GetIdentifiable(self.Method.GetEndOfChain()) + ); } - private static MethodBase GetMethodFix(Func orig, StackFrame self) + static Assembly GetExecutingAssemblyReplacement() { - var method = orig(self); - if (method is not null && RealMethodMap.TryGetValue(PlatformTriple.Current.GetIdentifiable(method), out var real)) - { - return real; - } - return method; + var frames = new StackTrace().GetFrames(); + if (frames?.Skip(1).FirstOrDefault() is { } frame && Harmony.GetOriginalMethodFromStackframe(frame) is { } original) + return original.Module.Assembly; + return Assembly.GetExecutingAssembly(); } - private static readonly AccessTools.FieldRef GetDetourState = AccessTools.FieldRefAccess(AccessTools.DeclaredField(typeof(MethodDetourInfo), "state")); + private static MethodBase GetMethodReplacement(StackFrame self) + { + var method = self.GetMethod(); + var original = PatchManager.GetOriginal(PlatformTriple.Current.GetIdentifiable(method) as MethodInfo); + return original ?? method; + } - private static readonly AccessTools.FieldRef GetEndOfChain = - AccessTools.FieldRefAccess(AccessTools.DeclaredField(typeof(DetourManager).GetNestedType("ManagedDetourState", AccessTools.all), "EndOfChain")); + // ReSharper disable InconsistentNaming + private static readonly MethodInfo GetExecutingAssembly_MethodInfo = + SymbolExtensions.GetMethodInfo(() => Assembly.GetExecutingAssembly()); + private static readonly MethodInfo GetExecutingAssemblyReplacement_MethodInfo = + SymbolExtensions.GetMethodInfo(() => GetExecutingAssemblyReplacement()); + private static readonly MethodInfo GetMethod_MethodInfo = + AccessTools.DeclaredMethod(typeof(StackFrame), nameof(StackFrame.GetMethod), Type.EmptyTypes); + private static readonly MethodInfo GetMethodReplacement_MethodInfo = + SymbolExtensions.GetMethodInfo(() => GetMethodReplacement(null)); + // ReSharper restore InconsistentNaming - // Helper to save the detour info after patch is complete - private static void OnILChainRefresh(ILHookInfo self) + internal static void FixStackTrace(ILContext il) { - lock (RealMethodMap) - { - RealMethodMap[PlatformTriple.Current.GetIdentifiable(GetEndOfChain(GetDetourState(self.Method)))] = PlatformTriple.Current.GetIdentifiable(self.Method.Method); - } + MethodReference getExecutingAssemblyReplacement = null; + MethodReference getMethodReplacement = null; + + var c = new ILCursor(il); + + foreach (var instr in c.Instrs) + { + if (instr.MatchCall(GetExecutingAssembly_MethodInfo)) + { + getExecutingAssemblyReplacement ??= il.Import(GetExecutingAssemblyReplacement_MethodInfo); + instr.Operand = getExecutingAssemblyReplacement; + } + else if (instr.MatchCallvirt(GetMethod_MethodInfo)) + { + getMethodReplacement ??= il.Import(GetMethodReplacement_MethodInfo); + instr.OpCode = OpCodes.Call; + instr.Operand = getMethodReplacement; + } + } } + } } diff --git a/Harmony/Properties/AssemblyInfo.cs b/Harmony/Properties/AssemblyInfo.cs index 21a0f898..bc3f4bce 100644 --- a/Harmony/Properties/AssemblyInfo.cs +++ b/Harmony/Properties/AssemblyInfo.cs @@ -3,9 +3,9 @@ [assembly: ComVisible(false)] [assembly: InternalsVisibleTo("HarmonyTests")] -// MonoMod.Common uses IgnoresAccessChecksTo on its end, +// MonoMod.Core uses IgnoresAccessChecksTo on its end, // but older versions of the .NET runtime bundled with older versions of Windows // require Harmony to expose its internals instead. -// This is only relevant for when MonoMod.Common gets merged into Harmony. +// This is only relevant for when MonoMod.Core gets merged into Harmony. [assembly: InternalsVisibleTo("MonoMod.Utils.Cil.ILGeneratorProxy")] [assembly: Guid("69aee16a-b6e7-4642-8081-3928b32455df")] diff --git a/Harmony/Properties/launchSettings.json b/Harmony/Properties/launchSettings.json deleted file mode 100644 index c16e8e8e..00000000 --- a/Harmony/Properties/launchSettings.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "profiles": { - "Harmony": { - "commandName": "Executable", - "executablePath": "C:\\Program Files (x86)\\RimWorld1722Win\\RimWorld1722Win.exe", - "workingDirectory": "C:\\Program Files (x86)\\RimWorld1722Win\\" - } - } -} \ No newline at end of file diff --git a/Harmony/Public/Attributes.cs b/Harmony/Public/Attributes.cs index 7fe50292..12d39ac5 100644 --- a/Harmony/Public/Attributes.cs +++ b/Harmony/Public/Attributes.cs @@ -1,4 +1,3 @@ -using MonoMod.RuntimeDetour; using System; using System.Collections; using System.Collections.Generic; @@ -22,7 +21,10 @@ public enum MethodType /// This is an enumerator (, or UniTask coroutine) /// This path will target the method that contains the actual enumerator code Enumerator, +#if NET452_OR_GREATER || NETSTANDARD || NETCOREAPP + /// This targets the MoveNext method of the async state machine, that actually contains the method's implementation Async +#endif } /// Specifies the type of argument @@ -110,7 +112,7 @@ public enum MethodDispatchType public class HarmonyAttribute : Attribute { /// The common information for all attributes - public HarmonyMethod info = new HarmonyMethod(); + public HarmonyMethod info = new(); } /// Annotation to define a category for use with PatchCategory @@ -121,10 +123,7 @@ public class HarmonyPatchCategory : HarmonyAttribute /// Annotation specifying the category /// Name of patch category /// - public HarmonyPatchCategory(string category) - { - info.category = category; - } + public HarmonyPatchCategory(string category) => info.category = category; } /// Annotation to define your Harmony patch methods @@ -141,10 +140,7 @@ public HarmonyPatch() /// An annotation that specifies a class to patch /// The declaring class/type /// - public HarmonyPatch(Type declaringType) - { - info.declaringType = declaringType; - } + public HarmonyPatch(Type declaringType) => info.declaringType = declaringType; /// An annotation that specifies a method, property or constructor to patch /// The declaring class/type @@ -267,10 +263,7 @@ public HarmonyPatch(Type declaringType, string methodName, MethodType methodType /// An annotation that specifies a method, property or constructor to patch /// The name of the method, property or constructor to patch /// - public HarmonyPatch(string methodName) - { - info.methodName = methodName; - } + public HarmonyPatch(string methodName) => info.methodName = methodName; /// An annotation that specifies a method, property or constructor to patch /// The name of the method, property or constructor to patch @@ -306,10 +299,7 @@ public HarmonyPatch(string methodName, MethodType methodType) /// An annotation that specifies a method, property or constructor to patch /// The /// - public HarmonyPatch(MethodType methodType) - { - info.methodType = methodType; - } + public HarmonyPatch(MethodType methodType) => info.methodType = methodType; /// An annotation that specifies a method, property or constructor to patch /// The @@ -335,19 +325,13 @@ public HarmonyPatch(MethodType methodType, Type[] argumentTypes, ArgumentType[] /// An annotation that specifies a method, property or constructor to patch /// An array of argument types to target overloads /// - public HarmonyPatch(Type[] argumentTypes) - { - info.argumentTypes = argumentTypes; - } + public HarmonyPatch(Type[] argumentTypes) => info.argumentTypes = argumentTypes; /// An annotation that specifies a method, property or constructor to patch /// An array of argument types to target overloads /// An array of /// - public HarmonyPatch(Type[] argumentTypes, ArgumentType[] argumentVariations) - { - ParseSpecialArguments(argumentTypes, argumentVariations); - } + public HarmonyPatch(Type[] argumentTypes, ArgumentType[] argumentVariations) => ParseSpecialArguments(argumentTypes, argumentVariations); /// An annotation that specifies a method, property or constructor to patch /// The full name of the declaring class/type @@ -390,7 +374,7 @@ void ParseSpecialArguments(Type[] argumentTypes, ArgumentType[] argumentVariatio } types.Add(type); } - info.argumentTypes = types.ToArray(); + info.argumentTypes = [.. types]; } } @@ -441,10 +425,7 @@ public HarmonyDelegate(Type declaringType, string methodName, Type[] argumentTyp /// The /// public HarmonyDelegate(Type declaringType, MethodDispatchType methodDispatchType) - : base(declaringType, MethodType.Normal) - { - info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call; - } + : base(declaringType, MethodType.Normal) => info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call; /// An annotation that specifies a method, property or constructor to patch /// The declaring class/type @@ -452,10 +433,7 @@ public HarmonyDelegate(Type declaringType, MethodDispatchType methodDispatchType /// An array of argument types to target overloads /// public HarmonyDelegate(Type declaringType, MethodDispatchType methodDispatchType, params Type[] argumentTypes) - : base(declaringType, MethodType.Normal, argumentTypes) - { - info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call; - } + : base(declaringType, MethodType.Normal, argumentTypes) => info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call; /// An annotation that specifies a method, property or constructor to patch /// The declaring class/type @@ -464,10 +442,7 @@ public HarmonyDelegate(Type declaringType, MethodDispatchType methodDispatchType /// Array of /// public HarmonyDelegate(Type declaringType, MethodDispatchType methodDispatchType, Type[] argumentTypes, ArgumentType[] argumentVariations) - : base(declaringType, MethodType.Normal, argumentTypes, argumentVariations) - { - info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call; - } + : base(declaringType, MethodType.Normal, argumentTypes, argumentVariations) => info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call; /// An annotation that specifies a method, property or constructor to patch /// The declaring class/type @@ -475,10 +450,7 @@ public HarmonyDelegate(Type declaringType, MethodDispatchType methodDispatchType /// The /// public HarmonyDelegate(Type declaringType, string methodName, MethodDispatchType methodDispatchType) - : base(declaringType, methodName, MethodType.Normal) - { - info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call; - } + : base(declaringType, methodName, MethodType.Normal) => info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call; /// An annotation that specifies a method, property or constructor to patch /// The name of the method, property or constructor to patch @@ -506,28 +478,19 @@ public HarmonyDelegate(string methodName, Type[] argumentTypes, ArgumentType[] a /// The /// public HarmonyDelegate(string methodName, MethodDispatchType methodDispatchType) - : base(methodName, MethodType.Normal) - { - info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call; - } + : base(methodName, MethodType.Normal) => info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call; /// An annotation that specifies call dispatching mechanics for the delegate /// The /// - public HarmonyDelegate(MethodDispatchType methodDispatchType) - { - info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call; - } + public HarmonyDelegate(MethodDispatchType methodDispatchType) => info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call; /// An annotation that specifies a method, property or constructor to patch /// The /// An array of argument types to target overloads /// public HarmonyDelegate(MethodDispatchType methodDispatchType, params Type[] argumentTypes) - : base(MethodType.Normal, argumentTypes) - { - info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call; - } + : base(MethodType.Normal, argumentTypes) => info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call; /// An annotation that specifies a method, property or constructor to patch /// The @@ -535,10 +498,7 @@ public HarmonyDelegate(MethodDispatchType methodDispatchType, params Type[] argu /// An array of /// public HarmonyDelegate(MethodDispatchType methodDispatchType, Type[] argumentTypes, ArgumentType[] argumentVariations) - : base(MethodType.Normal, argumentTypes, argumentVariations) - { - info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call; - } + : base(MethodType.Normal, argumentTypes, argumentVariations) => info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call; /// An annotation that specifies a method, property or constructor to patch /// An array of argument types to target overloads @@ -562,10 +522,7 @@ public class HarmonyReversePatch : HarmonyAttribute /// An annotation that specifies the type of reverse patching /// The of the reverse patch /// - public HarmonyReversePatch(HarmonyReversePatchType type = HarmonyReversePatchType.Original) - { - info.reversePatchType = type; - } + public HarmonyReversePatch(HarmonyReversePatchType type = HarmonyReversePatchType.Original) => info.reversePatchType = type; } /// A Harmony annotation to define that all methods in a class are to be patched @@ -583,10 +540,7 @@ public class HarmonyPriority : HarmonyAttribute /// A Harmony annotation to define patch priority /// The priority /// - public HarmonyPriority(int priority) - { - info.priority = priority; - } + public HarmonyPriority(int priority) => info.priority = priority; } /// A Harmony annotation to define that a patch comes before another patch @@ -597,10 +551,7 @@ public class HarmonyBefore : HarmonyAttribute /// A Harmony annotation to define that a patch comes before another patch /// The array of harmony IDs of the other patches /// - public HarmonyBefore(params string[] before) - { - info.before = before; - } + public HarmonyBefore(params string[] before) => info.before = before; } /// A Harmony annotation to define that a patch comes after another patch @@ -610,10 +561,7 @@ public class HarmonyAfter : HarmonyAttribute /// A Harmony annotation to define that a patch comes after another patch /// The array of harmony IDs of the other patches /// - public HarmonyAfter(params string[] after) - { - info.after = after; - } + public HarmonyAfter(params string[] after) => info.after = after; } /// A Harmony annotation to output a debug log for a patch @@ -622,10 +570,7 @@ public class HarmonyDebug : HarmonyAttribute { /// A Harmony annotation to debug a patch (output uses to log to your Desktop) /// - public HarmonyDebug() - { - info.debug = true; - } + public HarmonyDebug() => info.debug = true; } /// A Harmony annotation to emit IL of the patch to a DLL @@ -635,18 +580,12 @@ public class HarmonyEmitIL : HarmonyAttribute { /// A Harmony annotation to emit IL of the patch to the current working directory /// - public HarmonyEmitIL() - { - info.debugEmitPath = "./"; - } + public HarmonyEmitIL() => info.debugEmitPath = "./"; /// A Harmony annotation to emit IL of the patch to the given path /// Directory to which emit the patch /// - public HarmonyEmitIL(string dir) - { - info.debugEmitPath = dir; - } + public HarmonyEmitIL(string dir) => info.debugEmitPath = dir; } /// A Harmony attribute to automatically wrap the patch into try/catch. Exceptions are logged to Harmony log and eaten. @@ -656,10 +595,7 @@ public class HarmonyWrapSafe : HarmonyAttribute { /// If specified on a prefix, postfix or a finalizer, the method will be automatically wrapped into try/catch. /// - public HarmonyWrapSafe() - { - info.wrapTryCatch = true; - } + public HarmonyWrapSafe() => info.wrapTryCatch = true; } /// Specifies the Prepare function in a patch class diff --git a/Harmony/Public/CodeInstruction.cs b/Harmony/Public/CodeInstruction.cs index d4692609..454c889c 100644 --- a/Harmony/Public/CodeInstruction.cs +++ b/Harmony/Public/CodeInstruction.cs @@ -1,4 +1,3 @@ -using MonoMod.Utils; using System; using System.Collections.Generic; using System.Linq; @@ -23,11 +22,11 @@ public class CodeInstruction /// All labels defined on this instruction /// - public List