Mod support
I do feel a bit selfish for immediately asking for this, but I've been wondering whether it is possible to get mods working with this setup? The official BepInEx site mentions that it is compatible with macOS, but I couldn't get it to work on the first try.
No worries! 🙌
The current Valheim + Steam integration works due to injection of SteamAppId into the environment when the app launches in Info.plist.
From a quick inspection it seems that the BepInEx script launches the MacOS/Valheim binary directly, which might mean that particular Steam setting is not taken into account.
Could you try running it as follows:
SteamAppId=892970 ./run_bepinex.sh
Hey, @Fusion86. Spent the evening yesterday myself getting BepInEx to work. Here's the rundown.
- Moved Valheim.app from build/ to it's own directory in
/Applications/Games/Valheim/GAME - Downloaded BepInEx (BepInEx_unix_5.4.21.0.zip)
- Unpacked it into
GAMEdir (i.e. the dir-structure is now:Valheim.app,BepInEx,doorstop_libs,run_bepinex.shandchangelog.txt) - Open a terminal in the
GAMEdir and make the .sh user-executable by typingchmod u+x run_bepinex.sh - [hours of trying to get it to work skipped for you]
- Download the denikson BepInEx distribution for Valheim at thunderstore.io
- unpack somewhere else and copy
winhttp.dll,doostop_config.iniand (probably, most importantly)unstripped_corlibto theGAMEdir. Also copyBepInEx/config(and why notBepInEx/plugins/Valheim.DisplayBepInExInfo.dll, while you're at it) toGAME/BepInEx/First part is done.
Now edit run_bepinex.sh in the GAME dir as follows:
- after the
# ---- EDIT AS NEEDED ------line - addexport SteamAppId=892970as per @timkurvers comment above (thanks!) - change
executable_nametoexecutable_name="Valheim.app" - find the
DOORSTOP_CORLIB_OVERRIDE_PATHand change it to"$BASEDIR/unstripped_corlib"(or copy the relevant part for it from here:)
# -------- SETTINGS --------
# ---- EDIT AS NEEDED ------
export SteamAppId=892970
# EDIT THIS: The name of the executable to run
# LINUX: This is the name of the Unity game executable
# MACOS: This is the name of the game app folder, including the .app suffix
executable_name="Valheim.app"
# The rest is automatically handled by BepInEx
# Whether or not to enable Doorstop. Valid values: TRUE or FALSE
export DOORSTOP_ENABLE=TRUE
# What .NET assembly to execute. Valid value is a path to a .NET DLL that mono can execute.
export DOORSTOP_INVOKE_DLL_PATH="$BASEDIR/BepInEx/core/BepInEx.Preloader.dll"
# If specified, Doorstop will load core libraries from this folder instead of the normal Managed folder
# Mainly usable to unstrip assemblies in some games
export DOORSTOP_CORLIB_OVERRIDE_PATH="$BASEDIR/unstripped_corlib"
# ----- DO NOT EDIT FROM THIS LINE FORWARD ------
To launch directly from steam:
- Open steam and add a non-steam game.
- Now, find
Valheim.app(in my case it's inside:/Applications/Games/Valheim/GAME) - After you add the game, select the newly added Valheim in your steam library (it shouldn't have an icon), click the little cogwheel-settings button and select
Properties.... - There, edit
Launch Optionsas follows:"/Applications/Games/Valheim/GAME/run_bepinex.sh" %command% --args -console"(You can skip the --args -console if you don't need the in-game console for some reason).
That's it.
You should now be able to start from steam and it should work.
In case it doesn't - try to launch from the terminal and post the output here: (i.e. open the terminal, go to the GAME dir and type in ./run_bepinex.sh).
PS: Oh, and @timkurvers: Thanks so much for making this happen! We'll enjoy the ride, while it lasts : )
Incredible write-up @phonique! Thanks for sharing 🥳
Thanks @phonique for that detailed description! with that held I was able to make it even easier to work (in my case I wanted to use ValheimPlus, which already includes BepEx):
Just head to their release page and get the latest UnixClient.zip (for me it was 0.9.9.16) and put the content next to the Valheim.app folder.
The only thing you have to adapt now is the same as @phonique described:
edit the start_game_bepinex.sh:
...
# -------- SETTINGS --------
# ---- EDIT AS NEEDED ------
export SteamAppId=892970
# EDIT THIS: The name of the executable to run
# LINUX: This is the name of the Unity game executable
# MACOS: This is the name of the game app folder, including the .app suffix
executable_name="Valheim.app"
...
export DOORSTOP_CORLIB_OVERRIDE_PATH="$BASEDIR/unstripped_corlib"
...
If you do not want ValheimPlus you can just delete the dll in the `BepInEx/plugins` folder
This worked fantastic! Thank you! Was able to get Valheim+ (Grantapher Temp) and Advize PlantEverything installed and haven't had any issues so far.
I've followed the steps in this thread and have mods loading but some mods have a problem where their textures aren't loading and all the items or enemies they add are purple. For example monstrum mobs are purple but the odinshorse loads in just fine. Epicloot weapons are purple pillars when thrown. but odins campsites loads and works fine. There are no errors in the logs.
I've tested it on windows and all the mods are compatible with no issues.
Any help would be appreciated.
I've followed the steps in this thread and have mods loading but some mods have a problem where their textures aren't loading and all the items or enemies they add are purple. For example monstrum mobs are purple but the odinshorse loads in just fine. Epicloot weapons are purple pillars when thrown. but odins campsites loads and works fine. There are no errors in the logs.
I've tested it on windows and all the mods are compatible with no issues.
Any help would be appreciated.
It's possible the mods are using texture formats that are not supported by OpenGL for macOS (Apple deprecated it years ago, after all).
Anything in the Player.log about textures that could not be loaded?
Great write up @phonique Just chiming in about some recent changes:
Basically unstripped_corlibs is no longer needed. Tested this last night, and bepinex works.
For reference, this is what my shell file now looks like:
Have fun!
LogOutput.log Anyone able to get epicloot working? Bepin loads just fine, but plugins seem to not load in game. Doing same manual setup on pc works just fine.
Here's the error in the log:
[Error : Unity Log] IOException: Operation not supported
Stack trace:
System.IO.CoreFX.FileSystemWatcher.StartRaisingEvents () (at <5fe808a9ce234d7cb9b1a4e14f988a80>:0)
System.IO.CoreFX.FileSystemWatcher.StartRaisingEventsIfNotDisposed () (at <5fe808a9ce234d7cb9b1a4e14f988a80>:0)
System.IO.CoreFX.FileSystemWatcher.set_EnableRaisingEvents (System.Boolean value) (at <5fe808a9ce234d7cb9b1a4e14f988a80>:0)
(wrapper remoting-invoke-with-check) System.IO.CoreFX.FileSystemWatcher.set_EnableRaisingEvents(bool)
System.IO.CoreFXFileSystemWatcherProxy+<>c.<StartDispatching>b__9_0 (System.IO.CoreFX.FileSystemWatcher internal_fsw, System.IO.FileSystemWatcher fsw) (at <5fe808a9ce234d7cb9b1a4e14f988a80>:0)
System.IO.CoreFXFileSystemWatcherProxy.Operation (System.Action`4[T1,T2,T3,T4] map_op, System.Action`2[T1,T2] object_op, System.Object handle, System.Action`2[T1,T2] cancel_op) (at <5fe808a9ce234d7cb9b1a4e14f988a80>:0)
Rethrow as InvalidOperationException: object_op
System.IO.CoreFXFileSystemWatcherProxy.Operation (System.Action`4[T1,T2,T3,T4] map_op, System.Action`2[T1,T2] object_op, System.Object handle, System.Action`2[T1,T2] cancel_op) (at <5fe808a9ce234d7cb9b1a4e14f988a80>:0)
System.IO.CoreFXFileSystemWatcherProxy.StartDispatching (System.Object handle) (at <5fe808a9ce234d7cb9b1a4e14f988a80>:0)
System.IO.FileSystemWatcher.Start () (at <5fe808a9ce234d7cb9b1a4e14f988a80>:0)
System.IO.FileSystemWatcher.set_EnableRaisingEvents (System.Boolean value) (at <5fe808a9ce234d7cb9b1a4e14f988a80>:0)
(wrapper remoting-invoke-with-check) System.IO.FileSystemWatcher.set_EnableRaisingEvents(bool)
EpicLoot.EpicLoot.LoadJsonFile[T] (System.String filename, System.Action`1[T] onFileLoad, EpicLoot.Data.ConfigType configType, System.Boolean update) (at <c085ade0925d42a7910d0d32c1396d5c>:0)
EpicLoot.EpicLoot.InitializeConfig () (at <c085ade0925d42a7910d0d32c1396d5c>:0)
EpicLoot.EpicLoot.Awake () (at <c085ade0925d42a7910d0d32c1396d5c>:0)
UnityEngine.GameObject:AddComponent(Type)
BepInEx.Bootstrap.Chainloader:Start()
UnityEngine.UI.Graphic:get_canvas()
TMPro.TextMeshProUGUI:OnCanvasHierarchyChanged()
@seathasky Judging from Mono's FileSystemWatcher code, it should be possible to swap to a different watcher (seems to default to CoreFX on macOS?) by setting environment variable MONO_MANAGED_WATCHER to something (e.g. false) or disabled.
@seathasky Judging from Mono's
FileSystemWatchercode, it should be possible to swap to a different watcher (seems to default to CoreFX on macOS?) by setting environment variableMONO_MANAGED_WATCHERto something (e.g.false) ordisabled.
This did it! Thank you!!
For those having similar issues to mods, add export MONO_MANAGED_WATCHER=FALSE to you run shell.
epic loot working:
@timkurvers thanks again
Hey, @Fusion86. Spent the evening yesterday myself getting BepInEx to work. Here's the rundown.
* Moved Valheim.app from build/ to it's own directory in `/Applications/Games/Valheim/GAME` * Downloaded [BepInEx](https://github.com/BepInEx/BepInEx/releases/tag/v5.4.21) (BepInEx_unix_5.4.21.0.zip) * Unpacked it into `GAME` dir (i.e. the dir-structure is now: `Valheim.app`, `BepInEx`, `doorstop_libs`, `run_bepinex.sh` and `changelog.txt`) * Open a terminal in the `GAME` dir and make the .sh user-executable by typing `chmod u+x run_bepinex.sh` * [hours of trying to get it to work skipped for you] * Download the denikson BepInEx distribution for Valheim at [thunderstore.io](https://valheim.thunderstore.io/package/denikson/BepInExPack_Valheim/) * unpack somewhere else and copy `winhttp.dll`, `doostop_config.ini` and (probably, most importantly) `unstripped_corlib` to the `GAME` dir. Also copy `BepInEx/config` (and why not `BepInEx/plugins/Valheim.DisplayBepInExInfo.dll`, while you're at it) to `GAME/BepInEx/` First part is done.Now edit
run_bepinex.shin theGAMEdir as follows:* after the `# ---- EDIT AS NEEDED ------` line - add `export SteamAppId=892970` as per @timkurvers comment above (thanks!) * change `executable_name` to `executable_name="Valheim.app"` * find the `DOORSTOP_CORLIB_OVERRIDE_PATH` and change it to `"$BASEDIR/unstripped_corlib"` (or copy the relevant part for it from here:)# -------- SETTINGS -------- # ---- EDIT AS NEEDED ------ export SteamAppId=892970 # EDIT THIS: The name of the executable to run # LINUX: This is the name of the Unity game executable # MACOS: This is the name of the game app folder, including the .app suffix executable_name="Valheim.app" # The rest is automatically handled by BepInEx # Whether or not to enable Doorstop. Valid values: TRUE or FALSE export DOORSTOP_ENABLE=TRUE # What .NET assembly to execute. Valid value is a path to a .NET DLL that mono can execute. export DOORSTOP_INVOKE_DLL_PATH="$BASEDIR/BepInEx/core/BepInEx.Preloader.dll" # If specified, Doorstop will load core libraries from this folder instead of the normal Managed folder # Mainly usable to unstrip assemblies in some games export DOORSTOP_CORLIB_OVERRIDE_PATH="$BASEDIR/unstripped_corlib" # ----- DO NOT EDIT FROM THIS LINE FORWARD ------To launch directly from steam:
* Open steam and add a non-steam game. * Now, find `Valheim.app` (in my case it's inside: `/Applications/Games/Valheim/GAME`) * After you add the game, select the newly added Valheim in your steam library (it shouldn't have an icon), click the little cogwheel-settings button and select `Properties...`. * There, edit `Launch Options` as follows: `"/Applications/Games/Valheim/GAME/run_bepinex.sh" %command% --args -console"` (You can skip the --args -console if you don't need the in-game console for some reason).That's it.
You should now be able to start from steam and it should work. In case it doesn't - try to launch from the terminal and post the output here: (i.e. open the terminal, go to the
GAMEdir and type in./run_bepinex.sh).PS: Oh, and @timkurvers: Thanks so much for making this happen! We'll enjoy the ride, while it lasts : )
got it working, thanks a lot.
but now must comment DOORSTOP_CORLIB_OVERRIDE_PATH asignation, now that lib is into Valheim i think
Thank you @timkurvers for all you've done. I'm new to Mac but got this going thanks to you. Additionally I want to thank @phonique and @seathasky for the details with getting mods to work...which I have. The only thing that doesn't work for me is launching the external app in Steam. I put in the console options "/Applications/Games/Valheim/GAME/run_bepinex.sh" %command% --args -console" but it throws an unknown error. If I remove %command% it launches but no bepinex or mods are enabled. Currently I can only run mods by using @phonique 's terminal instructions: ./run_bepinex.sh
If anyone has any suggestions to get it working from the external Steam app method I would be most grateful.
@drummercraig - can you share any details on what mod you were using and how you got it runnning? It looks like BepInEx had it's config files rearchitected at some point as the config files look completely different than this thread.
I'm trying to play ValheimPlus and when I update the game path and try to launch using the start_game_bepinex.sh script I get an error:
./start_game_bepinex.sh: line 86: /gamepath/GAME/Valheim.app: is a directory
I've tried to update the config to point to the exectuable at Valheim.app/Contents/MacOS/Valheim and the game launches but BepInEx is not injected and its not running ValheimPlus.
Example of the current config file:
# Resolve base directory relative to this script
# Hopefully this resolves relative paths and links
a="/$0"; a=${a%/*}; a=${a#/}; a=${a:-.}; BASEDIR=$(cd "$a"; pwd -P)
# Special case: program is launched via Steam
# In that case rerun the script via their bootstrapper to ensure Steam overlay works
if [ "$2" = "SteamLaunch" ]; then
cmd="$1 $2 $3 $4 $0"
shift 4
exec $cmd $@
exit
fi
exec="$BASEDIR/Valheim.app"
export DOORSTOP_ENABLE=TRUE
export DOORSTOP_INVOKE_DLL_PATH="$BASEDIR/BepInEx/core/BepInEx.Preloader.dll"
export DOORSTOP_CORLIB_OVERRIDE_PATH="$BASEDIR/unstripped_corlib"
export SteamAppId=892970
# Allow to specify --doorstop-enable true|false
# Everything else is passed as-is to `exec`
while :; do
case $1 in
To answer your question - I was able to get (the base game) running via steam by following some of the steps here.
EDIT: while I was working on getting this running Valhiem announced an official MacOS Port earlier today on Twitter!!
Totally appreciate you asking. I have learned to just use the command line to launch and don't need to launch with Steam and am happy with that. A friend told me today about the official MacOS coming on the 10th I think? Awesome.
Sorry, I think my earlier response didn't answer a question you asked. I run it on an M1 Mac Studio and have never got the Steam launch to work. I do currently run 13 mods with my install. I also never got the start_game_bepinex.sh to work. So to try and clarify, I built the Valheim app using Tim's instructions. I then created a new separate folder (name it what you want) to be my Valheim game folder and copied the single Valheim.app file previously built. Then I manually downloaded from thunderstore the specific Valheim Bepinex and copied the Bepinex folder into my new folder and added the mods into the plugin folder within. I have a separate run_bepinex.sh file that I got from somewhere in here that I use to launch the game via command line. I have copied the contents below. I hope that helps and if you need any other details just ask. Sorry about the comment formatting below...this page just does it, changing font, removing the # etc and I don't know how to not have it change anything.
#!/bin/sh
BepInEx running script
This script is used to run a Unity game with BepInEx enabled.
Usage: Configure the script below and simply run this script when you want to run your game modded.
a="/$0"; a=${a%/*}; a=${a#/}; a=${a:-.}; BASEDIR=$(cd "$a"; pwd -P)
-------- SETTINGS --------
---- EDIT AS NEEDED ------
export SteamAppId=892970
EDIT THIS: The name of the executable to run
LINUX: This is the name of the Unity game executable
MACOS: This is the name of the game app folder, including the .app suffix
executable_name="Valheim.app"
The rest is automatically handled by BepInEx
Whether or not to enable Doorstop. Valid values: TRUE or FALSE
export DOORSTOP_ENABLE=TRUE
What .NET assembly to execute. Valid value is a path to a .NET DLL that mono can execute.
export DOORSTOP_INVOKE_DLL_PATH="$BASEDIR/BepInEx/core/BepInEx.Preloader.dll"
If specified, Doorstop will load core libraries from this folder instead of the normal Managed folder
Mainly usable to unstrip assemblies in some games
export DOORSTOP_CORLIB_OVERRIDE_PATH=""
----- DO NOT EDIT FROM THIS LINE FORWARD ------
----- (unless you know what you're doing) ------
Special case: program is launched via Steam
In that case rerun the script via their bootstrapper to ensure Steam overlay works
if [ "$2" = "SteamLaunch" ]; then "$1" "$2" "$3" "$4" "$0" "$5" exit fi
if [ ! -x "$1" -a ! -x "$executable_name" ]; then echo "Please open run.sh in a text editor and configure executable name." exit 1 fi
doorstop_libs="$BASEDIR/doorstop_libs" arch="" executable_path="" lib_postfix=""
os_type=$(uname -s) case $os_type in Linux*) executable_path="$BASEDIR/${executable_name}" lib_postfix="so" ;; Darwin*) executable_name=$(basename "${executable_name}" .app) real_executable_name=$(defaults read "$BASEDIR/${executable_name}.app/Contents/Info" CFBundleExecutable) executable_path="$BASEDIR/${executable_name}.app/Contents/MacOS/${real_executable_name}" lib_postfix="dylib" ;; *) echo "Cannot identify OS (got $(uname -s))!" echo "Please create an issue at https://github.com/BepInEx/BepInEx/issues." exit 1 ;; esac
Special case: if there is an arg, use that as executable path
Linux: arg is path to the executable
MacOS: arg is path to the .app folder which we need to resolve to the exectuable
if [ -n "$1" ]; then case $os_type in Linux*) executable_path="$1" ;; Darwin*) # Special case: allow to specify path to the executable within .app full_path_part=$(echo "$1" | grep ".app/Contents/MacOS") if [ -z "$full_path_part" ]; then executable_name=$(basename "$1" .app) real_executable_name=$(defaults read "$1/Contents/Info" CFBundleExecutable) executable_path="$1/Contents/MacOS/${real_executable_name}" else executable_path="$1" fi ;; esac fi
abs_path() { echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")" }
_readlink() { # relative links with readlink (without -f) do not preserve the path info ab_path="$(abs_path "$1")" link="$(readlink "${ab_path}")" case $link in /*);; *) link="$(dirname "$ab_path")/$link";; esac echo "$link" }
resolve_executable_path () { e_path="$(abs_path "$1")"
while [ -L "${e_path}" ]; do
e_path=$(_readlink "${e_path}");
done
echo "${e_path}"
}
executable_path=$(resolve_executable_path "${executable_path}") echo "${executable_path}" executable_type=$(LD_PRELOAD="" file -b "${executable_path}");
case $executable_type in PE32) echo "The executable is a Windows executable file. You must use Wine/Proton and BepInEx for Windows with this executable." echo "Uninstall BepInEx for *nix and install BepInEx for Windows instead." echo "More info: https://docs.bepinex.dev/articles/advanced/steam_interop.html#protonwine" exit 1 ;; 64-bit) arch="x64" ;; 32-bit|i386) arch="x86" ;; *) echo "Cannot identify executable type (got ${executable_type})!" echo "Please create an issue at https://github.com/BepInEx/BepInEx/issues." exit 1 ;; esac
doorstop_libname=libdoorstop_${arch}.${lib_postfix} export LD_LIBRARY_PATH="${doorstop_libs}":${LD_LIBRARY_PATH} export LD_PRELOAD=$doorstop_libname:$LD_PRELOAD export DYLD_LIBRARY_PATH="${doorstop_libs}" export DYLD_INSERT_LIBRARIES="${doorstop_libs}/$doorstop_libname"
"${executable_path}"
@drummercraig - thank you! Could you try pasting the old run_bepinx.sh script here again - try using triple tilde's before and after the script and it should format the whole thing correctly as a code block. I'm tying to make it work but some of the code was reformatted from not being in a code-block.
I think that's the issue - the newer .sh included with the later versions of Bepinx refuse to launch the .app file and are detecting it as a folder.
EDIT: nevermind - the older releases are still available - I pulled down the start script from there. Thank you!
Closing this issue as the official macOS client is now available! 🥳 (see #104)