lupi

cow of tailed snake (gay)

avatar by @citriccenobite

you can say "chimoora" instead of "cow of tailed snake" if you want. its a good pun.​


i ramble about aerospace sometimes
I take rocket photos and you can see them @aWildLupi


I have a terminal case of bovine pungiform encephalopathy, the bovine puns are cowmpulsory


they/them/moo where "moo" stands in for "you" or where it's funny, like "how are moo today, Lupi?" or "dancing with mooself"



Bovigender (click flag for more info!)
bovigender pride flag, by @arina-artemis (click for more info)



vallerie
@vallerie

For reasons (I'm giving a talk at a local university on getting started with writing GLSL, and might want to use Godot as part of it, due to the lack of licensing), I need to have Godot running with the following restrictions:

  • the student machines are running M1 Macs (specifically, they all use Mac Studios)
  • Usage of the C# Godot Editor (due to Java being so prevalent, and Java -> C# being a pretty easy migration)
  • No admin rights on any machines
  • No local installation of .NET
  • Can execute unsigned applications from any directory on disk (this is macOS, install directories are more of a vibe than a science)

So! How do we solve this?

Godot doesn't come bundled with .NET

Error message from Godot saying it cannot load the .NET runtime. It points us to dotnet.microsoft.com

Pretty big starter issue here: Godot doesn't come bundled with .NET. This isn't usually an issue, and Godot gives you this helpful prompt. Let's do this then!

Every developer tool assumes you have admin rights

GIF of trying to use the dotnet .pkg to install dotnet. It asks for admin rights, and Val types oh no in the username field

For anyone who has ever tried teaching, or anyone who was ever a kid trying to play video games on the school computer, you'll know intimately that basically everything assumes you have admin rights. With .NET, this is fair - it tries to install itself to somewhere in /usr/local, as that's where every program using it assumes it will be.

Installing .NET without admin

Screenshot of the .NET binary download page. There's a radial blurred Mr Beast, and a big red circle around the binaries.
look i had to add something to make these dry images fun, and mr beast is a well known C# user
(note to self: check if "well known C# user" is libellous)

.NET can actually be installed without admin! Microsoft provide binaries, on their website, and they come in a .tar.gz. We can just place it somewhere, and setup our DOTNET_ROOT and PATH environment variables to point to the right directory.

(Thanks to everyone who has contributed to this GitHub issue, and specifically GitHub users Splitwirez and definitelyokay!)

Pointing Godot at this new .NET path

We now have a copy of .NET, and, a copy of Godot. But - launching Godot straight from the .app file still gives us the same issue. What gives?

Turns out, there's a hint in that GitHub issue! Specifically, this comment from definitelyokay

Commenting here because running Godot from Finder/macOS doesn't respect the path to dotnet set in .zshrc. Opening Godot from the terminal does allow it to find the dotnet sdk from the path specified in the .zshrc file. Godot 3.4.4.mono.stable.

I verify this by running ~/Applications/Godot_mono.app/Contents/MacOS/Godot, and, yup! .NET is found... and I get "Application is damaged" from macOS. A simple xattr -d com.apple.quarantine -r . where I've extracted .NET will fix this.

Not needing the terminal

For anyone who doesn't use a Mac, .app files that look like a flat file in the Finder, but, in reality, are just directories. If someone wanted to go and replace the binary, they can just replace YourCoolApp.app/Contents/MacOs/YourCoolApp.

As it's Just a Directory, we can do some cool stuff here! Specifically, we can move Contents/MacOS/Godot to Contents/MacOs/GodotBin, and then add a new Contents/MacOS/Godot to be our launcher. This launcher will setup the environment variables for us, so launching Godot from the Finder / Spotlight / Dock will execute this lanucher, which will then in turn launch Godot proper. The script should be something like this:

#!/bin/bash
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )

# Let Godot find .NET!
export PATH=$PATH:~/.bin/dotnet-sdk-7/
export DOTNET_ROOT="~/.bin/dotnet-sdk-7/"

