Skip to content

Commit

Permalink
Update to ML 0.3.0+, change CL settings
Browse files Browse the repository at this point in the history
  • Loading branch information
knah committed Jul 25, 2021
1 parent 44b053b commit db6c551
Show file tree
Hide file tree
Showing 12 changed files with 149 additions and 132 deletions.
2 changes: 1 addition & 1 deletion CoreLimiter/CoreLimiter.csproj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
<AssemblyVersion>1.0.1.0</AssemblyVersion>
<AssemblyVersion>1.0.2.0</AssemblyVersion>
</PropertyGroup>
</Project>
66 changes: 44 additions & 22 deletions CoreLimiter/CoreLimiterMod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,49 +4,71 @@
using CoreLimiter;
using MelonLoader;

[assembly:MelonInfo(typeof(CoreLimiterMod), "Core Limiter", "1.0.1", "knah", "https://github.com/knah/ML-UniversalMods")]
[assembly:MelonInfo(typeof(CoreLimiterMod), "Core Limiter", "1.0.2", "knah", "https://github.com/knah/ML-UniversalMods")]
[assembly:MelonGame]

namespace CoreLimiter
{
public class CoreLimiterMod : MelonMod
{
private const string CoreLimiterPrefCategory = "CoreLimiter";
private const string MaxCoresPref = "MaxCores";
private const string SkipHyperThreadsPref = "SkipHyperThreads";

public override void OnApplicationStart()
{
MelonPrefs.RegisterCategory(CoreLimiterPrefCategory, "Core Limiter");
MelonPrefs.RegisterInt(CoreLimiterPrefCategory, MaxCoresPref, 4, "Maximum cores");
MelonPrefs.RegisterBool(CoreLimiterPrefCategory, SkipHyperThreadsPref, true, "Don't use both threads of a core");
var category = MelonPreferences.CreateCategory("CoreLimiter", "Core Limiter");

var maxCores = category.CreateEntry("MaxCores", Math.Max(1, Environment.ProcessorCount / 4), "Maximum cores");
var useBothHyperthreads = category.CreateEntry("UseBothHyperthreads", true, "Use both hyperthreads");
var useFirstCores = category.CreateEntry("UseFirstCores", false, "Use first X cores (instead of last)");
var specificCores = category.CreateEntry("SpecificCores", "", "Use specific cores (comma separated, i.e. '0,2,4,6'; overrides other settings)");

MelonLogger.Log($"[CoreLimiter] Have {Environment.ProcessorCount} processor cores");
MelonLogger.Msg($"Have {Environment.ProcessorCount} processor cores");

ApplyAffinity();
}
void UpdateState() => ApplyAffinity(maxCores.Value, useBothHyperthreads.Value, useFirstCores.Value, specificCores.Value);

public override void OnModSettingsApplied()
{
ApplyAffinity();
maxCores.OnValueChangedUntyped += UpdateState;
useBothHyperthreads.OnValueChangedUntyped += UpdateState;
useFirstCores.OnValueChangedUntyped += UpdateState;
specificCores.OnValueChangedUntyped += UpdateState;

UpdateState();
}

private static void ApplyAffinity()
private static long GetMaskAuto(int coreCount, bool useHyperthreads, bool useFirstCores)
{
var processorCount = Environment.ProcessorCount;
long mask = 0;

var targetNumCores = MelonPrefs.GetInt(CoreLimiterPrefCategory, MaxCoresPref);
var targetBit = processorCount - 1;
var bitStep = MelonPrefs.GetBool(CoreLimiterPrefCategory, SkipHyperThreadsPref) ? 2 : 1;
for (var i = 0; i < targetNumCores && targetBit > 0; i++)
var startBit = useFirstCores ? 0 : processorCount - coreCount * 2;
var endBit = useFirstCores ? coreCount * 2 : processorCount;
for (var i = startBit; i < endBit; i += 2)
{
mask |= 1L << targetBit;
targetBit -= bitStep;
mask |= 1L << i;
if (useHyperthreads)
mask |= 1L << (i + 1);
}

return mask;
}

private static long GetMaskManual(string input)
{
long mask = 0;
foreach (var s in input.Split(','))
{
if (int.TryParse(s, out var i))
mask |= 1L << i;
}

return mask;
}

private static void ApplyAffinity(int coreCount, bool useHyperthreads, bool useFirstCores, string specificCores)
{
var mask = string.IsNullOrEmpty(specificCores) ? GetMaskAuto(coreCount, useHyperthreads, useFirstCores) : GetMaskManual(specificCores);

if (mask == 0) mask = 1; // don't set empty masks

var process = Process.GetCurrentProcess().Handle;
MelonLogger.Log($"[CoreLimiter] Assigning affinity mask: {mask}");
MelonLogger.Msg($"Assigning affinity mask: {mask}");
SetProcessAffinityMask(process, new IntPtr(mask));
}

Expand Down
2 changes: 1 addition & 1 deletion HWIDPatch/HWIDPatch.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>latest</LangVersion>
<UseAltLibs>true</UseAltLibs>
<Version>1.0.1.0</Version>
<Version>1.0.2.0</Version>
</PropertyGroup>
</Project>
35 changes: 15 additions & 20 deletions HWIDPatch/HWIDPatchMod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,32 @@
using UnhollowerBaseLib;
using UnityEngine;

[assembly:MelonInfo(typeof(HWIDPatchMod), "HWIDPatch", "1.0.1", "knah", "https://github.com/knah/ML-UniversalMods")]
[assembly:MelonInfo(typeof(HwidPatchMod), "HWIDPatch", "1.0.2", "knah", "https://github.com/knah/ML-UniversalMods")]
[assembly:MelonGame]

namespace HWIDPatch
{
public class HWIDPatchMod : MelonMod
public class HwidPatchMod : MelonMod
{
private static Il2CppSystem.Object ourGeneratedHwidString;

public override unsafe void OnApplicationStart()
{
try
{
var settingsCategory = "HWIDPatch";
MelonPrefs.RegisterCategory(settingsCategory, "HWID Patch");
MelonPrefs.RegisterString(settingsCategory, "HWID", "", hideFromList: true);
var category = MelonPreferences.CreateCategory("HWIDPatch", "HWID Patch");
var hwidEntry = category.CreateEntry("HWID", "", is_hidden: true);

var newId = MelonPrefs.GetString(settingsCategory, "HWID");
var newId = hwidEntry.Value;
if (newId.Length != SystemInfo.deviceUniqueIdentifier.Length)
{
var random = new System.Random(Environment.TickCount);
var bytes = new byte[SystemInfo.deviceUniqueIdentifier.Length / 2];
random.NextBytes(bytes);
newId = string.Join("", bytes.Select(it => it.ToString("x2")));
MelonPrefs.SetString(settingsCategory, "HWID", newId);
MelonLogger.Msg("Generated and saved a new HWID");
hwidEntry.Value = newId;
category.SaveToFile(false);
}

ourGeneratedHwidString = new Il2CppSystem.Object(IL2CPP.ManagedStringToIl2Cpp(newId));
Expand All @@ -39,30 +40,24 @@ public override unsafe void OnApplicationStart()
var icallAddress = IL2CPP.il2cpp_resolve_icall(icallName);
if (icallAddress == IntPtr.Zero)
{
MelonLogger.LogError("Can't resolve the icall, not patching");
MelonLogger.Error("Can't resolve the icall, not patching");
return;
}

CompatHook((IntPtr) (&icallAddress),
typeof(HWIDPatchMod).GetMethod(nameof(GetDeviceIdPatch),
MelonUtils.NativeHookAttach((IntPtr) (&icallAddress),
typeof(HwidPatchMod).GetMethod(nameof(GetDeviceIdPatch),
BindingFlags.Static | BindingFlags.NonPublic)!.MethodHandle.GetFunctionPointer());

MelonLogger.Log("Patched HWID; below two should match:");
MelonLogger.Log($"Current: {SystemInfo.deviceUniqueIdentifier}");
MelonLogger.Log($"Target: {newId}");
MelonLogger.Msg("Patched HWID; below two should match:");
MelonLogger.Msg($"Current: {SystemInfo.deviceUniqueIdentifier}");
MelonLogger.Msg($"Target: {newId}");
}
catch (Exception ex)
{
MelonLogger.LogError(ex.ToString());
MelonLogger.Error(ex.ToString());
}
}

private static IntPtr GetDeviceIdPatch() => ourGeneratedHwidString.Pointer;

private static void CompatHook(IntPtr first, IntPtr second)
{
typeof(Imports).GetMethod("Hook", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)!
.Invoke(null, new object[] {first, second});
}
}
}
2 changes: 1 addition & 1 deletion LocalPlayerPrefs/LocalPlayerPrefs.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Version>1.0.1.0</Version>
<Version>1.0.2.0</Version>
</PropertyGroup>

</Project>
22 changes: 11 additions & 11 deletions LocalPlayerPrefs/LocalPlayerPrefsMod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
using UnhollowerBaseLib;
using UnityEngine;

[assembly:MelonInfo(typeof(LocalPlayerPrefsMod), "LocalPlayerPrefs", "1.0.1", "knah", "https://github.com/knah/ML-UniversalMods")]
[assembly:MelonInfo(typeof(LocalPlayerPrefsMod), "LocalPlayerPrefs", "1.0.2", "knah", "https://github.com/knah/ML-UniversalMods")]
[assembly:MelonGame]

namespace LocalPlayerPrefs
Expand All @@ -22,7 +22,7 @@ public class LocalPlayerPrefsMod : MelonMod
private readonly List<Delegate> myPinnedDelegates = new List<Delegate>();
private readonly ConcurrentDictionary<string, object> myPrefs = new ConcurrentDictionary<string, object>();

private bool myHadChanges = false;
private bool myHadChanges;

[UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate bool TrySetFloatDelegate(IntPtr keyPtr, float value);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate bool TrySetIntDelegate(IntPtr keyPtr, int value);
Expand All @@ -45,12 +45,12 @@ public override void OnApplicationStart()
{
var dict = (ProxyObject) JSON.Load(File.ReadAllText(FileName));
foreach (var keyValuePair in dict) myPrefs[keyValuePair.Key] = ToObject(keyValuePair.Key, keyValuePair.Value);
MelonLogger.Log($"Loaded {dict.Count} prefs from PlayerPrefs.json");
MelonLogger.Msg($"Loaded {dict.Count} prefs from PlayerPrefs.json");
}
}
catch (Exception ex)
{
MelonLogger.LogError($"Unable to load PlayerPrefs.json: {ex}");
MelonLogger.Error($"Unable to load PlayerPrefs.json: {ex}");
}

HookICall<TrySetFloatDelegate>(nameof(PlayerPrefs.TrySetFloat), TrySetFloat);
Expand All @@ -73,7 +73,7 @@ private object ToObject(string key, Variant value)
if (value is null) return null;

if (value is ProxyString proxyString)
return proxyString.ToString();
return proxyString.ToString(CultureInfo.InvariantCulture);

if (value is ProxyNumber number)
{
Expand All @@ -87,16 +87,16 @@ private object ToObject(string key, Variant value)
throw new ArgumentException($"Unknown value in prefs: {key} = {value?.GetType()} / {value}");
}

public override void OnLevelWasLoaded(int level)
public override void OnSceneWasLoaded(int buildIndex, string name)
{
Save();
MelonLogger.Log("Saved PlayerPrefs.json on level load");
MelonLogger.Msg("Saved PlayerPrefs.json on level load");
}

public override void OnApplicationQuit()
{
Save();
MelonLogger.Log("Saved PlayerPrefs.json on exit");
MelonLogger.Msg("Saved PlayerPrefs.json on exit");
}

private bool HasKey(IntPtr keyPtr)
Expand Down Expand Up @@ -133,7 +133,7 @@ private void Save()
}
catch (IOException ex)
{
MelonLogger.LogWarning($"Exception while saving PlayerPrefs: {ex}");
MelonLogger.Warning($"Exception while saving PlayerPrefs: {ex}");
}
}

Expand Down Expand Up @@ -215,12 +215,12 @@ private unsafe void HookICall<T>(string name, T target) where T: Delegate
var originalPointer = IL2CPP.il2cpp_resolve_icall("UnityEngine.PlayerPrefs::" + name);
if (originalPointer == IntPtr.Zero)
{
MelonLogger.LogWarning($"ICall {name} was not found, not patching");
MelonLogger.Warning($"ICall {name} was not found, not patching");
return;
}

myPinnedDelegates.Add(target);
Imports.Hook((IntPtr) (&originalPointer), Marshal.GetFunctionPointerForDelegate(target));
MelonUtils.NativeHookAttach((IntPtr) (&originalPointer), Marshal.GetFunctionPointerForDelegate(target));
}
}
}
2 changes: 1 addition & 1 deletion NoSteamAtAll/NoSteamAtAll.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Version>1.0.2</Version>
<Version>1.0.3</Version>
</PropertyGroup>

