Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 65 additions & 5 deletions Dependencies/Il2CppAssemblyGenerator/Core.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
using System.IO;
using System.Net.Http;
using MelonLoader.Il2CppAssemblyGenerator.Packages;
using MelonLoader.Il2CppAssemblyGenerator.Packages;
using MelonLoader.Il2CppAssemblyGenerator.Packages.Models;
using MelonLoader.Modules;
using MelonLoader.Utils;
using System.IO;
using System.Linq;
using System.Net.Http;
#if ANDROID
using MelonLoader.Java;
#endif

namespace MelonLoader.Il2CppAssemblyGenerator
{
Expand Down Expand Up @@ -31,7 +35,18 @@ public override void OnInitialize()
{
Logger = LoggerInstance;

#if ANDROID
// Android has problems with SSL, which prevents any connections. This is the workaround.
HttpClientHandler handler = new()
{
ClientCertificateOptions = ClientCertificateOption.Manual,
ServerCertificateCustomValidationCallback = (_, _, _, _) => true
};

webClient = new(handler);
#else
webClient = new();
#endif
webClient.DefaultRequestHeaders.Add("User-Agent", $"{Properties.BuildInfo.Name} v{Properties.BuildInfo.Version}");

AssemblyGenerationNeeded = LoaderConfig.Current.UnityEngine.ForceRegeneration;
Expand All @@ -46,6 +61,8 @@ public override void OnInitialize()

#if OSX
GameAssemblyPath = Path.Combine(MelonEnvironment.GameExecutablePath, "Contents", "Frameworks", gameAssemblyName);
#elif ANDROID
GameAssemblyPath = GetLibIl2CppPath();
#else
GameAssemblyPath = Path.Combine(MelonEnvironment.GameRootDirectory, gameAssemblyName);
#endif
Expand All @@ -60,12 +77,17 @@ private static int Run()
if (!LoaderConfig.Current.UnityEngine.ForceOfflineGeneration)
RemoteAPI.Contact();

Cpp2IL cpp2IL_netcore = new Cpp2IL();
Packages.Cpp2IL cpp2IL_netcore = new();
if (MelonUtils.IsWindows
&& (cpp2IL_netcore.VersionSem < Cpp2IL.NetCoreMinVersion))
&& (cpp2IL_netcore.VersionSem < Packages.Cpp2IL.NetCoreMinVersion))
cpp2il = new Cpp2IL_NetFramework();
else
cpp2il = cpp2IL_netcore;

#if ANDROID
cpp2il = new Cpp2IL_Android();
#endif

cpp2il_scrs = new Cpp2IL_StrippedCodeRegSupport(cpp2il);

il2cppinterop = new Packages.Il2CppInterop();
Expand Down Expand Up @@ -133,6 +155,44 @@ private static int Run()
return 0;
}

#if ANDROID
private string GetLibIl2CppPath()
{
// get player activity
using JClass unityClass = JNI.FindClass("com/unity3d/player/UnityPlayer");
JFieldID activityFieldId = JNI.GetStaticFieldID(unityClass, "currentActivity", "Landroid/app/Activity;");
using JObject currentActivityObj = JNI.GetStaticObjectField<JObject>(unityClass, activityFieldId);

// get applicationinfo
using JClass activityType = JNI.GetObjectClass(currentActivityObj);
JMethodID getAppInfoId = JNI.GetMethodID(activityType, "getApplicationInfo", "()Landroid/content/pm/ApplicationInfo;");
using JObject applicationInfoObj = JNI.CallObjectMethod<JObject>(currentActivityObj, getAppInfoId);

// get nativelibrarydir
JFieldID filesFieldId = JNI.GetFieldID(JNI.GetObjectClass(applicationInfoObj), "nativeLibraryDir", "Ljava/lang/String;");
using JString pathJString = JNI.GetObjectField<JString>(applicationInfoObj, filesFieldId);

if (pathJString == null || !pathJString.Valid())
{
MelonLogger.Msg("Unable to get libil2cpp path.");
if (JNI.ExceptionCheck())
{
var ex = JNI.ExceptionOccurred();
JNI.ExceptionClear();
MelonLogger.Msg(ex.GetMessage());
}

return "";
}

string nativePath = JNI.GetJStringString(pathJString);
string[] directoryLibs = Directory.GetFiles(nativePath, "*.so");

string libil2Path = directoryLibs.FirstOrDefault(s => s.EndsWith("libil2cpp.so"));
return libil2Path;
}
#endif