# "$@" is because Godot opening a project will execute itself with some command line arguments
# So, we pass all arguments to the real Godot binary
$SCRIPT_DIR/GodotBin "$@"

Then, we just mark this executable with chmod +x Contents/MacOS/Godot. Now you can load Godot from the dock, and it finds .NET, all without a care in the world

Making this more friendly for education

So, this is all good, but, this is a lot of hardcoded paths. Instead, I'd love a copy of Godot I can put on a bunch of machines using a USB drive shortly before a workshop, all setup with the environment variables and a copy of .NET.

This isn't actually too hard. We can move our dotnet-sdk-7 folder into the Godot_Mono.app/Contents/ folder, and then setup our paths to be local. The modification of the script to do this is as follows!

#!/bin/bash
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )

# Let Godot find .NET!
export PATH=$PATH:$SCRIPT_DIR/../dotnet-sdk-7/
export DOTNET_ROOT="$SCRIPT_DIR/../dotnet-sdk-7/"

# "$@" is because Godot opening a project will execute itself with some command line arguments
# So, we pass all arguments to the real Godot binary
$SCRIPT_DIR/GodotBin "$@"

Some thoughts, and wrapping up

A Godot application showing a small sprite moving up and down on a sine wave. Behind the Godot Application is the Godot Editor, with the C# script for the sine moving displayed
all is good in the world, we now have sine waves.

Godot is really close to being a great starter tool for teaching C# based gamedev. It's not got any licensing issues (universities, and way more schools, can be odd when it comes to requiring sign in for use of apps), an integrated IDE, and separation of 2D & 3D modes, for when you just want to teach fundamentals in 2D.

But, I think more effort could be done into supporting this usecase where the person installing Godot may not have admin rights. Unity doesn't require you to install .NET, and the Unity Hub can totally work without admin rights, and lots of work goes into this.

This isn't just a Godot issue by the way - VS Code always prompts you to enter your password to install "Helper tools" on macOS, and so many hacks on macOS assume you have the rights to go change what has accessibility permissions.

But! Hopefully this post can help some people in a similar boat - including you, Mr Beast.


You must log in to comment.

in reply to @vallerie's post:

Is that my favourite geopolitical conflict starter and C# user Mr Beast? What about his doctor brother, Mr Breast? And what about his hungry sibling Mr Feast? And we can't be forgetting his brother that can only go in one direction, Mr East

so! i haven't used Unreal in this kind of situation. i imagine the biggest blocker will be xcode and the epic game store, but, i vaguely remember it not needing admin rights. xcode might prove problematic, but i also feel it could be fine.

however, i think given the download size of about 50 gigs, and the compilation time when writing C++, it's probably not viable for this situation unless the uni is already teaching unreal anyway - in which case your work is done for you!

Technically Unity itself comes bundled with a version of .NET/Mono, similarly to how it ships with its own internal version of the Android SDK & JDK. Which means (positive) you don't need to install .NET separately, but (negative) you use up more disk space with multiple copies of Unity or when other programs require .NET standard.

Likewise, the reason you can't open Apps from the finder and have them reflect the environment variable is because Finder does not load .bashrc/.zshrc/etc. — The OS itself has its own PATH variable, which then gets things appended to it when a terminal sources an rc or _profile file.

Be careful with changing package contents, btw. — Depending on how bundles are signed and configured you could run the risk of macOS thinking the application has been maliciously tampered with or platform incompatible and refusing to run it.

A cleaner way of going about it would be to write a wrapper bundle for Godot which launches it instead, with Godot nested inside, at least until Godot lets you specify a .NET installation. This would also make updates a lot easier as you won't get your launcher script overwritten.

