diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index c1982ea0..fbdedbba 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -42,6 +42,8 @@ jobs:
copy libs/BepInEx.cfg Release/BepInEx/config/BepInEx.cfg
copy PathfinderPatcher/bin/Release/PathfinderPatcher.exe Release/PathfinderPatcher.exe
copy libs/Mono.Cecil.dll Release/Mono.Cecil.dll
+ copy Linux/intercept.so Release/intercept.so
+ copy Linux/StartPathfinder.sh Release/StartPathfinder.sh
- name: Create Release ZIP
uses: TheDoctor0/zip-release@0.6.0
diff --git a/BepInEx.Hacknet/BepInEx.Hacknet.csproj b/BepInEx.Hacknet/BepInEx.Hacknet.csproj
index 4843374b..650e1da6 100644
--- a/BepInEx.Hacknet/BepInEx.Hacknet.csproj
+++ b/BepInEx.Hacknet/BepInEx.Hacknet.csproj
@@ -9,7 +9,7 @@
Properties
BepInEx.Hacknet
BepInEx.Hacknet
- v4.0
+ v4.5
512
true
@@ -35,18 +35,17 @@
false
-
+
..\libs\0Harmony.dll
-
+
..\libs\BepInEx.Core.dll
-
- False
+
..\libs\FNA.dll
False
-
+
..\libs\HacknetPathfinder.exe
False
@@ -62,20 +61,19 @@
..\libs\Mono.Cecil.Rocks.dll
-
+
..\libs\MonoMod.RuntimeDetour.dll
-
+
..\libs\MonoMod.Utils.dll
-
- ..\libs\SemVer.dll
+
+ ..\libs\SemanticVersioning.dll
-
diff --git a/BepInEx.Hacknet/HacknetChainloader.cs b/BepInEx.Hacknet/HacknetChainloader.cs
index 7ebf33d0..5b20cfe4 100644
--- a/BepInEx.Hacknet/HacknetChainloader.cs
+++ b/BepInEx.Hacknet/HacknetChainloader.cs
@@ -11,6 +11,7 @@
using HarmonyLib;
using Microsoft.Xna.Framework;
using Mono.Cecil;
+using Mono.Cecil.Cil;
using MonoMod.Cil;
using HN = global::Hacknet;
@@ -138,13 +139,27 @@ internal static bool LoadTempPluginsPrefix(ExtensionInfo info)
[HarmonyPatch(typeof(HN.OS), nameof(HN.OS.quitGame))]
internal static void UnloadOnOSQuitPostfix() => HacknetChainloader.Instance.UnloadTemps();
- // I would hook Hacknet.Screens.DrawExtensionInfoDetail instead, but for some reason that method is cursed, so I look here instead
- [HarmonyPostfix]
- [HarmonyPatch(typeof(Button), nameof(Button.doButton), new Type[] { typeof(int), typeof(int), typeof(int), typeof(int), typeof(int), typeof(string), typeof(Color?) })]
- internal static void OnBackButtonPressPostfix(int myID, bool __result)
+ [HarmonyILManipulator]
+ [HarmonyPatch(typeof(ExtensionsMenuScreen), nameof(ExtensionsMenuScreen.DrawExtensionInfoDetail))]
+ internal static void OnBackButtonPressPostfix(ILContext il)
+ {
+ ILCursor c = new ILCursor(il);
+
+ c.GotoNext(MoveType.Before,
+ x => x.MatchLdnull(),
+ x => x.MatchStfld(AccessTools.Field(typeof(ExtensionsMenuScreen), nameof(ExtensionsMenuScreen.ExtensionInfoToShow)))
+ );
+
+ c.Emit(OpCodes.Ldsfld, AccessTools.Field(typeof(HacknetChainloader), nameof(HacknetChainloader.Instance)));
+ c.Emit(OpCodes.Callvirt, AccessTools.Method(typeof(HacknetChainloader), nameof(HacknetChainloader.UnloadTemps)));
+ }
+
+ [HarmonyPrefix]
+ [HarmonyPatch(typeof(AppDomain), "get_BaseDirectory")]
+ private static bool ReturnCorrectDirectoryPrefix(out string __result)
{
- if (myID == 7900040 && __result)
- HacknetChainloader.Instance.UnloadTemps();
+ __result = Paths.GameRootPath;
+ return false;
}
}
diff --git a/ExampleMod/ExampleMod.csproj b/ExampleMod/ExampleMod.csproj
index 1196b7d3..88ffc401 100644
--- a/ExampleMod/ExampleMod.csproj
+++ b/ExampleMod/ExampleMod.csproj
@@ -9,7 +9,7 @@
Properties
ExampleMod
ExampleMod
- v4.0
+ v4.5
512
true
@@ -33,30 +33,22 @@
4
-
+
..\libs\0Harmony.dll
- False
+ False
-
+
..\libs\BepInEx.Core.dll
- False
+ False
-
+
..\libs\FNA.dll
False
-
+
..\libs\HacknetPathfinder.exe
False
-
- ..\libs\Mono.Cecil.dll
- False
-
-
- ..\libs\MonoMod.Utils.dll
- False
-
diff --git a/Linux/StartPathfinder.sh b/Linux/StartPathfinder.sh
new file mode 100644
index 00000000..3bad6c53
--- /dev/null
+++ b/Linux/StartPathfinder.sh
@@ -0,0 +1 @@
+TERM=xterm LD_PRELOAD="$(pwd)/lib64/libcef.so $(pwd)/intercept.so /usr/lib/libmono-2.0.so.1" MONO_DEBUG=explicit-null-checks ./HacknetPathfinder.bin.x86_64
diff --git a/Linux/intercept.c b/Linux/intercept.c
new file mode 100644
index 00000000..3ea0b95e
--- /dev/null
+++ b/Linux/intercept.c
@@ -0,0 +1,11 @@
+#define _GNU_SOURCE
+
+#include
+#include
+
+void mono_set_dirs(char *assembly_dir,char *config_dir) {
+ setenv("MONO_PATH", "/usr/lib/mono/4.5", 1);
+
+ void (*set_dir_ptr)(char*,char*) = dlsym(RTLD_NEXT, "mono_set_dirs");
+ (*set_dir_ptr)("/usr/lib/mono/4.5", config_dir);
+}
diff --git a/Linux/intercept.so b/Linux/intercept.so
new file mode 100755
index 00000000..79511f25
Binary files /dev/null and b/Linux/intercept.so differ
diff --git a/PathfinderAPI/PathfinderAPI.csproj b/PathfinderAPI/PathfinderAPI.csproj
index c397635d..eb101cf6 100644
--- a/PathfinderAPI/PathfinderAPI.csproj
+++ b/PathfinderAPI/PathfinderAPI.csproj
@@ -9,7 +9,7 @@
Properties
Pathfinder
PathfinderAPI
- v4.0
+ v4.5
512
true
8
@@ -32,29 +32,29 @@
4
-
+
..\libs\0Harmony.dll
- False
+ False
-
+
..\libs\BepInEx.Core.dll
- False
+ False
-
+
..\libs\FNA.dll
False
-
+
..\libs\HacknetPathfinder.exe
False
..\libs\Mono.Cecil.dll
- False
+ False
-
+
..\libs\MonoMod.Utils.dll
- False
+ False
diff --git a/PathfinderInstaller/PathfinderInstaller.py b/PathfinderInstaller/PathfinderInstaller.py
index 1e6fee2f..7124de2f 100644
--- a/PathfinderInstaller/PathfinderInstaller.py
+++ b/PathfinderInstaller/PathfinderInstaller.py
@@ -41,9 +41,12 @@ def install_pathfinder(gen_event_callback, hacknet_directory):
try:
os.remove(patcher_exe)
os.remove(os.path.join(hacknet_directory, 'Mono.Cecil.dll'))
- hacknet_exe = os.path.join(hacknet_directory, 'Hacknet.exe')
- os.rename(hacknet_exe, os.path.join(hacknet_directory, 'HacknetOld.exe'))
- os.rename(os.path.join(hacknet_directory, 'HacknetPathfinder.exe'), hacknet_exe)
+ if platform.system() == 'Windows':
+ hacknet_exe = os.path.join(hacknet_directory, 'Hacknet.exe')
+ os.rename(hacknet_exe, os.path.join(hacknet_directory, 'HacknetOld.exe'))
+ os.rename(os.path.join(hacknet_directory, 'HacknetPathfinder.exe'), hacknet_exe)
+ else:
+ shutil.copy(os.path.join(hacknet_directory, 'Hacknet.bin.x86_64'), os.path.join(hacknet_directory, 'HacknetPathfinder.bin.x86_64'))
except OSError:
gen_event_callback('<>')
return
diff --git a/PathfinderPatcher/Program.cs b/PathfinderPatcher/Program.cs
index 7617cddb..3c35a6f3 100644
--- a/PathfinderPatcher/Program.cs
+++ b/PathfinderPatcher/Program.cs
@@ -1,7 +1,7 @@
using System;
using System.Linq;
using System.Security;
-using System.Reflection;
+using SR = System.Reflection;
using Mono.Cecil;
using Mono.Cecil.Cil;
@@ -66,17 +66,17 @@ void MakePublic(TypeDefinition type, bool nested = false)
processor.Emit(OpCodes.Ldstr, "./BepInEx/core/BepInEx.Hacknet.dll");
processor.Emit(OpCodes.Call, hn.MainModule.ImportReference(typeof(System.IO.Path).GetMethod("GetFullPath", new Type[] { typeof(string) })));
// Load BepInEx.Hacknet.dll
- processor.Emit(OpCodes.Call, hn.MainModule.ImportReference(typeof(Assembly).GetMethod("LoadFile", new Type[] { typeof(string) })));
+ processor.Emit(OpCodes.Call, hn.MainModule.ImportReference(typeof(SR.Assembly).GetMethod("LoadFile", new Type[] { typeof(string) })));
// Get Entrypoint type
processor.Emit(OpCodes.Ldstr, "BepInEx.Hacknet.Entrypoint");
- processor.Emit(OpCodes.Call, hn.MainModule.ImportReference(typeof(Assembly).GetMethod("GetType", new Type[] { typeof(string) })));
+ processor.Emit(OpCodes.Call, hn.MainModule.ImportReference(typeof(SR.Assembly).GetMethod("GetType", new Type[] { typeof(string) })));
// Get bootstrap method
processor.Emit(OpCodes.Ldstr, "Bootstrap");
processor.Emit(OpCodes.Call, hn.MainModule.ImportReference(typeof(Type).GetMethod("GetMethod", new Type[] { typeof(string) })));
// Call bootstrap method
processor.Emit(OpCodes.Ldnull);
processor.Emit(OpCodes.Ldnull);
- processor.Emit(OpCodes.Callvirt, hn.MainModule.ImportReference(typeof(MethodBase).GetMethod("Invoke", new Type[] { typeof(object), typeof(object[]) })));
+ processor.Emit(OpCodes.Callvirt, hn.MainModule.ImportReference(typeof(SR.MethodBase).GetMethod("Invoke", new Type[] { typeof(object), typeof(object[]) })));
processor.Emit(OpCodes.Pop);
// Return
processor.Emit(OpCodes.Ret);
@@ -88,6 +88,17 @@ void MakePublic(TypeDefinition type, bool nested = false)
var unverifiableCtor = hn.MainModule.ImportReference(unverifiableType.Methods.First(x => x.IsConstructor && x.Parameters.Count == 0));
hn.MainModule.CustomAttributes.Add(new CustomAttribute(unverifiableCtor));
+ var corlibRef = hn.MainModule.AssemblyReferences.FirstOrDefault(x => x.Name == "mscorlib");
+ corlibRef.PublicKey = null;
+ corlibRef.PublicKeyToken = null;
+ corlibRef.HasPublicKey = false;
+
+ var targetRuntime = hn.CustomAttributes.FirstOrDefault(x => x.AttributeType.Name == "TargetFrameworkAttribute");
+ targetRuntime.ConstructorArguments.Clear();
+ targetRuntime.ConstructorArguments.Add(new CustomAttributeArgument(hn.MainModule.TypeSystem.String, ".NETFramework,Version=v4.5"));
+ targetRuntime.Properties.Clear();
+ targetRuntime.Properties.Add(new CustomAttributeNamedArgument("FrameworkDisplayName", new CustomAttributeArgument(hn.MainModule.TypeSystem.String, ".NET Framework 4.5")));
+
// Write modified assembly to disk
hn.Write("HacknetPathfinder.exe");
diff --git a/README.md b/README.md
index 5a26ab17..16832e4d 100644
--- a/README.md
+++ b/README.md
@@ -8,20 +8,32 @@ There are several options available to choose to install Pathfinder, the install
### Installer
-If you're on Windows, it's recommended that you use the installer .exe from [here](https://github.com/Arkhist/Hacknet-Pathfinder/releases). Just run the installer and it should automatically find your Hacknet folder, then just hit install. Launching Hacknet from Steam will launch Pathfinder!
+If you're on Windows, it's recommended that you use the installer .exe from [here](https://github.com/Arkhist/Hacknet-Pathfinder/releases). Just run the installer and it should automatically find your Hacknet folder, then just hit install. Launching Hacknet from Steam will launch Pathfinder (on Windows)!
If you decide to use the .py installer (or you're just on Linux and have to use it) keep in mind it requires python3 and tk to be installed before you run it.
+If you're on Linux, once the installer is complete, make sure to +x StartPathfinder.sh yourself.
+
To uninstall, just reopen the installer and click uninstall. This will clear out all of the changes the installer made, and will also delete all of your mods with it.
-### Manually
+### Manually (Windows)
Get the latest ZIP from the releases page [here](https://github.com/Arkhist/Hacknet-Pathfinder/releases) and extract it to your Hacknet folder.
-Run PathfinderPatcher.exe and it will create HacknetPathfinder.exe, if you want this to be launched when you launch from Steam rename Hacknet.exe and replace it with HacknetPathfinder.exe (this also applies to Linux).
+Run PathfinderPatcher.exe and it will create HacknetPathfinder.exe, if you want this to be launched when you launch from Steam rename Hacknet.exe and replace it with HacknetPathfinder.exe.
To uninstall, just delete HacknetPathfinder.exe (or whatever you renamed it to) and move back the original Hacknet.exe if you renamed it. If you also want to remove all your mods and configs, delete the BepInEx directory.
+### Manually (Linux)
+
+Get the latest ZIP from the releases page [here](https://github.com/Arkhist/Hacknet-Pathfinder/releases) and extract it to your Hacknet folder.
+
+Run PathfinderPatcher.exe and it will create HacknetPathfinder.exe.
+
+Copy `Hacknet.bin.x86_64` to `HacknetPathfinder.bin.x86_64`
+
+Make StartPathfinder.sh executable and run it.
+
## Troubleshooting
### The game crashes before it even loads! (Windows only)
diff --git a/libs/0Harmony.dll b/libs/0Harmony.dll
index 1065ad10..2f2e6ef9 100644
Binary files a/libs/0Harmony.dll and b/libs/0Harmony.dll differ
diff --git a/libs/BepInEx.Core.dll b/libs/BepInEx.Core.dll
index af11f59e..f90a869e 100644
Binary files a/libs/BepInEx.Core.dll and b/libs/BepInEx.Core.dll differ
diff --git a/libs/BepInEx.Core.xml b/libs/BepInEx.Core.xml
index 46f787d1..d42d0727 100644
--- a/libs/BepInEx.Core.xml
+++ b/libs/BepInEx.Core.xml
@@ -810,7 +810,7 @@
- The version range of the referenced plugin.
+ The version range of the referenced plugin.
@@ -887,6 +887,14 @@
The plugin instance.
The attributes of the instance, if existing.
+
+
+ Gets the specified attributes of a reflection metadata type, if they exist.
+
+ The attribute type to retrieve.
+ The reflection metadata instance.
+ The attributes of the instance, if existing.
+
Retrieves the dependencies of the specified plugin type.
diff --git a/libs/MonoMod.RuntimeDetour.dll b/libs/MonoMod.RuntimeDetour.dll
index 35087890..ede4adbe 100644
Binary files a/libs/MonoMod.RuntimeDetour.dll and b/libs/MonoMod.RuntimeDetour.dll differ
diff --git a/libs/MonoMod.Utils.dll b/libs/MonoMod.Utils.dll
index a8fecaf8..4eadfbe7 100644
Binary files a/libs/MonoMod.Utils.dll and b/libs/MonoMod.Utils.dll differ
diff --git a/libs/SemVer.dll b/libs/SemVer.dll
deleted file mode 100644
index daba2a2e..00000000
Binary files a/libs/SemVer.dll and /dev/null differ
diff --git a/libs/SemanticVersioning.dll b/libs/SemanticVersioning.dll
new file mode 100644
index 00000000..9e47be91
Binary files /dev/null and b/libs/SemanticVersioning.dll differ