diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d2da10f66..00aa44c22 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,4 +1,5 @@ name: Build MelonLoader +run-name: ${{ vars.DEVVERSION }}${{ github.event_name != 'workflow_dispatch' && format('-ci.{0}', github.run_number) || '' }} | ${{ github.event_name != 'workflow_dispatch' && (github.event.head_commit.message || format('`[PR]` {0}', github.event.pull_request.title)) || 'Manual Build' }} on: push: @@ -8,35 +9,47 @@ on: workflow_dispatch: jobs: - build_core_debug: + build_core: + name: Build Managed Binaries runs-on: windows-latest steps: - uses: actions/checkout@v4 - - name: setup-msbuild - uses: microsoft/setup-msbuild@v2 - - name: Build Melonloader Core - shell: cmd - run: msbuild /restore /p:Platform="Windows - x64" # Platform is actually irrelevant for core, it's compiled as AnyCPU either way - - name: Upload core artifact + - name: Setup dotnet + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 8.0.x + + - name: Restore Dependencies + run: dotnet restore + + - name: Build Melonloader Core Debug + run: dotnet build --no-restore -c Debug -p:Platform="Windows - x64" -p:Version="${{ vars.DEVVERSION }}${{ github.event_name != 'workflow_dispatch' && format('.{0}', github.run_number) || '' }}" # Platform is actually irrelevant for core, it's compiled as AnyCPU either way + + - name: Upload Debug Core Artifact uses: actions/upload-artifact@v4 with: name: MLCoreDebug path: Output/Debug/MelonLoader/ - build_core_release: - runs-on: windows-latest - steps: - - uses: actions/checkout@v4 - - name: setup-msbuild - uses: microsoft/setup-msbuild@v2 - - name: Build Melonloader Core - shell: cmd - run: msbuild /restore /p:Configuration=Release /p:Platform="Windows - x64" - - name: Upload core artifact + + - name: Build MelonLoader Core Release + run: dotnet build --no-restore -c Release -p:Platform="Windows - x64" -p:Version="${{ vars.DEVVERSION }}${{ github.event_name != 'workflow_dispatch' && format('.{0}', github.run_number) || '' }}" + + - name: Upload Release Core Artifact uses: actions/upload-artifact@v4 with: name: MLCoreRelease path: Output/Release/MelonLoader/ + + - name: Pack NuGet Package + run: dotnet pack --no-build -c Release -p:Version="${{ vars.DEVVERSION }}${{ github.event_name != 'workflow_dispatch' && format('-ci.{0}', github.run_number) || '' }}" + + - name: Upload NuGet Artifact + uses: actions/upload-artifact@v4 + with: + name: MelonLoader.NuGet + path: Output/Release/MelonLoader/LavaGang.MelonLoader.${{ vars.DEVVERSION }}${{ github.event_name != 'workflow_dispatch' && format('-ci.{0}', github.run_number) || '' }}.nupkg build_rust_windows: + name: Build Native Binaries (Windows) runs-on: windows-latest steps: - uses: actions/checkout@v4 @@ -109,6 +122,7 @@ jobs: name: MLBootstrapX64-Windows-Debug path: target/x86_64-pc-windows-msvc/debug/Bootstrap.dll build_rust_linux: + name: Build Native Binaries (Linux) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -150,279 +164,250 @@ jobs: with: name: MLBootstrapX64-Linux-Debug path: target/x86_64-unknown-linux-gnu/debug/libBootstrap.so - finalize_x64_debug_zip_windows: - runs-on: windows-latest - needs: [build_core_debug, build_rust_windows] + + finalize_windows: + name: Finalize Windows Artifacts + runs-on: ubuntu-22.04 + needs: [build_core, build_rust_windows] steps: - uses: actions/checkout@v4 - - name: Download core artifact + - name: Download Debug Managed Artifact uses: actions/download-artifact@v4 with: name: MLCoreDebug - path: Output/Debug/x64/MelonLoader/ - - name: Download proxy x64 + path: Output/Debug/Managed/ + - name: Download Debug Proxy x64 Artifact uses: actions/download-artifact@v4 with: name: MLProxyX64-Windows-Debug path: Output/Debug/x64/ - - name: Download bootstrap x64 + - name: Download Debug Bootstrap x64 Artifact uses: actions/download-artifact@v4 with: name: MLBootstrapX64-Windows-Debug path: Output/Debug/x64/MelonLoader/Dependencies/ - - name: Package x64 zip - shell: cmd + - name: Package Debug x64 Artifact run: | echo Copying Managed Libs... - mkdir Output\Debug\x64\MelonLoader\Dependencies\Mono - xcopy BaseLibs\Mono Output\Debug\x64\MelonLoader\Dependencies\Mono\ /E /H /Y - xcopy BaseLibs\net35 Output\Debug\x64\MelonLoader\net35\ /E /H /Y - xcopy BaseLibs\net6 Output\Debug\x64\MelonLoader\net6\ /E /H /Y - echo. + mkdir -p Output/Debug/x64/MelonLoader/Dependencies/Mono + cp -r Output/Debug/Managed/* Output/Debug/x64/MelonLoader/ + cp -r BaseLibs/Mono Output/Debug/x64/MelonLoader/Dependencies/ + cp -r BaseLibs/net35 Output/Debug/x64/MelonLoader/ + cp -r BaseLibs/net6 Output/Debug/x64/MelonLoader/ + mkdir -p Output/Debug/x64/MelonLoader/Dependencies/SupportModules/NetStandardPatches + cp -r BaseLibs/NetStandardPatches Output/Debug/x64/MelonLoader/Dependencies/SupportModules/NetStandardPatches + echo echo Copying Dobby x64... - xcopy BaseLibs\dobby_x64.dll Output\Debug\x64\MelonLoader\Dependencies\dobby.dll* - echo. + cp BaseLibs/dobby_x64.dll Output/Debug/x64/MelonLoader/Dependencies/dobby.dll + echo echo Copying documentation files... - copy NOTICE.txt Output\Debug\x64 - mkdir Output\Debug\x64\MelonLoader\Documentation - copy CHANGELOG.md Output\Debug\x64\MelonLoader\Documentation\ - copy LICENSE.md Output\Debug\x64\MelonLoader\Documentation\ - copy NOTICE.txt Output\Debug\x64\MelonLoader\Documentation\ - copy README.md Output\Debug\x64\MelonLoader\Documentation\ - del Output\Debug\x64\MelonLoader\net6\MelonStartScreen.dll - del Output\Debug\x64\MelonLoader\net6\MelonStartScreen.deps.json + mkdir -p Output/Debug/x64/MelonLoader/Documentation + cp CHANGELOG.md Output/Debug/x64/MelonLoader/Documentation/ + cp LICENSE.md Output/Debug/x64/MelonLoader/Documentation/ + cp NOTICE.txt Output/Debug/x64/MelonLoader/Documentation/ + cp README.md Output/Debug/x64/MelonLoader/Documentation/ - uses: actions/upload-artifact@v4 - name: Upload Zip | Windows - x64 + name: Upload Zip | Windows - Debug - x64 with: name: MelonLoader.Windows.x64.CI.Debug path: ./Output/Debug/x64/* - finalize_x86_debug_zip_windows: - runs-on: windows-latest - needs: [build_core_debug, build_rust_windows] - steps: - - uses: actions/checkout@v4 - - name: Download core artifact - uses: actions/download-artifact@v4 - with: - name: MLCoreDebug - path: Output/Debug/x86/MelonLoader/ - - name: Download proxy x86 - uses: actions/download-artifact@v4 - with: - name: MLProxyX86-Windows-Debug - path: Output/Debug/x86/ - - name: Download bootstrap x86 - uses: actions/download-artifact@v4 - with: - name: MLBootstrapX86-Windows-Debug - path: Output/Debug/x86/MelonLoader/Dependencies/ - - name: Package x86 zip - shell: cmd - run: | - echo Copying Managed Libs... - mkdir Output\Debug\x86\MelonLoader\Dependencies\Mono - xcopy BaseLibs\Mono Output\Debug\x86\MelonLoader\Dependencies\Mono\ /E /H /Y - xcopy BaseLibs\net35 Output\Debug\x86\MelonLoader\net35\ /E /H /Y - xcopy BaseLibs\net6 Output\Debug\x86\MelonLoader\net6\ /E /H /Y - echo. - echo Copying Dobby x86... - xcopy BaseLibs\dobby_x86.dll Output\Debug\x86\MelonLoader\Dependencies\dobby.dll* - echo. - echo Copying documentation files... - copy NOTICE.txt Output\Debug\x86 - mkdir Output\Debug\x86\MelonLoader\Documentation - copy CHANGELOG.md Output\Debug\x86\MelonLoader\Documentation\ - copy LICENSE.md Output\Debug\x86\MelonLoader\Documentation\ - copy NOTICE.txt Output\Debug\x86\MelonLoader\Documentation\ - copy README.md Output\Debug\x86\MelonLoader\Documentation\ - del Output\Debug\x86\MelonLoader\net6\MelonStartScreen.dll - del Output\Debug\x86\MelonLoader\net6\MelonStartScreen.deps.json - - uses: actions/upload-artifact@v4 - name: Upload Zip | Windows - x86 - with: - name: MelonLoader.Windows.x86.CI.Debug - path: ./Output/Debug/x86/* - finalize_x64_release_zip_windows: - runs-on: windows-latest - needs: [build_core_release, build_rust_windows] - steps: - - uses: actions/checkout@v4 - - name: Download core artifact + + - name: Download Release Managed Artifact uses: actions/download-artifact@v4 with: name: MLCoreRelease - path: Output/Release/x64/MelonLoader/ - - name: Download proxy x64 + path: Output/Release/Managed/ + - name: Download Release Proxy x64 Artifact uses: actions/download-artifact@v4 with: name: MLProxyX64-Windows-Release path: Output/Release/x64/ - - name: Download bootstrap x64 + - name: Download Debug Bootstrap x64 Artifact uses: actions/download-artifact@v4 with: name: MLBootstrapX64-Windows-Release path: Output/Release/x64/MelonLoader/Dependencies/ - - name: Package x64 zip - shell: cmd + - name: Package Release x64 Artifact run: | echo Copying Managed Libs... - mkdir Output\Release\x64\MelonLoader\Dependencies\Mono - xcopy BaseLibs\Mono Output\Release\x64\MelonLoader\Dependencies\Mono\ /E /H /Y - xcopy BaseLibs\net35 Output\Release\x64\MelonLoader\net35\ /E /H /Y - xcopy BaseLibs\net6 Output\Release\x64\MelonLoader\net6\ /E /H /Y - echo. + mkdir -p Output/Release/x64/MelonLoader/Dependencies/Mono + cp -r Output/Release/Managed/* Output/Release/x64/MelonLoader/ + cp -r BaseLibs/Mono Output/Release/x64/MelonLoader/Dependencies/ + cp -r BaseLibs/net35 Output/Release/x64/MelonLoader/ + cp -r BaseLibs/net6 Output/Release/x64/MelonLoader/ + mkdir -p Output/Release/x64/MelonLoader/Dependencies/SupportModules/NetStandardPatches + cp -r BaseLibs/NetStandardPatches Output/Release/x64/MelonLoader/Dependencies/SupportModules/NetStandardPatches + echo echo Copying Dobby x64... - xcopy BaseLibs\dobby_x64.dll Output\Release\x64\MelonLoader\Dependencies\dobby.dll* - echo. + cp BaseLibs/dobby_x64.dll Output/Release/x64/MelonLoader/Dependencies/dobby.dll + echo echo Copying documentation files... - copy NOTICE.txt Output\Release\x64 - mkdir Output\Release\x64\MelonLoader\Documentation - copy CHANGELOG.md Output\Release\x64\MelonLoader\Documentation\ - copy LICENSE.md Output\Release\x64\MelonLoader\Documentation\ - copy NOTICE.txt Output\Release\x64\MelonLoader\Documentation\ - copy README.md Output\Release\x64\MelonLoader\Documentation\ - del Output\Release\x64\MelonLoader\net6\MelonStartScreen.dll - del Output\Release\x64\MelonLoader\net6\MelonStartScreen.deps.json + mkdir -p Output/Release/x64/MelonLoader/Documentation + cp CHANGELOG.md Output/Release/x64/MelonLoader/Documentation/ + cp LICENSE.md Output/Release/x64/MelonLoader/Documentation/ + cp NOTICE.txt Output/Release/x64/MelonLoader/Documentation/ + cp README.md Output/Release/x64/MelonLoader/Documentation/ - uses: actions/upload-artifact@v4 - name: Upload Zip | Windows - x64 + name: Upload Zip | Windows - Release - x64 with: name: MelonLoader.Windows.x64.CI.Release path: ./Output/Release/x64/* - finalize_x86_release_zip_windows: - runs-on: windows-latest - needs: [build_core_release, build_rust_windows] - steps: - - uses: actions/checkout@v4 - - name: Download core artifact + + - name: Download Debug Proxy x86 Artifact uses: actions/download-artifact@v4 with: - name: MLCoreRelease - path: Output/Release/x86/MelonLoader/ - - name: Download proxy x86 + name: MLProxyX86-Windows-Debug + path: Output/Debug/x86/ + - name: Download Debug Bootstrap x86 Artifact + uses: actions/download-artifact@v4 + with: + name: MLBootstrapX86-Windows-Debug + path: Output/Debug/x86/MelonLoader/Dependencies/ + - name: Package Debug x86 Artifact + run: | + echo Copying Managed Libs... + mkdir -p Output/Debug/x86/MelonLoader/Dependencies/Mono + cp -r Output/Debug/Managed/* Output/Debug/x86/MelonLoader/ + cp -r BaseLibs/Mono Output/Debug/x86/MelonLoader/Dependencies/ + cp -r BaseLibs/net35 Output/Debug/x86/MelonLoader/ + cp -r BaseLibs/net6 Output/Debug/x86/MelonLoader/ + mkdir -p Output/Debug/x86/MelonLoader/Dependencies/SupportModules/NetStandardPatches + cp -r BaseLibs/NetStandardPatches Output/Debug/x86/MelonLoader/Dependencies/SupportModules/NetStandardPatches + echo + echo Copying Dobby x86... + cp BaseLibs/dobby_x86.dll Output/Debug/x86/MelonLoader/Dependencies/dobby.dll + echo + echo Copying documentation files... + mkdir -p Output/Debug/x86/MelonLoader/Documentation + cp CHANGELOG.md Output/Debug/x86/MelonLoader/Documentation/ + cp LICENSE.md Output/Debug/x86/MelonLoader/Documentation/ + cp NOTICE.txt Output/Debug/x86/MelonLoader/Documentation/ + cp README.md Output/Debug/x86/MelonLoader/Documentation/ + - uses: actions/upload-artifact@v4 + name: Upload Zip | Windows - Debug - x86 + with: + name: MelonLoader.Windows.x86.CI.Debug + path: ./Output/Debug/x86/* + + - name: Download Release Proxy x86 Artifact uses: actions/download-artifact@v4 with: name: MLProxyX86-Windows-Release path: Output/Release/x86/ - - name: Download bootstrap x86 + - name: Download Release Bootstrap x86 Artifact uses: actions/download-artifact@v4 with: name: MLBootstrapX86-Windows-Release path: Output/Release/x86/MelonLoader/Dependencies/ - - name: Package x86 zip - shell: cmd + - name: Package Release x86 Artifact run: | echo Copying Managed Libs... - mkdir Output\Release\x86\MelonLoader\Dependencies\Mono - xcopy BaseLibs\Mono Output\Release\x86\MelonLoader\Dependencies\Mono\ /E /H /Y - xcopy BaseLibs\net35 Output\Release\x86\MelonLoader\net35\ /E /H /Y - xcopy BaseLibs\net6 Output\Release\x86\MelonLoader\net6\ /E /H /Y - echo. + mkdir -p Output/Release/x86/MelonLoader/Dependencies/Mono + cp -r Output/Release/Managed/* Output/Release/x86/MelonLoader/ + cp -r BaseLibs/Mono Output/Release/x86/MelonLoader/Dependencies/ + cp -r BaseLibs/net35 Output/Release/x86/MelonLoader/ + cp -r BaseLibs/net6 Output/Release/x86/MelonLoader/ + mkdir -p Output/Release/x86/MelonLoader/Dependencies/SupportModules/NetStandardPatches + cp -r BaseLibs/NetStandardPatches Output/Release/x86/MelonLoader/Dependencies/SupportModules/NetStandardPatches + echo echo Copying Dobby x86... - xcopy BaseLibs\dobby_x86.dll Output\Release\x86\MelonLoader\Dependencies\dobby.dll* - echo. + cp BaseLibs/dobby_x86.dll Output/Release/x86/MelonLoader/Dependencies/dobby.dll + echo echo Copying documentation files... - copy NOTICE.txt Output\Release\x86 - mkdir Output\Release\x86\MelonLoader\Documentation - copy CHANGELOG.md Output\Release\x86\MelonLoader\Documentation\ - copy LICENSE.md Output\Release\x86\MelonLoader\Documentation\ - copy NOTICE.txt Output\Release\x86\MelonLoader\Documentation\ - copy README.md Output\Release\x86\MelonLoader\Documentation\ - del Output\Release\x86\MelonLoader\net6\MelonStartScreen.dll - del Output\Release\x86\MelonLoader\net6\MelonStartScreen.deps.json + mkdir -p Output/Release/x86/MelonLoader/Documentation + cp CHANGELOG.md Output/Release/x86/MelonLoader/Documentation/ + cp LICENSE.md Output/Release/x86/MelonLoader/Documentation/ + cp NOTICE.txt Output/Release/x86/MelonLoader/Documentation/ + cp README.md Output/Release/x86/MelonLoader/Documentation/ - uses: actions/upload-artifact@v4 - name: Upload Zip | Windows - x86 + name: Upload Zip | Windows - Release - x86 with: name: MelonLoader.Windows.x86.CI.Release path: ./Output/Release/x86/* - finalize_x64_debug_zip_linux: - runs-on: windows-latest - needs: [build_core_debug, build_rust_linux] + + finalize_linux: + name: Finalize Linux Artifacts + runs-on: ubuntu-22.04 + needs: [build_core, build_rust_linux] steps: - uses: actions/checkout@v4 - - name: Download core artifact + - name: Download Debug Managed Artifact uses: actions/download-artifact@v4 with: name: MLCoreDebug path: Output/Debug/x64/MelonLoader/ - - name: Download proxy x64 + - name: Download Debug Proxy Artifact uses: actions/download-artifact@v4 with: name: MLProxyX64-Linux-Debug path: Output/Debug/x64/ - - name: Download bootstrap x64 + - name: Download Debug Bootstrap Artifact uses: actions/download-artifact@v4 with: name: MLBootstrapX64-Linux-Debug path: Output/Debug/x64/MelonLoader/Dependencies/ - - name: Package x64 zip - shell: cmd + - name: Package Debug Zip run: | echo Copying Managed Libs... - mkdir Output\Debug\x64\MelonLoader\Dependencies\Mono - xcopy BaseLibs\Mono Output\Debug\x64\MelonLoader\Dependencies\Mono\ /E /H /Y - xcopy BaseLibs\net35 Output\Debug\x64\MelonLoader\net35\ /E /H /Y - xcopy BaseLibs\net6 Output\Debug\x64\MelonLoader\net6\ /E /H /Y - echo. + mkdir -p Output/Debug/x64/MelonLoader/Dependencies/Mono + cp -r BaseLibs/Mono Output/Debug/x64/MelonLoader/Dependencies/ + cp -r BaseLibs/net35 Output/Debug/x64/MelonLoader/ + cp -r BaseLibs/net6 Output/Debug/x64/MelonLoader/ + mkdir -p Output/Debug/x64/MelonLoader/Dependencies/SupportModules/NetStandardPatches + cp -r BaseLibs/NetStandardPatches Output/Debug/x64/MelonLoader/Dependencies/SupportModules/NetStandardPatches + echo echo Copying documentation files... - copy NOTICE.txt Output\Debug\x64 - mkdir Output\Debug\x64\MelonLoader\Documentation - copy CHANGELOG.md Output\Debug\x64\MelonLoader\Documentation\ - copy LICENSE.md Output\Debug\x64\MelonLoader\Documentation\ - copy NOTICE.txt Output\Debug\x64\MelonLoader\Documentation\ - copy README.md Output\Debug\x64\MelonLoader\Documentation\ - del Output\Debug\x64\MelonLoader\net6\MelonStartScreen.dll - del Output\Debug\x64\MelonLoader\net6\MelonStartScreen.deps.json + mkdir -p Output/Debug/x64/MelonLoader/Documentation + cp CHANGELOG.md Output/Debug/x64/MelonLoader/Documentation/ + cp LICENSE.md Output/Debug/x64/MelonLoader/Documentation/ + cp NOTICE.txt Output/Debug/x64/MelonLoader/Documentation/ + cp README.md Output/Debug/x64/MelonLoader/Documentation/ - uses: actions/upload-artifact@v4 - name: Upload Zip | Linux - x64 + name: Upload Zip | Linux - Debug - x64 with: name: MelonLoader.Linux.x64.CI.Debug path: ./Output/Debug/x64/* - finalize_x64_release_zip_linux: - runs-on: windows-latest - needs: [build_core_release, build_rust_linux] - steps: - - uses: actions/checkout@v4 - - name: Download core artifact + - name: Download Release Managed Artifact uses: actions/download-artifact@v4 with: name: MLCoreRelease path: Output/Release/x64/MelonLoader/ - - name: Download proxy x64 + - name: Download Release Proxy Artifact uses: actions/download-artifact@v4 with: name: MLProxyX64-Linux-Release path: Output/Release/x64/ - - name: Download bootstrap x64 + - name: Download Release Bootstrap Artifact uses: actions/download-artifact@v4 with: name: MLBootstrapX64-Linux-Release path: Output/Release/x64/MelonLoader/Dependencies/ - - name: Package x64 zip - shell: cmd + - name: Package Release Zip run: | echo Copying Managed Libs... - mkdir Output\Release\x64\MelonLoader\Dependencies\Mono - xcopy BaseLibs\Mono Output\Release\x64\MelonLoader\Dependencies\Mono\ /E /H /Y - xcopy BaseLibs\net35 Output\Release\x64\MelonLoader\net35\ /E /H /Y - xcopy BaseLibs\net6 Output\Release\x64\MelonLoader\net6\ /E /H /Y - echo. + mkdir -p Output/Release/x64/MelonLoader/Dependencies/Mono + cp -r BaseLibs/Mono Output/Release/x64/MelonLoader/Dependencies/ + cp -r BaseLibs/net35 Output/Release/x64/MelonLoader/ + cp -r BaseLibs/net6 Output/Release/x64/MelonLoader/ + mkdir -p Output/Release/x64/MelonLoader/Dependencies/SupportModules/NetStandardPatches + cp -r BaseLibs/NetStandardPatches Output/Release/x64/MelonLoader/Dependencies/SupportModules/NetStandardPatches + echo echo Copying documentation files... - copy NOTICE.txt Output\Release\x64 - mkdir Output\Release\x64\MelonLoader\Documentation - copy CHANGELOG.md Output\Release\x64\MelonLoader\Documentation\ - copy LICENSE.md Output\Release\x64\MelonLoader\Documentation\ - copy NOTICE.txt Output\Release\x64\MelonLoader\Documentation\ - copy README.md Output\Release\x64\MelonLoader\Documentation\ - del Output\Release\x64\MelonLoader\net6\MelonStartScreen.dll - del Output\Release\x64\MelonLoader\net6\MelonStartScreen.deps.json + mkdir -p Output/Release/x64/MelonLoader/Documentation + cp CHANGELOG.md Output/Release/x64/MelonLoader/Documentation/ + cp LICENSE.md Output/Release/x64/MelonLoader/Documentation/ + cp NOTICE.txt Output/Release/x64/MelonLoader/Documentation/ + cp README.md Output/Release/x64/MelonLoader/Documentation/ - uses: actions/upload-artifact@v4 - name: Upload Zip | Linux - x64 + name: Upload Zip | Linux - Release - x64 with: name: MelonLoader.Linux.x64.CI.Release path: ./Output/Release/x64/* + cleanup_artifacts: - runs-on: windows-latest - needs: [finalize_x86_debug_zip_windows, finalize_x64_debug_zip_windows, finalize_x86_release_zip_windows, finalize_x64_release_zip_windows, finalize_x64_debug_zip_linux, finalize_x64_release_zip_linux] + name: Cleanup Artifacts + runs-on: ubuntu-22.04 + needs: [finalize_windows, finalize_linux] steps: - uses: GeekyEggo/delete-artifact@v5.0.0 with: @@ -440,4 +425,5 @@ jobs: MLProxyX64-Windows-Release MLBootstrapX64-Windows-Release MLProxyX64-Linux-Release - MLBootstrapX64-Linux-Release \ No newline at end of file + MLBootstrapX64-Linux-Release + \ No newline at end of file diff --git a/.github/workflows/nuget.yml b/.github/workflows/nuget.yml deleted file mode 100644 index 78042b0af..000000000 --- a/.github/workflows/nuget.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: Build NuGet Package - -on: - push: - branches: [ master, alpha-development, v0.6.0-rewrite ] - pull_request: - branches: [ master, alpha-development, v0.6.0-rewrite ] - workflow_dispatch: - -jobs: - build_nuget_package: - runs-on: windows-latest - steps: - - uses: actions/checkout@v4 - - name: Setup .NET - uses: actions/setup-dotnet@v4.0.1 - with: - dotnet-version: 7.0.x - - name: .NET Pack - run: dotnet pack -c Release - working-directory: ./MelonLoader/ - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: MelonLoaderNuGetPackage - path: MelonLoader/Output/Release/MelonLoader/LavaGang.MelonLoader.0.6.6.nupkg \ No newline at end of file diff --git a/Dependencies/SupportModules/Preload/Resources/System.Core.dll b/BaseLibs/NetStandardPatches/System.Core.dll similarity index 100% rename from Dependencies/SupportModules/Preload/Resources/System.Core.dll rename to BaseLibs/NetStandardPatches/System.Core.dll diff --git a/Dependencies/SupportModules/Preload/Resources/System.Drawing.dll b/BaseLibs/NetStandardPatches/System.Drawing.dll similarity index 100% rename from Dependencies/SupportModules/Preload/Resources/System.Drawing.dll rename to BaseLibs/NetStandardPatches/System.Drawing.dll diff --git a/Dependencies/SupportModules/Preload/Resources/System.dll b/BaseLibs/NetStandardPatches/System.dll similarity index 100% rename from Dependencies/SupportModules/Preload/Resources/System.dll rename to BaseLibs/NetStandardPatches/System.dll diff --git a/CHANGELOG.md b/CHANGELOG.md index da8e3655b..39a24557a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,25 +41,36 @@ ### v0.6.6 1. Updated Il2CppInterop to 1.4.6-ci.579 -2. Implemented a RegisterTypeInIl2CppWithInterfaces attribute -3. Implemented Recursive Melon Folders with extended UserLib Resolving -4. Reimplemented NetFramework Variant of Cpp2IL as fallback -5. Standardized Assembly Searching and Resolving to work on both Mono and Il2Cpp Games -6. Temporarily removed Start Screen for being broken in most cases -7. Modified Command-Line Argument Logging to show Internal Arguments Only -8. Added UserLibs folders to Native Library Search Directories -9. Moved `dobby.dll` to `MelonLoader\Dependencies` -10. Moved Assembly Resolver Related Classes to `MelonLoader.Resolver` Namespace -11. Moved `MonoLibrary` class to `MelonLoader.Utils` Namespace -12. Removed Useless TODO Warning from Il2CppAssemblyGenerator -13. Removed EOS Compatibility Layer for being Unneeded -14. Fixed Regression with LemonMD5, LemonSHA256, and LemonSHA512 -15. Fixed an issue with older Cpp2IL versions causing a download failure -16. Fixed an issue with Il2CppInterop not properly logging Trampoline Exceptions -17. Fixed an issue with Il2Cpp Class Injection Attributes causing exceptions to be thrown on Mono games -18. Fixed an issue with the Bootstrap not reading `--melonloader.basedir` correctly -19. Fixed an issue with Loading `dobby.dll` in some rare cases -20. Fixed an issue with Compatibility Layers getting Garbage Collected while still in use +2. Reverted AssetTools.NET to 3.0.0-preview3 +3. Implemented a RegisterTypeInIl2CppWithInterfaces attribute +4. Implemented Recursive Melon Folders with extended UserLib Resolving +5. Implemented Melon Preprocessor to prevent Loading Duplicates +6. Reimplemented NetFramework Variant of Cpp2IL as fallback +7. Standardized Assembly Searching and Resolving to work on both Mono and Il2Cpp Games +8. Temporarily removed Start Screen for being broken in most cases +9. Modified Command-Line Argument Logging to show Internal Arguments Only +10. Reworked Il2CppICallInjector to use Il2CppInterop's Native to Manage trampoline generation +11. Reworked Launch Option Parsing to ignore First Element +12. Added UserLibs folders to Native Library Search Directories +13. Moved `dobby.dll` to `MelonLoader\Dependencies` +14. Moved Assembly Resolver Related Classes to `MelonLoader.Resolver` Namespace +15. Moved `MonoLibrary` class to `MelonLoader.Utils` Namespace +16. Moved dobby scan to check Game Directory after Base Directory +17. Removed Useless TODO Warning from Il2CppAssemblyGenerator +18. Removed EOS Compatibility Layer for being Unneeded +19. Fixed Regression with LemonMD5, LemonSHA256, and LemonSHA512 +20. Fixed an issue with older Cpp2IL versions causing a download failure +21. Fixed an issue with Il2CppInterop not properly logging Trampoline Exceptions +22. Fixed an issue with Il2Cpp Class Injection Attributes causing exceptions to be thrown on Mono games +23. Fixed an issue with the Bootstrap not reading `--melonloader.basedir` correctly +24. Fixed an issue with Loading `dobby.dll` in some rare cases +25. Fixed an issue with Compatibility Layers getting Garbage Collected while still in use +26. Fixed an issue with Linux Proxy failing to find dobby +27. Fixed an issue with trying to load Managed Assemblies from Native Libraries inside UserLibs +28. Fixed an issue with Compatibility Layer loading not validating Names Checked +29. Fixed an issue with Type Load spamming errors when failing to resolve a Dependency +30. Fixed an issue with Launch Option Parsing ignoring Argument Values +31. Fixed a race condition crash with Multi-Launching a Game and the Logger trying to delete old files --- diff --git a/Dependencies/CompatibilityLayers/Demeo/Demeo.csproj b/Dependencies/CompatibilityLayers/Demeo/Demeo.csproj index 8ba1116ea..a3c7b7a95 100644 --- a/Dependencies/CompatibilityLayers/Demeo/Demeo.csproj +++ b/Dependencies/CompatibilityLayers/Demeo/Demeo.csproj @@ -2,9 +2,7 @@ MelonLoader.CompatibilityLayers net472 - Latest true - false false $(SolutionDir)Output\$(Configuration)\MelonLoader\Dependencies\CompatibilityLayers\ true @@ -12,8 +10,6 @@ - - Runtime - + \ No newline at end of file diff --git a/Dependencies/CompatibilityLayers/Demeo/Module.cs b/Dependencies/CompatibilityLayers/Demeo/Module.cs index 9ec9d47e5..8bd856fde 100644 --- a/Dependencies/CompatibilityLayers/Demeo/Module.cs +++ b/Dependencies/CompatibilityLayers/Demeo/Module.cs @@ -4,6 +4,8 @@ using System.Reflection; using MelonLoader.Modules; +[assembly: MelonLoader.PatchShield] + namespace MelonLoader.CompatibilityLayers { internal class Demeo_Module : MelonModule diff --git a/Dependencies/CompatibilityLayers/Demeo/Properties/AssemblyInfo.cs b/Dependencies/CompatibilityLayers/Demeo/Properties/AssemblyInfo.cs deleted file mode 100644 index 81808f72e..000000000 --- a/Dependencies/CompatibilityLayers/Demeo/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle(MelonLoader.BuildInfo.Description)] -[assembly: AssemblyDescription(MelonLoader.BuildInfo.Description)] -[assembly: AssemblyCompany(MelonLoader.BuildInfo.Company)] -[assembly: AssemblyProduct(MelonLoader.BuildInfo.Name)] -[assembly: AssemblyCopyright("Created by " + MelonLoader.BuildInfo.Author)] -[assembly: AssemblyTrademark(MelonLoader.BuildInfo.Company)] -[assembly: Guid("FEAA0159-5871-4419-9827-3CF5CAD69A53")] -[assembly: AssemblyVersion(MelonLoader.BuildInfo.Version)] -[assembly: AssemblyFileVersion(MelonLoader.BuildInfo.Version)] -[assembly: MelonLoader.PatchShield] \ No newline at end of file diff --git a/Dependencies/CompatibilityLayers/IPA/IPA.csproj b/Dependencies/CompatibilityLayers/IPA/IPA.csproj index cc4d68bae..73734cb79 100644 --- a/Dependencies/CompatibilityLayers/IPA/IPA.csproj +++ b/Dependencies/CompatibilityLayers/IPA/IPA.csproj @@ -2,9 +2,7 @@ MelonLoader.CompatibilityLayers net35 - Latest true - false false $(SolutionDir)Output\$(Configuration)\MelonLoader\Dependencies\CompatibilityLayers\ true diff --git a/Dependencies/CompatibilityLayers/IPA/Module.cs b/Dependencies/CompatibilityLayers/IPA/Module.cs index 018263c95..87cb99a13 100644 --- a/Dependencies/CompatibilityLayers/IPA/Module.cs +++ b/Dependencies/CompatibilityLayers/IPA/Module.cs @@ -7,6 +7,8 @@ using MelonLoader.Modules; using MelonLoader.Resolver; +[assembly: MelonLoader.PatchShield] + namespace MelonLoader.CompatibilityLayers { internal class IPA_Module : MelonModule diff --git a/Dependencies/CompatibilityLayers/IPA/Properties/AssemblyInfo.cs b/Dependencies/CompatibilityLayers/IPA/Properties/AssemblyInfo.cs deleted file mode 100644 index 0f2b1903f..000000000 --- a/Dependencies/CompatibilityLayers/IPA/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle(MelonLoader.BuildInfo.Description)] -[assembly: AssemblyDescription(MelonLoader.BuildInfo.Description)] -[assembly: AssemblyCompany(MelonLoader.BuildInfo.Company)] -[assembly: AssemblyProduct(MelonLoader.BuildInfo.Name)] -[assembly: AssemblyCopyright("Created by " + MelonLoader.BuildInfo.Author)] -[assembly: AssemblyTrademark(MelonLoader.BuildInfo.Company)] -[assembly: Guid("5100810A-9842-4073-9658-E5841FDF9D73")] -[assembly: AssemblyVersion(MelonLoader.BuildInfo.Version)] -[assembly: AssemblyFileVersion(MelonLoader.BuildInfo.Version)] -[assembly: MelonLoader.PatchShield] \ No newline at end of file diff --git a/Dependencies/CompatibilityLayers/Muse_Dash_Mono/Module.cs b/Dependencies/CompatibilityLayers/Muse_Dash_Mono/Module.cs index 0551542a4..80c8d1ce0 100644 --- a/Dependencies/CompatibilityLayers/Muse_Dash_Mono/Module.cs +++ b/Dependencies/CompatibilityLayers/Muse_Dash_Mono/Module.cs @@ -6,6 +6,8 @@ using ModHelper; using MelonLoader.Resolver; +[assembly: MelonLoader.PatchShield] + namespace MelonLoader.CompatibilityLayers { internal class Muse_Dash_Mono_Module : MelonModule diff --git a/Dependencies/CompatibilityLayers/Muse_Dash_Mono/Muse_Dash_Mono.csproj b/Dependencies/CompatibilityLayers/Muse_Dash_Mono/Muse_Dash_Mono.csproj index cc4d68bae..73734cb79 100644 --- a/Dependencies/CompatibilityLayers/Muse_Dash_Mono/Muse_Dash_Mono.csproj +++ b/Dependencies/CompatibilityLayers/Muse_Dash_Mono/Muse_Dash_Mono.csproj @@ -2,9 +2,7 @@ MelonLoader.CompatibilityLayers net35 - Latest true - false false $(SolutionDir)Output\$(Configuration)\MelonLoader\Dependencies\CompatibilityLayers\ true diff --git a/Dependencies/CompatibilityLayers/Muse_Dash_Mono/Properties/AssemblyInfo.cs b/Dependencies/CompatibilityLayers/Muse_Dash_Mono/Properties/AssemblyInfo.cs deleted file mode 100644 index 7982318b0..000000000 --- a/Dependencies/CompatibilityLayers/Muse_Dash_Mono/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle(MelonLoader.BuildInfo.Description)] -[assembly: AssemblyDescription(MelonLoader.BuildInfo.Description)] -[assembly: AssemblyCompany(MelonLoader.BuildInfo.Company)] -[assembly: AssemblyProduct(MelonLoader.BuildInfo.Name)] -[assembly: AssemblyCopyright("Created by " + MelonLoader.BuildInfo.Author)] -[assembly: AssemblyTrademark(MelonLoader.BuildInfo.Company)] -[assembly: Guid("C268E68B-3DF1-4EE3-A49F-750A8F55B799")] -[assembly: AssemblyVersion(MelonLoader.BuildInfo.Version)] -[assembly: AssemblyFileVersion(MelonLoader.BuildInfo.Version)] -[assembly: MelonLoader.PatchShield] \ No newline at end of file diff --git a/Dependencies/CompatibilityLayers/Stress_Level_Zero_Il2Cpp/Module.cs b/Dependencies/CompatibilityLayers/Stress_Level_Zero_Il2Cpp/Module.cs index 791f9c824..a71f73b76 100644 --- a/Dependencies/CompatibilityLayers/Stress_Level_Zero_Il2Cpp/Module.cs +++ b/Dependencies/CompatibilityLayers/Stress_Level_Zero_Il2Cpp/Module.cs @@ -1,6 +1,8 @@ using MelonLoader.Modules; using System.Collections.Generic; +[assembly: MelonLoader.PatchShield] + namespace MelonLoader.CompatibilityLayers { internal class SLZ_Module : MelonModule diff --git a/Dependencies/CompatibilityLayers/Stress_Level_Zero_Il2Cpp/Properties/AssemblyInfo.cs b/Dependencies/CompatibilityLayers/Stress_Level_Zero_Il2Cpp/Properties/AssemblyInfo.cs deleted file mode 100644 index 81808f72e..000000000 --- a/Dependencies/CompatibilityLayers/Stress_Level_Zero_Il2Cpp/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle(MelonLoader.BuildInfo.Description)] -[assembly: AssemblyDescription(MelonLoader.BuildInfo.Description)] -[assembly: AssemblyCompany(MelonLoader.BuildInfo.Company)] -[assembly: AssemblyProduct(MelonLoader.BuildInfo.Name)] -[assembly: AssemblyCopyright("Created by " + MelonLoader.BuildInfo.Author)] -[assembly: AssemblyTrademark(MelonLoader.BuildInfo.Company)] -[assembly: Guid("FEAA0159-5871-4419-9827-3CF5CAD69A53")] -[assembly: AssemblyVersion(MelonLoader.BuildInfo.Version)] -[assembly: AssemblyFileVersion(MelonLoader.BuildInfo.Version)] -[assembly: MelonLoader.PatchShield] \ No newline at end of file diff --git a/Dependencies/CompatibilityLayers/Stress_Level_Zero_Il2Cpp/Stress_Level_Zero_Il2Cpp.csproj b/Dependencies/CompatibilityLayers/Stress_Level_Zero_Il2Cpp/Stress_Level_Zero_Il2Cpp.csproj index 938439701..c2eab15ea 100644 --- a/Dependencies/CompatibilityLayers/Stress_Level_Zero_Il2Cpp/Stress_Level_Zero_Il2Cpp.csproj +++ b/Dependencies/CompatibilityLayers/Stress_Level_Zero_Il2Cpp/Stress_Level_Zero_Il2Cpp.csproj @@ -2,9 +2,7 @@ MelonLoader.CompatibilityLayers net472 - Latest true - false false $(SolutionDir)Output\$(Configuration)\MelonLoader\Dependencies\CompatibilityLayers\ true @@ -17,9 +15,9 @@ - - false - false - + + false + false + \ No newline at end of file diff --git a/Dependencies/Il2CppAssemblyGenerator/Il2CppAssemblyGenerator.csproj b/Dependencies/Il2CppAssemblyGenerator/Il2CppAssemblyGenerator.csproj index 09f20a55d..b7c195233 100644 --- a/Dependencies/Il2CppAssemblyGenerator/Il2CppAssemblyGenerator.csproj +++ b/Dependencies/Il2CppAssemblyGenerator/Il2CppAssemblyGenerator.csproj @@ -2,9 +2,7 @@ MelonLoader.Il2CppAssemblyGenerator net6 - Latest true - false true false $(SolutionDir)Output\$(Configuration)\MelonLoader\Dependencies\Il2CppAssemblyGenerator\ @@ -18,7 +16,7 @@ - + \ No newline at end of file diff --git a/Dependencies/Il2CppAssemblyGenerator/Properties/AssemblyInfo.cs b/Dependencies/Il2CppAssemblyGenerator/Properties/AssemblyInfo.cs deleted file mode 100644 index e98f6337e..000000000 --- a/Dependencies/Il2CppAssemblyGenerator/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle(MelonLoader.BuildInfo.Description)] -[assembly: AssemblyDescription(MelonLoader.BuildInfo.Description)] -[assembly: AssemblyCompany(MelonLoader.BuildInfo.Company)] -[assembly: AssemblyProduct(MelonLoader.BuildInfo.Name)] -[assembly: AssemblyCopyright("Created by " + MelonLoader.BuildInfo.Author)] -[assembly: AssemblyTrademark(MelonLoader.BuildInfo.Company)] -[assembly: Guid("0E4C9125-D149-441D-B7B6-16D9D8CF1DA5")] -[assembly: AssemblyVersion(MelonLoader.BuildInfo.Version)] -[assembly: AssemblyFileVersion(MelonLoader.BuildInfo.Version)] \ No newline at end of file diff --git a/Dependencies/MelonStartScreen/MelonStartScreen.csproj b/Dependencies/MelonStartScreen/MelonStartScreen.csproj index e6ca3c748..587ad73ee 100644 --- a/Dependencies/MelonStartScreen/MelonStartScreen.csproj +++ b/Dependencies/MelonStartScreen/MelonStartScreen.csproj @@ -1,26 +1,25 @@ - - MelonLoader.MelonStartScreen - net35;net6 - Latest - true - false - true - $(SolutionDir)Output\$(Configuration)\MelonLoader\ - true - embedded - - - - - - - - - - - - Runtime - - + + MelonLoader.MelonStartScreen + net35;net6 + true + true + $(SolutionDir)Output\$(Configuration)\MelonLoader\ + true + embedded + + + + + + + + + + + + Runtime + + \ No newline at end of file diff --git a/Dependencies/MelonStartScreen/Properties/AssemblyInfo.cs b/Dependencies/MelonStartScreen/Properties/AssemblyInfo.cs deleted file mode 100644 index efe736458..000000000 --- a/Dependencies/MelonStartScreen/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle(MelonLoader.BuildInfo.Description)] -[assembly: AssemblyDescription(MelonLoader.BuildInfo.Description)] -[assembly: AssemblyCompany(MelonLoader.BuildInfo.Company)] -[assembly: AssemblyProduct(MelonLoader.BuildInfo.Name)] -[assembly: AssemblyCopyright("Created by " + MelonLoader.BuildInfo.Author)] -[assembly: AssemblyTrademark(MelonLoader.BuildInfo.Company)] -[assembly: Guid("762d7545-6f6b-441a-b040-49cc31a1713b")] -[assembly: AssemblyVersion(MelonLoader.BuildInfo.Version)] -[assembly: AssemblyFileVersion(MelonLoader.BuildInfo.Version)] \ No newline at end of file diff --git a/Dependencies/SupportModules/Il2Cpp/Il2Cpp.csproj b/Dependencies/SupportModules/Il2Cpp/Il2Cpp.csproj index 53f3003ca..b661db0ff 100644 --- a/Dependencies/SupportModules/Il2Cpp/Il2Cpp.csproj +++ b/Dependencies/SupportModules/Il2Cpp/Il2Cpp.csproj @@ -2,9 +2,7 @@ MelonLoader.Support net6 - Latest true - false false $(SolutionDir)Output\$(Configuration)\MelonLoader\Dependencies\SupportModules\ true @@ -12,15 +10,8 @@ SM_Il2Cpp true - - https://nuget.bepinex.dev/v3/index.json - + https://nuget.bepinex.dev/v3/index.json - - - - - Libs\Il2Cppmscorlib.dll @@ -49,7 +40,7 @@ - + diff --git a/Dependencies/SupportModules/Il2Cpp/Main.cs b/Dependencies/SupportModules/Il2Cpp/Main.cs index 49f65d0c1..21c3d41cc 100644 --- a/Dependencies/SupportModules/Il2Cpp/Main.cs +++ b/Dependencies/SupportModules/Il2Cpp/Main.cs @@ -12,6 +12,8 @@ using MelonLoader.Utils; using System.IO; +[assembly: MelonLoader.PatchShield] + #pragma warning disable CS0618 // Type or member is obsolete namespace MelonLoader.Support diff --git a/Dependencies/SupportModules/Il2Cpp/Properties/AssemblyInfo.cs b/Dependencies/SupportModules/Il2Cpp/Properties/AssemblyInfo.cs deleted file mode 100644 index d64189128..000000000 --- a/Dependencies/SupportModules/Il2Cpp/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle(MelonLoader.BuildInfo.Description)] -[assembly: AssemblyDescription(MelonLoader.BuildInfo.Description)] -[assembly: AssemblyCompany(MelonLoader.BuildInfo.Company)] -[assembly: AssemblyProduct(MelonLoader.BuildInfo.Name)] -[assembly: AssemblyCopyright("Created by " + MelonLoader.BuildInfo.Author)] -[assembly: AssemblyTrademark(MelonLoader.BuildInfo.Company)] -[assembly: Guid("CD98B694-D833-41B0-AF57-A6B9D024B045")] -[assembly: AssemblyVersion(MelonLoader.BuildInfo.Version)] -[assembly: AssemblyFileVersion(MelonLoader.BuildInfo.Version)] -[assembly: MelonLoader.PatchShield] \ No newline at end of file diff --git a/Dependencies/SupportModules/Mono/Main.cs b/Dependencies/SupportModules/Mono/Main.cs index ea95dea2c..a12bce579 100644 --- a/Dependencies/SupportModules/Mono/Main.cs +++ b/Dependencies/SupportModules/Mono/Main.cs @@ -3,6 +3,8 @@ using MelonLoader.Support.Preferences; using UnityEngine; +[assembly: MelonLoader.PatchShield] + namespace MelonLoader.Support { internal static class Main diff --git a/Dependencies/SupportModules/Mono/Mono.csproj b/Dependencies/SupportModules/Mono/Mono.csproj index 99ac434c8..53d0fbf85 100644 --- a/Dependencies/SupportModules/Mono/Mono.csproj +++ b/Dependencies/SupportModules/Mono/Mono.csproj @@ -2,24 +2,14 @@ MelonLoader.Support net35 - Latest true - false false - $(SolutionDir)\Output\$(Configuration)\MelonLoader\Dependencies\SupportModules\ + $(SolutionDir)Output\$(Configuration)\MelonLoader\Dependencies\SupportModules\ true embedded - - - - - - - Libs\UnityEngine.dll - False - + @@ -29,8 +19,6 @@ - - Runtime - + \ No newline at end of file diff --git a/Dependencies/SupportModules/Mono/Properties/AssemblyInfo.cs b/Dependencies/SupportModules/Mono/Properties/AssemblyInfo.cs deleted file mode 100644 index 1d42e64c4..000000000 --- a/Dependencies/SupportModules/Mono/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle(MelonLoader.BuildInfo.Description)] -[assembly: AssemblyDescription(MelonLoader.BuildInfo.Description)] -[assembly: AssemblyCompany(MelonLoader.BuildInfo.Company)] -[assembly: AssemblyProduct(MelonLoader.BuildInfo.Name)] -[assembly: AssemblyCopyright("Created by " + MelonLoader.BuildInfo.Author)] -[assembly: AssemblyTrademark(MelonLoader.BuildInfo.Company)] -[assembly: Guid("EE48CA52-CCD3-48A5-B507-91773672E216")] -[assembly: AssemblyVersion(MelonLoader.BuildInfo.Version)] -[assembly: AssemblyFileVersion(MelonLoader.BuildInfo.Version)] -[assembly: MelonLoader.PatchShield] \ No newline at end of file diff --git a/Dependencies/SupportModules/Preload/Preload.cs b/Dependencies/SupportModules/Preload/Preload.cs index 1e0c30c67..a74b603ef 100644 --- a/Dependencies/SupportModules/Preload/Preload.cs +++ b/Dependencies/SupportModules/Preload/Preload.cs @@ -1,5 +1,4 @@ using System.IO; -using System.Reflection; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; using System; @@ -13,26 +12,30 @@ private static void Initialize() if (Environment.Version >= new Version("3.0.0.0")) return; - string managedFolder = string.Copy(GetManagedDirectory()); + var ownDir = typeof(Preload).Assembly.Location; + if (string.IsNullOrEmpty(ownDir)) + return; - WriteResource(Properties.Resources.System, Path.Combine(managedFolder, "System.dll")); - WriteResource(Properties.Resources.System_Core, Path.Combine(managedFolder, "System.Core.dll")); - WriteResource(Properties.Resources.System_Drawing, Path.Combine(managedFolder, "System.Drawing.dll")); - } + ownDir = Path.GetDirectoryName(ownDir); - [MethodImpl(MethodImplOptions.InternalCall)] - [return: MarshalAs(UnmanagedType.LPStr)] - private static extern string GetManagedDirectory(); + var managedFolder = GetManagedDirectory(); - private static void WriteResource(byte[] data, string destination) - { - try + var patchesDir = Path.Combine(ownDir, "NetStandardPatches"); + if (!Directory.Exists(patchesDir)) + return; + + foreach (var patch in Directory.GetFiles(patchesDir)) { - if (File.Exists(destination)) - File.Delete(destination); - File.WriteAllBytes(destination, data); + try + { + File.Copy(patch, Path.Combine(managedFolder, Path.GetFileName(patch)), true); + } + catch { } } - catch { } } + + [MethodImpl(MethodImplOptions.InternalCall)] + [return: MarshalAs(UnmanagedType.LPStr)] + private static extern string GetManagedDirectory(); } } \ No newline at end of file diff --git a/Dependencies/SupportModules/Preload/Preload.csproj b/Dependencies/SupportModules/Preload/Preload.csproj index 0c79f1ccd..6dbe152a9 100644 --- a/Dependencies/SupportModules/Preload/Preload.csproj +++ b/Dependencies/SupportModules/Preload/Preload.csproj @@ -2,9 +2,7 @@ MelonLoader.Support net20 - Latest true - false false $(SolutionDir)Output\$(Configuration)\MelonLoader\Dependencies\SupportModules\ true @@ -17,22 +15,6 @@ - - - - - - - - True - True - Resources.resx - - - - - ResXFileCodeGenerator - Resources.Designer.cs - + \ No newline at end of file diff --git a/Dependencies/SupportModules/Preload/Properties/AssemblyInfo.cs b/Dependencies/SupportModules/Preload/Properties/AssemblyInfo.cs deleted file mode 100644 index a078c0f7d..000000000 --- a/Dependencies/SupportModules/Preload/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle(MelonLoader.BuildInfo.Description)] -[assembly: AssemblyDescription(MelonLoader.BuildInfo.Description)] -[assembly: AssemblyCompany(MelonLoader.BuildInfo.Company)] -[assembly: AssemblyProduct(MelonLoader.BuildInfo.Name)] -[assembly: AssemblyCopyright("Created by " + MelonLoader.BuildInfo.Author)] -[assembly: AssemblyTrademark(MelonLoader.BuildInfo.Company)] -[assembly: Guid("08BE056B-C854-4F88-92E8-F3B39187B6AF")] -[assembly: AssemblyVersion(MelonLoader.BuildInfo.Version)] -[assembly: AssemblyFileVersion(MelonLoader.BuildInfo.Version)] \ No newline at end of file diff --git a/Dependencies/SupportModules/Preload/Properties/Resources.Designer.cs b/Dependencies/SupportModules/Preload/Properties/Resources.Designer.cs deleted file mode 100644 index d7760797e..000000000 --- a/Dependencies/SupportModules/Preload/Properties/Resources.Designer.cs +++ /dev/null @@ -1,93 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace MelonLoader.Support.Properties { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MelonLoader.Support.Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized resource of type System.Byte[]. - /// - internal static byte[] System { - get { - object obj = ResourceManager.GetObject("System", resourceCulture); - return ((byte[])(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Byte[]. - /// - internal static byte[] System_Core { - get { - object obj = ResourceManager.GetObject("System.Core", resourceCulture); - return ((byte[])(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Byte[]. - /// - internal static byte[] System_Drawing { - get { - object obj = ResourceManager.GetObject("System.Drawing", resourceCulture); - return ((byte[])(obj)); - } - } - } -} diff --git a/Dependencies/SupportModules/Preload/Properties/Resources.resx b/Dependencies/SupportModules/Preload/Properties/Resources.resx deleted file mode 100644 index a2b6ad7b2..000000000 --- a/Dependencies/SupportModules/Preload/Properties/Resources.resx +++ /dev/null @@ -1,130 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - - ..\Resources\System.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - ..\Resources\System.Core.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - ..\Resources\System.Drawing.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 000000000..4b42315a4 --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,11 @@ + + + 0.6.6 + Lava Gang + discord.gg/2Wn3N2P + Copyright (c) 2022 Lava Gang + Latest + false + + + \ No newline at end of file diff --git a/MelonLoader.NativeHost/MelonLoader.NativeHost.csproj b/MelonLoader.NativeHost/MelonLoader.NativeHost.csproj index 438c05c0f..ca78036f7 100644 --- a/MelonLoader.NativeHost/MelonLoader.NativeHost.csproj +++ b/MelonLoader.NativeHost/MelonLoader.NativeHost.csproj @@ -1,17 +1,17 @@  - - net6 - enable - enable - $(SolutionDir)Output\$(Configuration)\MelonLoader\ - true - True - embedded - + + net6 + enable + enable + $(SolutionDir)Output\$(Configuration)\MelonLoader\ + true + True + embedded + - - - + + + - + \ No newline at end of file diff --git a/MelonLoader.sln b/MelonLoader.sln index a432ca006..01a75c5d9 100644 --- a/MelonLoader.sln +++ b/MelonLoader.sln @@ -96,13 +96,11 @@ Global {762D7545-6F6B-441A-B040-49CC31A1713B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {762D7545-6F6B-441A-B040-49CC31A1713B}.Debug|Any CPU.Build.0 = Debug|Any CPU {762D7545-6F6B-441A-B040-49CC31A1713B}.Debug|Windows - x64.ActiveCfg = Debug|Any CPU - {762D7545-6F6B-441A-B040-49CC31A1713B}.Debug|Windows - x64.Build.0 = Debug|Any CPU {762D7545-6F6B-441A-B040-49CC31A1713B}.Debug|Windows - x86.ActiveCfg = Debug|Any CPU {762D7545-6F6B-441A-B040-49CC31A1713B}.Debug|Windows - x86.Build.0 = Debug|Any CPU {762D7545-6F6B-441A-B040-49CC31A1713B}.Release|Any CPU.ActiveCfg = Release|Any CPU {762D7545-6F6B-441A-B040-49CC31A1713B}.Release|Any CPU.Build.0 = Release|Any CPU {762D7545-6F6B-441A-B040-49CC31A1713B}.Release|Windows - x64.ActiveCfg = Release|Any CPU - {762D7545-6F6B-441A-B040-49CC31A1713B}.Release|Windows - x64.Build.0 = Release|Any CPU {762D7545-6F6B-441A-B040-49CC31A1713B}.Release|Windows - x86.ActiveCfg = Release|Any CPU {762D7545-6F6B-441A-B040-49CC31A1713B}.Release|Windows - x86.Build.0 = Release|Any CPU {542EC51D-E480-4802-B5AA-96EEC05AF19C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU diff --git a/MelonLoader/Attributes/VerifyLoaderVersionAttribute.cs b/MelonLoader/Attributes/VerifyLoaderVersionAttribute.cs index ae49bf02b..941f841b0 100644 --- a/MelonLoader/Attributes/VerifyLoaderVersionAttribute.cs +++ b/MelonLoader/Attributes/VerifyLoaderVersionAttribute.cs @@ -1,51 +1,50 @@ using System; using Semver; -namespace MelonLoader +namespace MelonLoader; + +[AttributeUsage(AttributeTargets.Assembly)] +public class VerifyLoaderVersionAttribute(SemVersion semver, bool is_minimum) : Attribute { - [AttributeUsage(AttributeTargets.Assembly)] - public class VerifyLoaderVersionAttribute : Attribute - { - /// - /// Specified SemVersion. - /// - public SemVersion SemVer { get; private set; } - - /// - /// Specified Version Major. - /// - public int Major { get; } - - /// - /// Specified Version Minor. - /// - public int Minor { get; } - - /// - /// Specified Version Patch. - /// - public int Patch { get; } - - /// - /// If Version Specified is a Minimum. - /// - public bool IsMinimum { get; private set; } - - - public VerifyLoaderVersionAttribute(int major, int minor, int patch) : this(new SemVersion(major, minor, patch), false) { } - public VerifyLoaderVersionAttribute(int major, int minor, int patch, bool is_minimum) : this(new SemVersion(major, minor, patch), is_minimum) { } - public VerifyLoaderVersionAttribute(string version) : this(version, false) { } - public VerifyLoaderVersionAttribute(string version, bool is_minimum) : this(SemVersion.Parse(version), is_minimum) { } - public VerifyLoaderVersionAttribute(SemVersion semver, bool is_minimum) - { - SemVer = semver; - IsMinimum = is_minimum; - } - - public bool IsCompatible(SemVersion version) - => SemVer == null || version == null || (IsMinimum ? SemVer <= version : SemVer == version); - - public bool IsCompatible(string version) - => !SemVersion.TryParse(version, out SemVersion ver) || IsCompatible(ver); - } + /// + /// Specified SemVersion. + /// + public SemVersion SemVer { get; private set; } = semver; + + /// + /// Specified Version Major. + /// + public int Major => SemVer.Major; + + /// + /// Specified Version Minor. + /// + public int Minor => SemVer.Minor; + + /// + /// Specified Version Patch. + /// + public int Patch => SemVer.Patch; + + /// + /// Specified Version Prerelease. + /// + public string Prerelease => SemVer.Prerelease; + + /// + /// If Version Specified is a Minimum. + /// + public bool IsMinimum { get; private set; } = is_minimum; + + public VerifyLoaderVersionAttribute(int major, int minor, int patch) : this(new SemVersion(major, minor, patch), false) { } + public VerifyLoaderVersionAttribute(int major, int minor, int patch, string prerelease, bool is_minimum = false) : this(new SemVersion(major, minor, patch, prerelease), is_minimum) { } + public VerifyLoaderVersionAttribute(int major, int minor, int patch, bool is_minimum) : this(new SemVersion(major, minor, patch), is_minimum) { } + public VerifyLoaderVersionAttribute(string version) : this(version, false) { } + public VerifyLoaderVersionAttribute(string version, bool is_minimum) : this(SemVersion.Parse(version), is_minimum) { } + + public bool IsCompatible(SemVersion version) + => SemVer == null || version == null || (IsMinimum ? SemVer <= version : SemVer == version); + + public bool IsCompatible(string version) + => !SemVersion.TryParse(version, out SemVersion ver) || IsCompatible(ver); } \ No newline at end of file diff --git a/MelonLoader/BuildInfo.cs b/MelonLoader/BuildInfo.cs new file mode 100644 index 000000000..c83b90ff7 --- /dev/null +++ b/MelonLoader/BuildInfo.cs @@ -0,0 +1,23 @@ +using Semver; + +namespace MelonLoader; + +public static class BuildInfo +{ + public const string Name = "MelonLoader"; + public const string Description = "MelonLoader"; + public const string Author = "Lava Gang"; + public const string Company = "discord.gg/2Wn3N2P"; + + public static SemVersion VersionNumber { get; private set; } + + // NOTICE: This used to be a constant. Making it a property won't break backwards compatibility. + public static string Version { get; private set; } + + static BuildInfo() + { + var version = typeof(BuildInfo).Assembly.GetName().Version!; + VersionNumber = new(version.Major, version.Minor, version.Build, version.Revision == 0 ? "" : ("ci." + version.Revision.ToString())); + Version = VersionNumber.ToString(); + } +} \ No newline at end of file diff --git a/MelonLoader/CompatibilityLayers/MelonCompatibilityLayer.cs b/MelonLoader/CompatibilityLayers/MelonCompatibilityLayer.cs index 0f380aa48..f9b622239 100644 --- a/MelonLoader/CompatibilityLayers/MelonCompatibilityLayer.cs +++ b/MelonLoader/CompatibilityLayers/MelonCompatibilityLayer.cs @@ -18,10 +18,15 @@ public static class MelonCompatibilityLayer private static void CheckGameLayerWithPlatform(string name, Func shouldBeIgnored) { + if (string.IsNullOrEmpty(name)) + return; + string nameNoSpaces = name.Replace(' ', '_'); foreach (var file in Directory.GetFiles(baseDirectory)) { string fileName = Path.GetFileNameWithoutExtension(file); + if (string.IsNullOrEmpty(fileName)) + continue; if (fileName.StartsWith(nameNoSpaces)) layers.Add(new MelonModule.Info(file, shouldBeIgnored)); } @@ -29,6 +34,9 @@ private static void CheckGameLayerWithPlatform(string name, Func shouldBeI private static void CheckGameLayer(string name) { + if (string.IsNullOrEmpty(name)) + return; + CheckGameLayerWithPlatform(name, () => false); CheckGameLayerWithPlatform($"{name}_Mono", () => MelonUtils.IsGameIl2Cpp()); CheckGameLayerWithPlatform($"{name}_Il2Cpp", () => !MelonUtils.IsGameIl2Cpp()); @@ -37,6 +45,9 @@ private static void CheckGameLayer(string name) if (spaceIndex > 0) { name = name.Substring(0, spaceIndex - 1); + if (string.IsNullOrEmpty(name)) + return; + CheckGameLayerWithPlatform(name, () => false); CheckGameLayerWithPlatform($"{name}_Mono", () => MelonUtils.IsGameIl2Cpp()); CheckGameLayerWithPlatform($"{name}_Il2Cpp", () => !MelonUtils.IsGameIl2Cpp()); diff --git a/MelonLoader/Core.cs b/MelonLoader/Core.cs index 5f5819b14..bb2206877 100644 --- a/MelonLoader/Core.cs +++ b/MelonLoader/Core.cs @@ -7,6 +7,9 @@ using MelonLoader.Resolver; using MelonLoader.Utils; using MelonLoader.InternalUtils; + +[assembly: MelonLoader.PatchShield] + #pragma warning disable IDE0051 // Prevent the IDE from complaining about private unreferenced methods namespace MelonLoader @@ -107,7 +110,7 @@ internal static int Initialize() bHapticsManager.Connect(BuildInfo.Name, UnityInformationHandler.GameName); MelonHandler.LoadUserlibs(MelonEnvironment.UserLibsDirectory); - MelonHandler.LoadMelonFolders(MelonEnvironment.PluginsDirectory); + MelonHandler.LoadMelonsFromDirectory(MelonEnvironment.PluginsDirectory); MelonEvents.MelonHarmonyEarlyInit.Invoke(); MelonEvents.OnPreInitialization.Invoke(); @@ -137,7 +140,7 @@ internal static int Start() return 1; MelonEvents.OnPreModsLoaded.Invoke(); - MelonHandler.LoadMelonFolders(MelonEnvironment.ModsDirectory); + MelonHandler.LoadMelonsFromDirectory(MelonEnvironment.ModsDirectory); MelonEvents.OnPreSupportModule.Invoke(); if (!SupportModule.Setup()) diff --git a/MelonLoader/Fixes/Il2CppICallInjector.cs b/MelonLoader/Fixes/Il2CppICallInjector.cs index bc2a8e7d7..7c4e00a4f 100644 --- a/MelonLoader/Fixes/Il2CppICallInjector.cs +++ b/MelonLoader/Fixes/Il2CppICallInjector.cs @@ -1,23 +1,22 @@ #if NET6_0_OR_GREATER -using Il2CppInterop.Runtime; -using Il2CppInterop.Runtime.InteropTypes; using MelonLoader.NativeUtils; using MonoMod.RuntimeDetour; using MonoMod.Utils; using System; using System.Collections.Generic; using System.Reflection; -using System.Reflection.Emit; using System.Runtime.InteropServices; +using Il2CppInterop.HarmonySupport; +using HarmonyLib; + +#pragma warning disable 0649 namespace MelonLoader.Fixes { internal static class Il2CppICallInjector { - private const string _customICallSuffix = "_INative"; - - private static Dictionary _lookup = new(); + private static Dictionary _lookup = new(); private delegate IntPtr dil2cpp_resolve_icall(IntPtr signature); private static NativeHook il2cpp_resolve_icall_hook; @@ -25,18 +24,10 @@ internal static class Il2CppICallInjector private delegate void dil2cpp_add_internal_call(IntPtr signature, IntPtr funcPtr); private static dil2cpp_add_internal_call il2cpp_add_internal_call; - private static Type _stringType; - private static Type _intPtrType; - private static Type _exceptionType; - private static Type _il2CppObjectBaseType; - - private static MethodInfo _stringConcat; - private static MethodInfo _objectToString; - private static MethodInfo _melonLoggerError; - private static MethodInfo _stringToIl2CppPtr; - private static MethodInfo _il2CppPtrToString; - private static MethodInfo _il2CppObjectBaseGetPointer; + private static Type _il2CppDetourMethodPatcher; + private static MethodInfo _generateNativeToManagedTrampoline; + private static bool _extendedDebug; private static MelonLogger.Instance _logger; internal static unsafe void Install() @@ -45,41 +36,13 @@ internal static unsafe void Install() { _logger = new MelonLogger.Instance(nameof(Il2CppICallInjector)); - Type thisType = typeof(Il2CppICallInjector); - Type objectType = typeof(object); - Type il2cppType = typeof(IL2CPP); - - _il2CppObjectBaseType = typeof(Il2CppObjectBase); - _exceptionType = typeof(Exception); - _intPtrType = typeof(IntPtr); - _stringType = typeof(string); - - _stringConcat = _stringType.GetMethod(nameof(string.Concat), [_stringType, _stringType]); - if (_stringConcat == null) - throw new Exception("Failed to get string.Concat"); - - _objectToString = objectType.GetMethod(nameof(ToString)); - if (_objectToString == null) - throw new Exception("Failed to get object.ToString"); - - _stringToIl2CppPtr = il2cppType.GetMethod(nameof(IL2CPP.ManagedStringToIl2Cpp)); - if (_stringToIl2CppPtr == null) - throw new Exception("Failed to get IL2CPP.ManagedStringToIl2Cpp"); - - _melonLoggerError = thisType.GetMethod(nameof(LogError), - BindingFlags.Static | BindingFlags.NonPublic, - [_stringType]); - if (_melonLoggerError == null) - throw new Exception("Failed to get MelonLogger.Error"); + _il2CppDetourMethodPatcher = typeof(HarmonySupport).Assembly.GetType("Il2CppInterop.HarmonySupport.Il2CppDetourMethodPatcher"); + if (_il2CppDetourMethodPatcher == null) + throw new Exception("Failed to get Il2CppDetourMethodPatcher"); - _il2CppPtrToString = il2cppType.GetMethod(nameof(IL2CPP.Il2CppStringToManaged)); - if (_il2CppPtrToString == null) - throw new Exception("Failed to get IL2CPP.Il2CppStringToManaged"); - - PropertyInfo pointerProp = _il2CppObjectBaseType.GetProperty(nameof(Il2CppObjectBase.Pointer)); - if (_il2CppPtrToString == null) - throw new Exception("Failed to get Il2CppObjectBase.Pointer"); - _il2CppObjectBaseGetPointer = pointerProp.GetMethod; + _generateNativeToManagedTrampoline = _il2CppDetourMethodPatcher.GetMethod("GenerateNativeToManagedTrampoline", BindingFlags.NonPublic | BindingFlags.Instance); + if (_generateNativeToManagedTrampoline == null) + throw new Exception("Failed to get Il2CppDetourMethodPatcher.GenerateNativeToManagedTrampoline"); string gameAssemblyName = "GameAssembly"; NativeLibrary gameAssemblyLib = NativeLibrary.Load(gameAssemblyName); @@ -101,7 +64,7 @@ internal static unsafe void Install() } catch (Exception e) { - LogError(e.ToString()); + LogDebugWarning(e.ToString()); } } @@ -122,8 +85,24 @@ internal static void Shutdown() } } + private static void LogMsg(string msg) + => _logger.Msg(msg); private static void LogError(string msg) => _logger.Error(msg); + private static void LogDebugMsg(string msg) + { + if (!_extendedDebug + || !MelonDebug.IsEnabled()) + return; + _logger.Msg(msg); + } + private static void LogDebugWarning(string msg) + { + if (!_extendedDebug + || !MelonDebug.IsEnabled()) + return; + _logger.Warning(msg); + } private static IntPtr il2cpp_resolve_icall_Detour(IntPtr signature) { @@ -134,31 +113,44 @@ private static IntPtr il2cpp_resolve_icall_Detour(IntPtr signature) // Check Cache if (_lookup.TryGetValue(signatureStr, out var result)) - return result.Item3; + { + LogDebugMsg($"Resolved {signatureStr} to ICall in Cache"); + return result.Item4; + } // Run Original IntPtr originalResult = il2cpp_resolve_icall_hook.Trampoline(signature); if (originalResult != IntPtr.Zero) { // Cache Original Result - _lookup[signatureStr] = (null, null, originalResult); + LogDebugMsg($"Resolved {signatureStr} to Unity ICall"); + _lookup[signatureStr] = (null, null, null, originalResult); return originalResult; } // Check if Injection is Needed if (!ShouldInject(signatureStr, out MethodInfo unityShimMethod)) + { + LogDebugWarning($"Unable to find suitable method to inject for {signatureStr}"); return IntPtr.Zero; + } // Create Injected Function and Cache Return - var pair = - _lookup[signatureStr] = GenerateTrampoline(unityShimMethod); + LogDebugMsg($"Generating Trampoline for {signatureStr}"); + var pair = GenerateTrampoline(unityShimMethod); + if (pair.Item4 == IntPtr.Zero) + { + LogDebugWarning($"Failed to generate trampoline for {signatureStr}"); + return IntPtr.Zero; + } // Add New ICall to Il2Cpp Domain - il2cpp_add_internal_call(signature, pair.Item3); - _logger.Msg($"Registered mono icall {signatureStr} in il2cpp domain"); + _lookup[signatureStr] = pair; + il2cpp_add_internal_call(signature, pair.Item4); + LogMsg($"Registered mono icall {signatureStr} in il2cpp domain"); // Return New Function Pointer - return pair.Item3; + return pair.Item4; } private static Type FindType(string typeFullName) @@ -192,6 +184,7 @@ private static bool ShouldInject(string signature, out MethodInfo unityShimMetho // Split the Signature string[] split = signature.Split("::"); string typeName = split[0]; + string methodName = split[1]; // Find Managed Type Type newType = FindType(typeName); @@ -199,166 +192,67 @@ private static bool ShouldInject(string signature, out MethodInfo unityShimMetho return false; // Find Managed Method - string methodName = split[1]; - MethodInfo method = newType.FindMethod(methodName); - if (method == null) + MethodInfo targetMethod = null; + try + { + // Get All Methods + MethodInfo[] allMethods = newType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance); + foreach (var method in allMethods) + { + // Validate Method + if ((method == null) + || (method.Name != methodName)) + continue; + + // Check for Generic Method since ICalls can't be Generic + if (method.IsGenericMethod) + continue; + + // Check for PInvoke to prevent Recursion + if (method.Attributes.HasFlag(MethodAttributes.PinvokeImpl)) + continue; + + // Check for Extern to prevent Recursion + var methodImpl = method.GetMethodImplementationFlags(); + if (methodImpl.HasFlag(MethodImplAttributes.InternalCall) + || methodImpl.HasFlag(MethodImplAttributes.Native) + || methodImpl.HasFlag(MethodImplAttributes.Unmanaged)) + continue; + + // Check if Method has no Body or just throws NotImplementedException + if (!method.HasMethodBody() + || method.IsNotImplemented()) + continue; + + // Found Shim + targetMethod = method; + break; + } + } + catch { return false; } + if (targetMethod == null) return false; // Inject ICall - unityShimMethod = method; + unityShimMethod = targetMethod; return true; } - private static (DynamicMethodDefinition, MethodInfo, IntPtr) GenerateTrampoline(MethodInfo unityShimMethod) + private static (object, DynamicMethodDefinition, MethodInfo, IntPtr) GenerateTrampoline(MethodInfo unityShimMethod) { - // Convert Method Parameters to Native Parameters - var methodParams = unityShimMethod.GetParameters(); - int offset = unityShimMethod.IsStatic ? 0 : 1; - Type[] paramTypes = new Type[methodParams.Length + offset]; - if (!unityShimMethod.IsStatic) - paramTypes[0] = _intPtrType; - for (int i = 0; i < methodParams.Length; i++) - { - if ((methodParams[i].ParameterType != _stringType) - && methodParams[i].ParameterType.IsValueType) - paramTypes[i + offset] = methodParams[i].ParameterType; - else - paramTypes[i + offset] = _intPtrType; - } - - // Convert Return Type - Type returnType = unityShimMethod.ReturnType; - if ((returnType == _stringType) - || !returnType.IsValueType) - returnType = _intPtrType; + // Create Patcher + object patcher = Activator.CreateInstance(_il2CppDetourMethodPatcher, [ unityShimMethod ]); + if (patcher == null) + return (null, null, null, IntPtr.Zero); // Create New Injected ICall Method - string newMethodName = $"{unityShimMethod.Name}{_customICallSuffix}"; - var trampoline = new DynamicMethodDefinition( - newMethodName, - returnType, - paramTypes); - var ilGenerator = trampoline.GetILGenerator(); - - // Begin Try-Catch - ilGenerator.BeginExceptionBlock(); - - // Emit This Object - if (!unityShimMethod.IsStatic) - ilGenerator.EmitPtrArgToManagedObject(0, unityShimMethod.DeclaringType); - - // Convert Method Parameters to Managed Objects - for (var i = 0; i < methodParams.Length; i++) - { - var param = methodParams[i]; - var paramType = param.ParameterType; - if (paramType == _stringType) - ilGenerator.EmitPtrArgToString(i + offset); - else if (paramType.IsValueType) - ilGenerator.EmitArg(i + offset); - else - ilGenerator.EmitPtrArgToManagedObject(i + offset, paramType); - } - - // Call Existing Method - ilGenerator.Emit(OpCodes.Call, unityShimMethod); - - // Convert Managed Return - var oldreturnType = unityShimMethod.ReturnType; - if (oldreturnType == _stringType) - ilGenerator.EmitStringToPtr(); - else if ((oldreturnType == _il2CppObjectBaseType) - || oldreturnType.IsSubclassOf(_il2CppObjectBaseType)) - ilGenerator.EmitIl2CppObjectBaseToPtr(); - - // Cache Return Value in Lcal - LocalBuilder returnLocal = null; - if (returnType != typeof(void)) - { - returnLocal = ilGenerator.DeclareLocal(returnType); - ilGenerator.Emit(OpCodes.Stloc, returnLocal); - } - - // End Try-Catch - ilGenerator.EmitExceptionCatch(); - - // Restore Return Value from Local - if (returnLocal != null) - ilGenerator.Emit(OpCodes.Ldloc, returnLocal); - - // Return even if there is no Return Value - ilGenerator.Emit(OpCodes.Ret); - + DynamicMethodDefinition trampoline = (DynamicMethodDefinition)_generateNativeToManagedTrampoline.Invoke(patcher, [ unityShimMethod ]); + if (trampoline == null) + return (null, null, null, IntPtr.Zero); + // Return the New Method MethodInfo newMethod = trampoline.Generate().Pin(); - return (trampoline, newMethod, newMethod.GetNativeStart()); - } - - private static void EmitArg(this ILGenerator ilGenerator, - int index) - => ilGenerator.Emit(OpCodes.Ldarg, index); - - private static void EmitPtrArgToString(this ILGenerator ilGenerator, - int argIndex) - { - ilGenerator.EmitArg(argIndex); - ilGenerator.Emit(OpCodes.Call, _il2CppPtrToString); - } - - private static void EmitStringToPtr(this ILGenerator ilGenerator) - => ilGenerator.Emit(OpCodes.Call, _stringToIl2CppPtr); - - private static void EmitPtrArgToManagedObject(this ILGenerator ilGenerator, - int argIndex, - Type managedType) - { - ilGenerator.EmitArg(argIndex); - - var labelNull = ilGenerator.DefineLabel(); - var labelDone = ilGenerator.DefineLabel(); - ilGenerator.Emit(OpCodes.Brfalse, labelNull); - ilGenerator.EmitArg(argIndex); - - ilGenerator.Emit(OpCodes.Newobj, - managedType.GetConstructor([ _intPtrType ])); - - ilGenerator.Emit(OpCodes.Br, labelDone); - ilGenerator.MarkLabel(labelNull); - ilGenerator.Emit(OpCodes.Ldnull); - ilGenerator.MarkLabel(labelDone); - } - - private static void EmitIl2CppObjectBaseToPtr(this ILGenerator ilGenerator) - { - var labelNull = ilGenerator.DefineLabel(); - var labelDone = ilGenerator.DefineLabel(); - ilGenerator.Emit(OpCodes.Dup); - ilGenerator.Emit(OpCodes.Brfalse, labelNull); - - ilGenerator.Emit(OpCodes.Call, _il2CppObjectBaseGetPointer); - - ilGenerator.Emit(OpCodes.Br, labelDone); - ilGenerator.MarkLabel(labelNull); - ilGenerator.Emit(OpCodes.Pop); - ilGenerator.Emit(OpCodes.Ldc_I4_0); - ilGenerator.Emit(OpCodes.Conv_I); - ilGenerator.MarkLabel(labelDone); - } - - private static void EmitExceptionCatch(this ILGenerator ilGenerator) - { - var exceptionLocal = ilGenerator.DeclareLocal(_exceptionType); - ilGenerator.BeginCatchBlock(_exceptionType); - - ilGenerator.Emit(OpCodes.Stloc, exceptionLocal); - ilGenerator.Emit(OpCodes.Ldstr, "Exception in IL2CPP Injected ICall: "); - ilGenerator.Emit(OpCodes.Ldloc, exceptionLocal); - - ilGenerator.Emit(OpCodes.Callvirt, _objectToString); - ilGenerator.Emit(OpCodes.Call, _stringConcat); - ilGenerator.Emit(OpCodes.Call, _melonLoggerError); - - ilGenerator.EndExceptionBlock(); + return (patcher, trampoline, newMethod, newMethod.GetNativeStart()); } } } diff --git a/MelonLoader/Fixes/Il2CppInteropFixes.cs b/MelonLoader/Fixes/Il2CppInteropFixes.cs index ea58d70aa..c94fc0351 100644 --- a/MelonLoader/Fixes/Il2CppInteropFixes.cs +++ b/MelonLoader/Fixes/Il2CppInteropFixes.cs @@ -67,6 +67,19 @@ internal unsafe static class Il2CppInteropFixes private static MethodInfo _reportException; private static MethodInfo _reportException_Prefix; + private static void LogMsg(string msg) + => _logger.Msg(msg); + private static void LogError(Exception ex) + => _logger.Error(ex); + private static void LogError(string msg, Exception ex) + => _logger.Error(msg, ex); + private static void LogDebugMsg(string msg) + { + if (!MelonDebug.IsEnabled()) + return; + _logger.Msg(msg); + } + internal static void Install() { try @@ -173,61 +186,61 @@ internal static void Install() _rewriteGlobalContext_TryGetNewTypeForOriginal_Prefix = thisType.GetMethod(nameof(RewriteGlobalContext_TryGetNewTypeForOriginal_Prefix), BindingFlags.NonPublic | BindingFlags.Static); _reportException_Prefix = thisType.GetMethod(nameof(ReportException_Prefix), BindingFlags.NonPublic | BindingFlags.Static); - MelonDebug.Msg("Patching Il2CppInterop ClassInjector.SystemTypeFromIl2CppType..."); + LogDebugMsg("Patching Il2CppInterop ClassInjector.SystemTypeFromIl2CppType..."); Core.HarmonyInstance.Patch(_systemTypeFromIl2CppType, new HarmonyMethod(_systemTypeFromIl2CppType_Prefix), null, new HarmonyMethod(_systemTypeFromIl2CppType_Transpiler)); - MelonDebug.Msg("Patching Il2CppInterop ClassInjector.RegisterTypeInIl2Cpp..."); + LogDebugMsg("Patching Il2CppInterop ClassInjector.RegisterTypeInIl2Cpp..."); Core.HarmonyInstance.Patch(_registerTypeInIl2Cpp, null, null, new HarmonyMethod(_registerTypeInIl2Cpp_Transpiler)); - MelonDebug.Msg("Patching Il2CppInterop ClassInjector.IsTypeSupported..."); + LogDebugMsg("Patching Il2CppInterop ClassInjector.IsTypeSupported..."); Core.HarmonyInstance.Patch(_isTypeSupported, null, null, new HarmonyMethod(_isTypeSupported_Transpiler)); - MelonDebug.Msg("Patching Il2CppInterop ClassInjector.RewriteType..."); + LogDebugMsg("Patching Il2CppInterop ClassInjector.RewriteType..."); Core.HarmonyInstance.Patch(_rewriteType, new HarmonyMethod(_rewriteType_Prefix)); - MelonDebug.Msg("Patching Il2CppInterop ClassInjector.ConvertMethodInfo..."); + LogDebugMsg("Patching Il2CppInterop ClassInjector.ConvertMethodInfo..."); Core.HarmonyInstance.Patch(_convertMethodInfo, null, null, new HarmonyMethod(_convertMethodInfo_Transpiler)); - MelonDebug.Msg("Patching Il2CppInterop ILGeneratorEx.EmitObjectToPointer..."); + LogDebugMsg("Patching Il2CppInterop ILGeneratorEx.EmitObjectToPointer..."); Core.HarmonyInstance.Patch(_emitObjectToPointer, new HarmonyMethod(_emitObjectToPointer_Prefix)); - MelonDebug.Msg("Patching Il2CppInterop RewriteGlobalContext.AddAssemblyContext..."); + LogDebugMsg("Patching Il2CppInterop RewriteGlobalContext.AddAssemblyContext..."); Core.HarmonyInstance.Patch(_rewriteGlobalContext_AddAssemblyContext, null, new HarmonyMethod(_rewriteGlobalContext_AddAssemblyContext_Postfix)); - MelonDebug.Msg("Patching Il2CppInterop RewriteGlobalContext.Dispose..."); + LogDebugMsg("Patching Il2CppInterop RewriteGlobalContext.Dispose..."); Core.HarmonyInstance.Patch(_rewriteGlobalContext_Dispose, new HarmonyMethod(_rewriteGlobalContext_Dispose_Prefix)); - MelonDebug.Msg("Patching Il2CppInterop RewriteGlobalContext.GetNewAssemblyForOriginal..."); + LogDebugMsg("Patching Il2CppInterop RewriteGlobalContext.GetNewAssemblyForOriginal..."); Core.HarmonyInstance.Patch(_rewriteGlobalContext_GetNewAssemblyForOriginal, new HarmonyMethod(_rewriteGlobalContext_GetNewAssemblyForOriginal_Prefix)); - MelonDebug.Msg("Patching Il2CppInterop RewriteGlobalContext.TryGetNewTypeForOriginal..."); + LogDebugMsg("Patching Il2CppInterop RewriteGlobalContext.TryGetNewTypeForOriginal..."); Core.HarmonyInstance.Patch(_rewriteGlobalContext_TryGetNewTypeForOriginal, new HarmonyMethod(_rewriteGlobalContext_TryGetNewTypeForOriginal_Prefix)); - MelonDebug.Msg("Patching Il2CppInterop Il2CppDetourMethodPatcher.ReportException..."); + LogDebugMsg("Patching Il2CppInterop Il2CppDetourMethodPatcher.ReportException..."); Core.HarmonyInstance.Patch(_reportException, new HarmonyMethod(_reportException_Prefix)); } catch (Exception e) { - MelonLogger.Error(e); + LogError(e); } } @@ -299,15 +312,13 @@ private static void FixedAddTypeToLookup(Type type, IntPtr typePointer) private static bool ReportException_Prefix(Exception __0) { - _logger.Error("During invoking native->managed trampoline", __0); - + LogError("During invoking native->managed trampoline", __0); return false; } private static bool EmitObjectToPointer_Prefix(bool __7, ref bool __8) { __8 = __7; - return true; } @@ -342,7 +353,7 @@ private static void RewriteGlobalContext_AddAssemblyContext_Postfix(RewriteGloba return; contexts[assemblyName] = __1; - //MelonDebug.Msg($"[RewriteGlobalContext] Added: {assemblyName}"); + //LogDebugMsg($"[RewriteGlobalContext] Added: {assemblyName}"); } private static bool RewriteGlobalContext_Dispose_Prefix(RewriteGlobalContext __instance) @@ -370,7 +381,7 @@ private static bool RewriteGlobalContext_GetNewAssemblyForOriginal_Prefix(Rewrit string assemblyName = __0.Name; if (contexts.TryGetValue(assemblyName, out __result)) { - //MelonDebug.Msg($"[RewriteGlobalContext] Found: {assemblyName}"); + //LogDebugMsg($"[RewriteGlobalContext] Found: {assemblyName}"); return false; } @@ -381,7 +392,7 @@ private static bool RewriteGlobalContext_GetNewAssemblyForOriginal_Prefix(Rewrit if (contexts.TryGetValue(assemblyName, out __result)) { - //MelonDebug.Msg($"[RewriteGlobalContext] Found: {assemblyName}"); + //LogDebugMsg($"[RewriteGlobalContext] Found: {assemblyName}"); return false; } @@ -407,7 +418,7 @@ private static bool RewriteGlobalContext_TryGetNewTypeForOriginal_Prefix(Rewrite AssemblyRewriteContext rewriteContext = null; if (contexts.TryGetValue(assemblyName, out rewriteContext)) { - //MelonDebug.Msg($"[RewriteGlobalContext] Found: {assemblyName}"); + //LogDebugMsg($"[RewriteGlobalContext] Found: {assemblyName}"); __result = rewriteContext.TryGetContextForOriginalType(__0); return false; } @@ -418,7 +429,7 @@ private static bool RewriteGlobalContext_TryGetNewTypeForOriginal_Prefix(Rewrite assemblyName = $"Il2Cpp{assemblyName}"; if (contexts.TryGetValue(assemblyName, out rewriteContext)) { - //MelonDebug.Msg($"[RewriteGlobalContext] Found: {assemblyName}"); + //LogDebugMsg($"[RewriteGlobalContext] Found: {assemblyName}"); __result = rewriteContext.TryGetContextForOriginalType(__0); return false; } @@ -510,7 +521,7 @@ private static IEnumerable SystemTypeFromIl2CppType_Transpiler( instruction.opcode = OpCodes.Call; instruction.operand = _fixedFindType; - MelonDebug.Msg("Patched Il2CppInterop ClassInjector.SystemTypeFromIl2CppType -> Type.GetType"); + LogDebugMsg("Patched Il2CppInterop ClassInjector.SystemTypeFromIl2CppType -> Type.GetType"); } yield return instruction; @@ -529,7 +540,7 @@ private static IEnumerable RegisterTypeInIl2Cpp_Transpiler(IEnu found = true; instruction.opcode = OpCodes.Call; instruction.operand = _fixedAddTypeToLookup; - MelonDebug.Msg("Patched Il2CppInterop ClassInjector.RegisterTypeInIl2Cpp -> InjectorHelpers.AddTypeToLookup"); + LogDebugMsg("Patched Il2CppInterop ClassInjector.RegisterTypeInIl2Cpp -> InjectorHelpers.AddTypeToLookup"); } if (!found2 @@ -539,7 +550,7 @@ private static IEnumerable RegisterTypeInIl2Cpp_Transpiler(IEnu found2 = true; instruction.opcode = OpCodes.Call; instruction.operand = _fixedFindAbstractMethods; - MelonDebug.Msg("Patched Il2CppInterop ClassInjector.RegisterTypeInIl2Cpp -> FindAbstractMethods"); + LogDebugMsg("Patched Il2CppInterop ClassInjector.RegisterTypeInIl2Cpp -> FindAbstractMethods"); } yield return instruction; @@ -558,7 +569,7 @@ private static IEnumerable ConvertMethodInfo_Transpiler(IEnumer found = true; instruction.opcode = OpCodes.Call; instruction.operand = _fixedIsByRef; - MelonDebug.Msg("Patched Il2CppInterop ClassInjector.ConvertMethodInfo -> Type.IsByRef"); + LogDebugMsg("Patched Il2CppInterop ClassInjector.ConvertMethodInfo -> Type.IsByRef"); } yield return instruction; @@ -576,7 +587,7 @@ private static IEnumerable IsTypeSupported_Transpiler(IEnumerab found = true; instruction.opcode = OpCodes.Call; instruction.operand = _fixedIsByRef; - MelonDebug.Msg("Patched Il2CppInterop ClassInjector.IsTypeSupported -> Type.IsByRef"); + LogDebugMsg("Patched Il2CppInterop ClassInjector.IsTypeSupported -> Type.IsByRef"); } yield return instruction; diff --git a/MelonLoader/InternalUtils/DependencyGraph.cs b/MelonLoader/InternalUtils/DependencyGraph.cs index 546fbdbaa..8c232ef92 100644 --- a/MelonLoader/InternalUtils/DependencyGraph.cs +++ b/MelonLoader/InternalUtils/DependencyGraph.cs @@ -179,7 +179,7 @@ private static string BuildMissingDependencyMessage(IDictionary argEnumerator = new LemonEnumerator(CommandLineArgs); - while (argEnumerator.MoveNext()) + string[] args = CommandLineArgs; + int maxLen = args.Length; + for (int i = 1; i < maxLen; i++) { - string fullcmd = argEnumerator.Current; + string fullcmd = args[i]; if (string.IsNullOrEmpty(fullcmd)) continue; @@ -78,11 +79,12 @@ internal static void Load() noPrefixCmd = split[0]; cmdArg = split[1]; } + if ((string.IsNullOrEmpty(cmdArg) - && !argEnumerator.Peek(out cmdArg)) + && ((i + 1) >= maxLen)) || string.IsNullOrEmpty(cmdArg) - || !cmdArg.StartsWith("--") - || !cmdArg.StartsWith("-")) + || cmdArg.StartsWith("--") + || cmdArg.StartsWith("-")) { // Unknown Command, Add it to Dictionary ExternalArguments.Add(noPrefixCmd, null); diff --git a/MelonLoader/MelonLoader.csproj b/MelonLoader/MelonLoader.csproj index 7b13fc509..8abca3600 100644 --- a/MelonLoader/MelonLoader.csproj +++ b/MelonLoader/MelonLoader.csproj @@ -1,26 +1,21 @@ - + net35;net6 - Latest true - false true $(SolutionDir)Output\$(Configuration)\MelonLoader\ $(OutputPath)$(TargetFramework)\MelonLoader.xml true true embedded - - 0.6.6 + + true LavaGang.MelonLoader modding unity https://github.com/LavaGang/MelonLoader Apache-2.0 git https://github.com/LavaGang/MelonLoader - Lava Gang - Lava Gang - Copyright (c) 2022 Lava Gang The World's First Universal Mod Loader for Unity Games compatible with both Il2Cpp and Mono. @@ -31,30 +26,41 @@ all + + + + + + + + - + + + + + - - + + + - - - + diff --git a/MelonLoader/MelonUtils.cs b/MelonLoader/MelonUtils.cs index fa0e64974..281a33ce8 100644 --- a/MelonLoader/MelonUtils.cs +++ b/MelonLoader/MelonUtils.cs @@ -51,7 +51,7 @@ internal static void Setup(AppDomain domain) UnityInformationHandler.Setup(); CurrentGameAttribute = new MelonGameAttribute(UnityInformationHandler.GameDeveloper, UnityInformationHandler.GameName); - CurrentPlatform = IsGame32Bit() ? MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X86 : MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64; // Temporarily + CurrentPlatform = IsGame32Bit() ? MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X86 : MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64; CurrentDomain = IsGameIl2Cpp() ? MelonPlatformDomainAttribute.CompatibleDomains.IL2CPP : MelonPlatformDomainAttribute.CompatibleDomains.MONO; } @@ -303,11 +303,14 @@ public static IEnumerable GetValidTypes(this Assembly asm, LemonFunc (x != null) && (predicate == null || predicate(x))); } @@ -318,9 +321,9 @@ public static Type GetValidType(this Assembly asm, string typeName, LemonFunc FindIncompatiblities(game, processName, gameVersion, SemVersion.Parse(mlVersion), mlBuildHashCode, platform, domain); + + public Incompatibility[] FindIncompatiblities(MelonGameAttribute game, string processName, string gameVersion, + SemVersion mlVersion, string mlBuildHashCode, MelonPlatformAttribute.CompatiblePlatforms platform, + MelonPlatformDomainAttribute.CompatibleDomains domain) { var result = new List(); if (!(Games.Length == 0 || Games.Any(x => x.IsCompatible(game)))) @@ -305,7 +311,7 @@ public Incompatibility[] FindIncompatiblities(MelonGameAttribute game, string pr public Incompatibility[] FindIncompatiblitiesFromContext() { - return FindIncompatiblities(MelonUtils.CurrentGameAttribute, Process.GetCurrentProcess().ProcessName, MelonUtils.GameVersion, BuildInfo.Version, MelonUtils.HashCode, MelonUtils.CurrentPlatform, MelonUtils.CurrentDomain); + return FindIncompatiblities(MelonUtils.CurrentGameAttribute, Process.GetCurrentProcess().ProcessName, MelonUtils.GameVersion, BuildInfo.VersionNumber, MelonUtils.HashCode, MelonUtils.CurrentPlatform, MelonUtils.CurrentDomain); } public static void PrintIncompatibilities(Incompatibility[] incompatibilities, MelonBase melon) diff --git a/MelonLoader/Melons/MelonFolderHandler.cs b/MelonLoader/Melons/MelonFolderHandler.cs index 49db61987..44213d085 100644 --- a/MelonLoader/Melons/MelonFolderHandler.cs +++ b/MelonLoader/Melons/MelonFolderHandler.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Drawing; using System.IO; @@ -6,7 +7,32 @@ namespace MelonLoader.Melons { internal class MelonFolderHandler { - internal static void Scan(string path) where T : MelonTypeBase + private static bool firstSpacer = false; + + internal enum eScanType + { + UserLibs, + Plugins, + Mods, + } + + internal static void ScanUserLibs(string path) + { + // Get Full Directory Path + path = Path.GetFullPath(path); + + // Log Loading Message + var loadingMsg = $"Loading UserLibs from '{path}'..."; + MelonLogger.WriteSpacer(); + MelonLogger.Msg(loadingMsg); + + // Parse Folders + bool hasWroteLine = false; + List melonAssemblies = new(); + ProcessFolder(eScanType.UserLibs, path, ref hasWroteLine, ref melonAssemblies); + } + + internal static void ScanMelons(string path) where T : MelonTypeBase { // Get Full Directory Path path = Path.GetFullPath(path); @@ -17,9 +43,11 @@ internal static void Scan(string path) where T : MelonTypeBase MelonLogger.Msg(loadingMsg); // Parse Folders + Type melonType = typeof(T); + bool isMod = melonType == typeof(MelonMod); bool hasWroteLine = false; List melonAssemblies = new(); - ProcessFolder(path, ref hasWroteLine, ref melonAssemblies); + ProcessFolder(isMod ? eScanType.Mods : eScanType.Plugins, path, ref hasWroteLine, ref melonAssemblies); // Parse Queue var melons = new List(); @@ -57,120 +85,97 @@ internal static void Scan(string path) where T : MelonTypeBase // Log Melon Count var count = MelonTypeBase._registeredMelons.Count; MelonLogger.Msg($"{count} {MelonTypeBase.TypeName.MakePlural(count)} loaded."); - if (MelonHandler.firstSpacer || (typeof(T) == typeof(MelonMod))) + if (firstSpacer || (typeof(T) == typeof(MelonMod))) MelonLogger.WriteSpacer(); - MelonHandler.firstSpacer = true; + firstSpacer = true; } - private static void LoadFolder(string path, - bool addToList, + private static void ProcessFolder(eScanType scanType, + string path, ref bool hasWroteLine, - ref List melonAssemblies) where T : MelonTypeBase + ref List melonAssemblies) { - // Get DLLs in Directory - var files = Directory.GetFiles(path, "*.dll", SearchOption.TopDirectoryOnly); - foreach (var f in files) - { - // Log - if (!hasWroteLine) - { - hasWroteLine = true; - MelonLogger.WriteLine(Color.Magenta); - } + // Validate Path + if (!Directory.Exists(path)) + return; - // Load Assembly - var asm = MelonAssembly.LoadMelonAssembly(f, false); - if (asm == null) - continue; + // Scan Directories + List melonDirectories = new(); + List userLibDirectories = new(); + ScanFolder(scanType, path, ref melonDirectories, ref userLibDirectories); - // Queue Assembly for Melon Parsing - if (addToList) - melonAssemblies.Add(asm); + // Add Base Path to End of Directories List + if (scanType == eScanType.UserLibs) + userLibDirectories.Add(path); + else + melonDirectories.Add(path); + + // Add Directories to Resolver + foreach (string directory in userLibDirectories) + { + MelonUtils.AddNativeDLLDirectory(directory); + Resolver.MelonAssemblyResolver.AddSearchDirectory(directory); } - } + if (scanType != eScanType.UserLibs) + foreach (string directory in melonDirectories) + Resolver.MelonAssemblyResolver.AddSearchDirectory(directory); - private static bool IsUserLibsFolder(string dirNameLower) - => dirNameLower.StartsWith("userlibs") - || dirNameLower.EndsWith("userlibs"); + // Load UserLibs + MelonPreprocessor.LoadFolders(userLibDirectories, false, ref hasWroteLine, ref melonAssemblies); - private static bool IsDisabledFolder(string path, - out string dirNameLower) - { - string dirName = new DirectoryInfo(path).Name; - dirNameLower = dirName.ToLowerInvariant(); - return dirNameLower.StartsWith("disabled") - || dirNameLower.EndsWith("disabled") - || dirNameLower.StartsWith("old") - || dirNameLower.EndsWith("old"); + // Load Melons from Folders + if (scanType != eScanType.UserLibs) + MelonPreprocessor.LoadFolders(melonDirectories, true, ref hasWroteLine, ref melonAssemblies); } - private static void ProcessFolder(string path, - ref bool hasWroteLine, - ref List melonAssemblies) where T : MelonTypeBase + private static void ScanFolder(eScanType scanType, + string path, + ref List melonDirectories, + ref List userLibDirectories) { - // Validate Path - if (!Directory.Exists(path)) - return; - - // Add Base Path to Resolver - Resolver.MelonAssemblyResolver.AddSearchDirectory(path); - // Get Directories - var directories = Directory.GetDirectories(path, "*", SearchOption.AllDirectories); + string[] directories = Directory.GetDirectories(path, "*", SearchOption.TopDirectoryOnly); + if ((directories == null) + || (directories.Length <= 0)) + return; - // Add Directories to Resolver - if ((directories != null) && (directories.Length > 0)) + // Parse Directories + foreach (var dir in directories) { - foreach (var dir in directories) - { - // Validate Path - if (!Directory.Exists(dir)) - continue; - - // Skip Disabled Folders - if (IsDisabledFolder(dir, out string dirNameLower)) - continue; + // Validate Path + if (!Directory.Exists(dir)) + continue; - // Load Assemblies - if (IsUserLibsFolder(dirNameLower)) - MelonUtils.AddNativeDLLDirectory(dir); - Resolver.MelonAssemblyResolver.AddSearchDirectory(dir); - } + // Validate Manifest + string manifestPath = Path.Combine(dir, "manifest.json"); + if (!File.Exists(manifestPath)) + continue; - // Load UserLibs - foreach (var dir in directories) + // Check for Deeper UserLibs + string userLibsPath = Path.Combine(dir, "UserLibs"); + if (Directory.Exists(userLibsPath)) { - // Validate Path - if (!Directory.Exists(dir)) - continue; - - // Skip Disabled Folders and any folders that doesn't end with or isn't equal to UserLibs - if (IsDisabledFolder(dir, out string dirNameLower) - || !IsUserLibsFolder(dirNameLower)) - continue; - - // Load Assemblies - LoadFolder(dir, false, ref hasWroteLine, ref melonAssemblies); + userLibDirectories.Add(userLibsPath); + ScanFolder(eScanType.UserLibs, userLibsPath, ref melonDirectories, ref userLibDirectories); } - // Load Melons from Extended Folders - foreach (var dir in directories) + // Is UserLibs Scan? + if (scanType == eScanType.UserLibs) + userLibDirectories.Add(dir); // Add to Directories List + else { - // Validate Path - if (!Directory.Exists(dir)) - continue; - - // Skip Disabled Folders - if (IsDisabledFolder(dir, out _)) - continue; + // Check for Deeper Melon Folder + string melonPath = Path.Combine(dir, (scanType == eScanType.Plugins) ? "Plugins" : "Mods"); + if (Directory.Exists(melonPath)) + { + melonDirectories.Add(melonPath); + ScanFolder(scanType, melonPath, ref melonDirectories, ref userLibDirectories); + } - // Load Melons from Extended Folder - LoadFolder(dir, true, ref hasWroteLine, ref melonAssemblies); + // Add to Directories List + melonDirectories.Add(dir); } } - - // Load Melons from Base Path - LoadFolder(path, true, ref hasWroteLine, ref melonAssemblies); } } } \ No newline at end of file diff --git a/MelonLoader/Melons/MelonHandler.cs b/MelonLoader/Melons/MelonHandler.cs index 80725eaf7..8abe773fa 100644 --- a/MelonLoader/Melons/MelonHandler.cs +++ b/MelonLoader/Melons/MelonHandler.cs @@ -32,91 +32,12 @@ internal static void Setup() Directory.CreateDirectory(MelonEnvironment.ModsDirectory); } - internal static bool firstSpacer = false; - public static void LoadMelonsFromDirectory(string path) where T : MelonTypeBase - { - path = Path.GetFullPath(path); - - var loadingMsg = $"Loading {MelonTypeBase.TypeName}s from '{path}'..."; - MelonLogger.WriteSpacer(); - MelonLogger.Msg(loadingMsg); - - bool hasWroteLine = false; - - var files = Directory.GetFiles(path, "*.dll", SearchOption.TopDirectoryOnly); - var melonAssemblies = new List(); - foreach (var f in files) - { - if (!hasWroteLine) - { - hasWroteLine = true; - MelonLogger.WriteLine(Color.Magenta); - } - - var asm = MelonAssembly.LoadMelonAssembly(f, false); - if (asm == null) - continue; - - melonAssemblies.Add(asm); - } - - var melons = new List(); - foreach (var asm in melonAssemblies) - { - asm.LoadMelons(); - foreach (var m in asm.LoadedMelons) - { - if (m is T t) - { - melons.Add(t); - } - else - { - MelonLogger.Warning($"Failed to load Melon '{m.Info.Name}' from '{path}': The given Melon is a {m.MelonTypeName} and cannot be loaded as a {MelonTypeBase.TypeName}. Make sure it's in the right folder."); - continue; - } - } - } - - if (hasWroteLine) - MelonLogger.WriteSpacer(); - - MelonBase.RegisterSorted(melons); - - if (hasWroteLine) - MelonLogger.WriteLine(Color.Magenta); - - var count = MelonTypeBase._registeredMelons.Count; - MelonLogger.Msg($"{count} {MelonTypeBase.TypeName.MakePlural(count)} loaded."); - if (firstSpacer || (typeof(T) == typeof(MelonMod))) - MelonLogger.WriteSpacer(); - firstSpacer = true; - } - public static void LoadUserlibs(string path) - { - path = Path.GetFullPath(path); - - var loadingMsg = $"Loading UserLibs from '{path}'..."; - MelonLogger.WriteSpacer(); - MelonLogger.Msg(loadingMsg); - - bool hasWroteLine = false; - var files = Directory.GetFiles(path, "*.dll", SearchOption.TopDirectoryOnly); - foreach (var f in files) - { - if (!hasWroteLine) - { - hasWroteLine = true; - MelonLogger.WriteLine(Color.Magenta); - } - - MelonAssembly.LoadMelonAssembly(f, false); - } - } + => MelonFolderHandler.ScanUserLibs(path); - public static void LoadMelonFolders(string path) where T : MelonTypeBase - => MelonFolderHandler.Scan(path); + public static void LoadMelonsFromDirectory(string path) + where T : MelonTypeBase + => MelonFolderHandler.ScanMelons(path); #region Obsolete Members /// diff --git a/MelonLoader/Melons/MelonPreprocessor.cs b/MelonLoader/Melons/MelonPreprocessor.cs new file mode 100644 index 000000000..950971709 --- /dev/null +++ b/MelonLoader/Melons/MelonPreprocessor.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using Mono.Cecil; + +namespace MelonLoader.Melons +{ + internal static class MelonPreprocessor + { + internal static void LoadFolders(List directoryPaths, + bool isMelon, + ref bool hasWroteLine, + ref List melonAssemblies) + { + // Find All Assemblies + Dictionary foundAssemblies = new(); + foreach (string path in directoryPaths) + PreprocessFolder(path, isMelon, ref foundAssemblies); + + // Load from File Paths + foreach (var foundFile in foundAssemblies) + { + // Log + if (!hasWroteLine) + { + hasWroteLine = true; + MelonLogger.WriteLine(Color.Magenta); + } + + // Load Assembly + var asm = MelonAssembly.LoadMelonAssembly(foundFile.Value.Item2, false); + if (asm == null) + continue; + + // Queue Assembly for Melon Parsing + if (isMelon) + melonAssemblies.Add(asm); + } + } + + private static void PreprocessFolder(string path, + bool isMelon, + ref Dictionary foundAssemblies) + { + // Validate Path + if (!Directory.Exists(path)) + return; + + // Get DLLs in Directory + var files = Directory.GetFiles(path, "*.dll", SearchOption.TopDirectoryOnly); + foreach (var f in files) + { + // Ignore Native DLLs + if (!MelonUtils.IsManagedDLL(f)) + continue; + + // Load Definition using Cecil + AssemblyDefinition asmDef = LoadDefinition(f); + if (asmDef == null) + continue; + + // Pull Name and Version from AssemblyDefinitionName + string name = $"{asmDef.Name.Name}"; + Version version = new(asmDef.Name.Version.ToString()); + + // Dispose of Definition + asmDef.Dispose(); + + // Check for Existing Version + if (foundAssemblies.TryGetValue(name, out (Version, string) existingVersion) + && (existingVersion.Item1 >= version)) + continue; + + // Add File to List + foundAssemblies[name] = (version, f); + } + } + + private static AssemblyDefinition LoadDefinition(string path) + { + path = Path.GetFullPath(path); + + try + { + return AssemblyDefinition.ReadAssembly(path); + } + catch (Exception ex) + { + MelonLogger.Error($"Failed to load AssemblyDefinition from '{path}':\n{ex}"); + return null; + } + } + } +} diff --git a/MelonLoader/Properties/AssemblyInfo.cs b/MelonLoader/Properties/AssemblyInfo.cs deleted file mode 100644 index 3277cba2d..000000000 --- a/MelonLoader/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle(MelonLoader.BuildInfo.Description)] -[assembly: AssemblyDescription(MelonLoader.BuildInfo.Description)] -[assembly: AssemblyCompany(MelonLoader.BuildInfo.Company)] -[assembly: AssemblyProduct(MelonLoader.BuildInfo.Name)] -[assembly: AssemblyCopyright("Created by " + MelonLoader.BuildInfo.Author)] -[assembly: AssemblyTrademark(MelonLoader.BuildInfo.Company)] -[assembly: Guid("A662769A-B294-434F-83B5-176FC4795334")] -[assembly: AssemblyVersion(MelonLoader.BuildInfo.Version)] -[assembly: AssemblyFileVersion(MelonLoader.BuildInfo.Version)] -[assembly: MelonLoader.PatchShield] - -[assembly: InternalsVisibleTo("MelonLoader.NativeHost")] -[assembly: InternalsVisibleTo("Il2CppAssemblyGenerator")] -[assembly: InternalsVisibleTo("Il2CppUnityTls")] -[assembly: InternalsVisibleTo("Il2Cpp")] -[assembly: InternalsVisibleTo("MelonStartScreen")] -[assembly: InternalsVisibleTo("EOS")] \ No newline at end of file diff --git a/MelonLoader/Properties/BuildInfo.cs b/MelonLoader/Properties/BuildInfo.cs deleted file mode 100644 index c6ff6b100..000000000 --- a/MelonLoader/Properties/BuildInfo.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace MelonLoader -{ - public static class BuildInfo - { - public const string Name = "MelonLoader"; - public const string Description = "MelonLoader"; - public const string Author = "Lava Gang"; - public const string Company = "discord.gg/2Wn3N2P"; - public const string Version = "0.6.6"; - } -} \ No newline at end of file diff --git a/MelonLoader/Resolver/MelonAssemblyResolver.cs b/MelonLoader/Resolver/MelonAssemblyResolver.cs index d4062503a..1840ae231 100644 --- a/MelonLoader/Resolver/MelonAssemblyResolver.cs +++ b/MelonLoader/Resolver/MelonAssemblyResolver.cs @@ -19,62 +19,83 @@ internal static void Setup() return; // Setup Search Directories - string[] searchdirlist = - { + AddSearchDirectories( MelonEnvironment.UserLibsDirectory, MelonEnvironment.PluginsDirectory, MelonEnvironment.ModsDirectory, - MelonEnvironment.MelonBaseDirectory, - MelonEnvironment.GameRootDirectory, + (MelonUtils.IsGameIl2Cpp() + ? MelonEnvironment.Il2CppAssembliesDirectory + : MelonEnvironment.UnityGameManagedDirectory), MelonEnvironment.OurRuntimeDirectory, - MelonEnvironment.Il2CppAssembliesDirectory, - MelonEnvironment.UnityGameManagedDirectory, - }; - foreach (string path in searchdirlist) - AddSearchDirectory(path); - - ForceResolveRuntime("Mono.Cecil.dll"); - ForceResolveRuntime("MonoMod.exe"); - ForceResolveRuntime("MonoMod.Utils.dll"); - ForceResolveRuntime("MonoMod.RuntimeDetour.dll"); + MelonEnvironment.GameRootDirectory); // Setup Redirections - string[] assembly_list = - { - "MelonLoader", - "MelonLoader.ModHandler", - }; - Assembly base_assembly = typeof(MelonAssemblyResolver).Assembly; - foreach (string assemblyName in assembly_list) - GetAssemblyResolveInfo(assemblyName).Override = base_assembly; + OverrideBaseAssembly(); + + // Resolve Default Runtime Assemblies + ForceResolveRuntime( + "Mono.Cecil.dll", + "MonoMod.exe", + "MonoMod.Utils.dll", + "MonoMod.RuntimeDetour.dll"); MelonDebug.Msg("[MelonAssemblyResolver] Setup Successful!"); } - private static void ForceResolveRuntime(string fileName) + private static void OverrideBaseAssembly() { - string filePath = Path.Combine(MelonEnvironment.OurRuntimeDirectory, fileName); - if (!File.Exists(filePath)) - return; + Assembly base_assembly = typeof(MelonAssemblyResolver).Assembly; + GetAssemblyResolveInfo(base_assembly.GetName().Name).Override = base_assembly; + GetAssemblyResolveInfo("MelonLoader").Override = base_assembly; + GetAssemblyResolveInfo("MelonLoader.ModHandler").Override = base_assembly; + } - Assembly assembly = null; - try + private static void ForceResolveRuntime(params string[] fileNames) + { + foreach (string fileName in fileNames) { + string filePath = Path.Combine(MelonEnvironment.OurRuntimeDirectory, fileName); + if (!File.Exists(filePath)) + return; + + Assembly assembly = null; + try + { #if NET6_0_OR_GREATER - assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(filePath); + assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(filePath); #else assembly = Assembly.LoadFrom(filePath); #endif - } - catch { assembly = null; } + } + catch { assembly = null; } - if (assembly == null) - return; + if (assembly == null) + return; - GetAssemblyResolveInfo(Path.GetFileNameWithoutExtension(fileName)).Override = assembly; + GetAssemblyResolveInfo(Path.GetFileNameWithoutExtension(fileName)).Override = assembly; + } } // Search Directories + + public static void AddSearchDirectories(params string[] directories) + { + foreach (string directory in directories) + AddSearchDirectory(directory); + } + + public static void AddSearchDirectories(int priority, params string[] directories) + { + foreach (string directory in directories) + AddSearchDirectory(directory, priority); + } + + public static void AddSearchDirectories(params (string, int)[] directories) + { + foreach (var pair in directories) + AddSearchDirectory(pair.Item1, pair.Item2); + } + public static void AddSearchDirectory(string path, int priority = 0) => SearchDirectoryManager.Add(path, priority); public static void RemoveSearchDirectory(string path) diff --git a/MelonLoader/Semver/SemVersion.cs b/MelonLoader/Semver/SemVersion.cs index 1b7aec5a2..72bdc9c90 100644 --- a/MelonLoader/Semver/SemVersion.cs +++ b/MelonLoader/Semver/SemVersion.cs @@ -337,8 +337,7 @@ public int CompareTo(SemVersion other) var r = CompareByPrecedence(other); if (r != 0) return r; - // If other is null, CompareByPrecedence() returns 1 - return CompareComponent(Build, other.Build); + return CompareComponent(Prerelease, other.Prerelease, true); } /// diff --git a/MelonLoader/Utils/MelonLogger.cs b/MelonLoader/Utils/MelonLogger.cs index 117a69372..365dc5fe6 100644 --- a/MelonLoader/Utils/MelonLogger.cs +++ b/MelonLoader/Utils/MelonLogger.cs @@ -55,7 +55,12 @@ internal static void Setup() break; else { - File.Delete(pair.Item1); + // This is cursed but better than crashing + try + { + File.Delete(pair.Item1); + } + catch { } fileCount--; } } diff --git a/MelonProxy/src/core.rs b/MelonProxy/src/core.rs index 8f978b0fd..c80f17788 100644 --- a/MelonProxy/src/core.rs +++ b/MelonProxy/src/core.rs @@ -59,9 +59,11 @@ pub fn init() -> Result<(), Box> { return Ok(()); } - //fix dobby_rs link - let dobby_path = files::get_dobby_dir(base_dir.clone(), game_dir)?; - add_dll_directory(dobby_path); + if cfg!(target_os = "windows") { + //fix dobby_rs link + let dobby_path = files::get_dobby_dir(base_dir.clone(), game_dir)?; + add_dll_directory(dobby_path); + } let bootstrap_path = files::get_bootstrap_path(&base_dir)?;