</Project>
16 changes: 10 additions & 6 deletions NoSteamAtAll/NoSteamAtAllMod.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using Harmony;
using HarmonyLib;
using MelonLoader;
using NoSteamAtAll;

[assembly:MelonGame]
[assembly:MelonInfo(typeof(NoSteamAtAllMod), "No Steam. At all.", "1.0.2", "knah")]
[assembly:MelonInfo(typeof(NoSteamAtAllMod), "No Steam. At all.", "1.0.3", "knah")]

namespace NoSteamAtAll
{
Expand All @@ -19,10 +20,13 @@ public class NoSteamAtAllMod : MelonMod

public override void OnApplicationStart()
{
var library = LoadLibrary(MelonUtils.GetGameDataDirectory() + "\\Plugins\\steam_api64.dll");
var path = MelonUtils.GetGameDataDirectory() + "\\Plugins\\steam_api64.dll";
if (!File.Exists(path)) path = MelonUtils.GetGameDataDirectory() + "\\Plugins\\x86_64\\steam_api64.dll";
if (!File.Exists(path)) path = MelonUtils.GetGameDataDirectory() + "\\Plugins\\x86\\steam_api64.dll";
var library = LoadLibrary(path);
if (library == IntPtr.Zero)
{
MelonLogger.LogError("Library load failed");
MelonLogger.Error($"Library load failed; used path: {path}");
return;
}
var names = new[]
Expand All @@ -43,10 +47,10 @@ public override void OnApplicationStart()
var address = GetProcAddress(library, name);
if (address == IntPtr.Zero)
{
MelonLogger.LogError($"Procedure {name} not found");
MelonLogger.Error($"Procedure {name} not found");
continue;
}
Imports.Hook((IntPtr) (&address),
MelonUtils.NativeHookAttach((IntPtr) (&address),
AccessTools.Method(typeof(NoSteamAtAllMod), nameof(InitFail)).MethodHandle
.GetFunctionPointer());
}
Expand Down
4 changes: 3 additions & 1 deletion ReleaseChangelog.md
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
Initial release in the new repository
Changes:
* All mods: updated to MelonLoader 0.3.0+
* CoreLimiter: changed settings to make a bit more sense
Loading

0 comments on commit db6c551

Please sign in to comment.