private static void OldFiles_Cleanup()
{
if (Config.Values.OldFiles.Count <= 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,15 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\MelonLoader\MelonLoader.csproj" Private="false" />
<PackageReference Include="AssetRipper.Primitives" Version="3.1.4" ExcludeAssets="Runtime" />
<PackageReference Include="AssetRipper.Primitives" Version="3.1.6" ExcludeAssets="Runtime" />
<PackageReference Include="Iced" Version="1.21.0" ExcludeAssets="Runtime" />
<PackageReference Include="Il2CppInterop.Generator" Version="$(Il2CppInteropVersion)" ExcludeAssets="Runtime" />
<PackageReference Include="Il2CppInterop.Common" Version="$(Il2CppInteropVersion)" ExcludeAssets="Runtime" />
<PackageReference Include="Il2CppInterop.Runtime" Version="$(Il2CppInteropVersion)" ExcludeAssets="Runtime" />
<PackageReference Include="Mono.Cecil" Version="0.11.6" ExcludeAssets="Runtime" />
</ItemGroup>
<ItemGroup Condition="'$(DefineConstants)' != '' and $(DefineConstants.Contains('ANDROID'))">
<PackageReference Include="Samboy063.Cpp2IL.Core" Version="2022.1.0-development.1374+d526068 " />
<PackageReference Include="Samboy063.LibCpp2IL" Version="2022.1.0-development.1374+d526068 " />
</ItemGroup>
</Project>
137 changes: 137 additions & 0 deletions Dependencies/Il2CppAssemblyGenerator/Packages/Cpp2IL_Android.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
#if ANDROID

using AssetRipper.Primitives;
using Cpp2IL.Core;
using Cpp2IL.Core.Api;
using Cpp2IL.Core.Extensions;
using Cpp2IL.Core.Logging;
using LibCpp2IL.Wasm;
using MelonLoader.InternalUtils;
using MelonLoader.Utils;
using System;
using System.IO;

namespace MelonLoader.Il2CppAssemblyGenerator.Packages
{
// Using a direct implementation of Cpp2IL as there isn't any good way of running the executable to my knowledge
internal class Cpp2IL_Android : Models.ExecutablePackage
{
internal Cpp2IL_Android()
{
Version = "2022.1.0-pre-release.20";

Name = nameof(Cpp2IL);
Destination = Path.Combine(Core.BasePath, Name);
OutputFolder = Path.Combine(Destination, "cpp2il_out");
}

internal override bool ShouldSetup()
=> string.IsNullOrEmpty(Config.Values.DumperVersion)
|| !Config.Values.DumperVersion.Equals(Version);

internal override void Cleanup() { }

internal override void Save()
=> Save(ref Config.Values.DumperVersion);

internal override bool Execute()
{
Logger.InfoLog += (l, s) => Core.Logger.Msg($"[{s}] {l.TrimEnd('\n')}");
Logger.WarningLog += (l, s) => Core.Logger.Warning($"[{s}] {l.TrimEnd('\n')}");
Logger.ErrorLog += (l, s) => Core.Logger.Error($"[{s}] {l.TrimEnd('\n')}");
Logger.VerboseLog += (l, s) => Core.Logger.Msg($"[{s}] {l.TrimEnd('\n')}");

byte[] mdData = APKAssetManager.GetAssetBytes("bin/Data/Managed/Metadata/global-metadata.dat");
string mdPath = Path.Combine(Core.BasePath, "global-metadata.dat");
File.WriteAllBytes(mdPath, mdData);

Cpp2IlApi.Init();
Cpp2IlApi.ConfigureLib(false);
var result = new Cpp2IlRuntimeArgs()
{
PathToAssembly = Core.GameAssemblyPath,
PathToMetadata = mdPath,
UnityVersion = UnityVersion.Parse(UnityInformationHandler.EngineVersion.ToString()), // they use different versions of the same library but under different names, thanks ds5678
Valid = true,
OutputRootDirectory = OutputFolder,
OutputFormat = OutputFormatRegistry.GetFormat("dummydll"),
ProcessingLayersToRun = [ProcessingLayerRegistry.GetById("attributeinjector")],
};

return RunCpp2IL(result);
}

// mostly copied from https://github.com/SamboyCoding/Cpp2IL/blob/development/Cpp2IL/Program.cs
private bool RunCpp2IL(Cpp2IlRuntimeArgs runtimeArgs)
{
var executionStart = DateTime.Now;

runtimeArgs.OutputFormat?.OnOutputFormatSelected();

WasmFile.RemappedDynCallFunctions = null;

Cpp2IlApi.InitializeLibCpp2Il(runtimeArgs.PathToAssembly, runtimeArgs.PathToMetadata, runtimeArgs.UnityVersion);

foreach (var (key, value) in runtimeArgs.ProcessingLayerConfigurationOptions)
Cpp2IlApi.CurrentAppContext.PutExtraData(key, value);

//Pre-process processing layers, allowing them to stop others from running
Core.Logger.Msg("Pre-processing processing layers...");
var layers = runtimeArgs.ProcessingLayersToRun.Clone();
RunProcessingLayers(runtimeArgs, processingLayer => processingLayer.PreProcess(Cpp2IlApi.CurrentAppContext, layers));
runtimeArgs.ProcessingLayersToRun = layers;

//Run processing layers
Core.Logger.Msg("Invoking processing layers...");
RunProcessingLayers(runtimeArgs, processingLayer => processingLayer.Process(Cpp2IlApi.CurrentAppContext));

var outputStart = DateTime.Now;

if (runtimeArgs.OutputFormat != null)
{
Core.Logger.Msg($"Outputting as {runtimeArgs.OutputFormat.OutputFormatName} to {runtimeArgs.OutputRootDirectory}...");
runtimeArgs.OutputFormat.DoOutput(Cpp2IlApi.CurrentAppContext, runtimeArgs.OutputRootDirectory);
Core.Logger.Msg($"Finished outputting in {(DateTime.Now - outputStart).TotalMilliseconds}ms");
}
else
{
Core.Logger.Warning("No output format requested, so not outputting anything. The il2cpp game loaded properly though! (Hint: You probably want to specify an output format, try --output-as)");
}

Cpp2IlPluginManager.CallOnFinish();

File.Delete(runtimeArgs.PathToMetadata); // because we extracted it from the apk's assets folder; only purpose was this

Core.Logger.Msg($"Done. Total execution time: {(DateTime.Now - executionStart).TotalMilliseconds}ms");
return true;
}

private static void RunProcessingLayers(Cpp2IlRuntimeArgs runtimeArgs, Action<Cpp2IlProcessingLayer> run)
{
foreach (var processingLayer in runtimeArgs.ProcessingLayersToRun)
{
var processorStart = DateTime.Now;

Core.Logger.Msg($" {processingLayer.Name}...");

#if !DEBUG
try
{
#endif
run(processingLayer);
#if !DEBUG
}
catch (Exception e)
{
Logger.Error($"Processing layer {processingLayer.Id} threw an exception: {e}");
Environment.Exit(1);
}
#endif

Core.Logger.Msg($" {processingLayer.Name} finished in {(DateTime.Now - processorStart).TotalMilliseconds}ms");
}
}
}
}

#endif
1 change: 0 additions & 1 deletion Dependencies/SupportModules/Il2Cpp/Il2Cpp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
<DebugType>embedded</DebugType>
<DefineConstants>SM_Il2Cpp</DefineConstants>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<RestoreAdditionalProjectSources>https://nuget.bepinex.dev/v3/index.json</RestoreAdditionalProjectSources>
<CETCompat>false</CETCompat>
</PropertyGroup>
<ItemGroup>
Expand Down
19 changes: 18 additions & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<PropertyGroup>
<Version>0.7.2</Version>
<Il2CppInteropVersion>1.5.0-ci.625</Il2CppInteropVersion>
<Il2CppInteropAndroidVersion>1.5.0-ci.5-arm64</Il2CppInteropAndroidVersion>

<Authors>Lava Gang</Authors>
<Company>discord.gg/2Wn3N2P</Company>
Expand All @@ -13,6 +14,9 @@
<Platforms>x86;x64</Platforms>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>

<!-- Workaround for `dotnet build` blocking the setting of RuntimeIdentifier -->
<RuntimeIdentifier Condition="'$(ForcedRID)' != ''">$(ForcedRID)</RuntimeIdentifier>
</PropertyGroup>

<PropertyGroup Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux)))' == 'true'">
Expand All @@ -24,6 +28,18 @@
<LibExt>.a</LibExt>
</PropertyGroup>

