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