(quick apologies if this seems like I'm pulling an "Um Actually,", I just find this topic interesting!)

first - i used to work at Unity! (please see attached image of me getting crushed at a Christmas party - they are absolutely lovely folks, even when their faces are pixelated)

as such, i'm familiar with how Unity bundles platform SDKs and Mono. the bundling situation is a bit more complicated than "Unity just bundles Mono!" - Unity uses it's own fork of mono, and then you have IL2CPP on top - but, yes, you're basically right here.

as for why i didn't incldue this, it's mostly that nuance does not play well with fun little posts! it's very much that if you're the kind of individual to have checked out Unity-Technologies/mono, that's chill, but it's not really super essential information when talking about Godot, .NET, and education environments. whether it's bundled, not-required, or using it's own fork that then comes with the engine is kind of a null point 😅

and yeah, you're absolutely correct on the Finder environment variable note, as well as being careful.

but, there's reasons for doing it this way:

  • this is a hack for education - i ultimately need this to work for 1 hour in maybe 5 weeks time, and I can validate it works on a locked down user on my up-to-date macOS
  • writing a full wrapper bundle is absolutely overkill
    • the time investment for that vs a simple shell script is non-zero
  • it's not the best vibe to do anything more than this quick hack, when it isn't the purpose of my workshop, and prep time is billable hours
  • if gatekeeper is locked down heavily, in about 10/15 minutes I can make maybe... 2 modifications (in bringing dotnet outside of the Godot .app, and then having the new launcher run xattr -d com.apple.qua... on the dotnet in the directory above)
    • this isn't an app for public distribution - i'm just copying it onto machines! so I can be super sure of the directory layout
    • then i can just resign this modified Godot app using my own Apple Developer Account to get it past gatekeeper

plus, if I'm in an environment that has gatekeeper locked down to prevent non-notarized / tampered apps from running, we might be having even more issues than .NET when it comes to gamedev 😅

ultimately - i find this all really fascinating, but there's ultimately a limit to what you can provide in a single post without having it degrade the reading experience and the point you're trying to get across. but, hopefully in future i'll share a bit more of this nuance! maybe in a little collapsable nuance section at the end, or a seperate draft post for that stuff.

writing a full wrapper bundle is absolutely overkill

You can appify shell scripts. Basically it'd be near identical to what you did, only Godot& .NET would be within the resources of another .app bundle that's just a shell script, icon, and info plist.

If you are fine with the pitfalls then that's good! I just know that others seeing this may not know of those pitfalls. (Also I am aware of Unity using a mono fork. If I'm not mistaken it used Mono before official .NET cross-platform was even a thing, yeah?)

huh, cool! thanks for the appify script, i'll keep that around. i genuinely had no idea that existed. do you know how appify plays with code signing and notarization? no worries if not, i can just test it myself when i have free time.

and yeah, absolutely about the pitfalls. but, i also didnt intend this as a guide, and moreso "hey, this is the wild journey you have to go on do to this very specific thing for education". i could have honestly not chosen Godot for this, and instead gone for a multitude of tools that assume the user is the owner of the machine.

on the mono note - yes! Unity's been using Mono for ages, certainly before cross-platform .NET. there's a hilarious in retrospect thread from 2007 where shaun manages to predict, but because of microsoft silverlight of all technologies.

keep in mind, most of the hisorical stuff is wrapped in healthy "i believe" - this was 17/18 years ago, and defo before my time - I worked at Unity from 2022 to 2023. Also, I would be worried if I was working there, because my focus was less so making games, more just playing them - specifically, trying to convince my parents to let me use the family computer to play Lego Island.

Slightly related - I was told stories of someone wheeling in an old PowerPC mac, and finding a pirated copy of Unity 1 (pirated because that's easier than building it yourself, and the licensing is probably dead now). This then became a fun little competition to see who in the office could use 1.0.

Not sure about the code signing, but in theory you could create an install script marked as executable that appifies the launcher script and moves all the assets into the bundle, thus making the bundle created by the local machine. Worst case.

Likewise, make sure the script is an .sh file or similar. I have learned that Apple Silicon will complain that the app "isn't compatible" with the platform if the appified script is extensionless as I used to do (extensionless worked the same but looked nicer). Not sure why but eh.