<PropertyGroup Condition="'$(RuntimeIdentifier.StartsWith(`linux-bionic`))' == 'true'">
<RuntimeIdentifiers>linux-bionic-arm64</RuntimeIdentifiers>
<RuntimeIdentifier>linux-bionic-arm64</RuntimeIdentifier>
<PlatformTarget>arm64</PlatformTarget>
<DefineConstants>$(DefineConstants);ANDROID</DefineConstants>
<LibPrefix>lib</LibPrefix>
<LibExt>.a</LibExt>

<!-- Overriding the Interop version here as a clean way tox override dependencies in all of the projects -->
<Il2CppInteropVersion>$(Il2CppInteropAndroidVersion)</Il2CppInteropVersion>
</PropertyGroup>

<PropertyGroup Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::OSX)))' == 'true'">
<!-- TODO: split x64 and arm64 -->
<RuntimeIdentifiers>osx-x64</RuntimeIdentifiers>
Expand All @@ -34,7 +50,8 @@
<LibExt>.a</LibExt>
</PropertyGroup>

<PropertyGroup Condition="'$([MSBuild]::IsOSUnixLike())' == 'false'">
<!-- The second condition is required for cross-compiling Android to prevent issues -->
<PropertyGroup Condition="'$([MSBuild]::IsOSUnixLike())' == 'false' and '$(RuntimeIdentifier)' == ''">
<RuntimeIdentifiers>win-x64;win-x86</RuntimeIdentifiers>
<RuntimeIdentifier>win-$(Platform)</RuntimeIdentifier>
<DefineConstants>$(DefineConstants);WINDOWS</DefineConstants>
Expand Down
Loading
Loading