I know it's my first post, so I apologize in advance for anything I do incorrectly. This is a topic I've given a good deal of thought to, and I want the community's opinion on what the best way to add Linux compatibility would be.
Introduction
Since the announcement of osu! becoming open source, I've been thinking about how to best make osu! available natively for Linux. Peppy's blog post on osu! going open source (http://blog.ppy.sh/post/143727030323/demystifying-open-source-osu) mentioned interest in having the community bring the game to different platforms. So I think it would be a good time to discuss how to best structure it all. Unix-like systems are very different than Windows, so we should try to make osu! play nicely with these sorts of environments. For instance, following the Linux Filesystem Hiearchy (http://www.tldp.org/LDP/Linux-Filesystem-Hierarchy/html/) and aiming for POSIX compatibility are important to making osu! run like any other native program.
osu! is written in C#, so the natural choice for cross-platform compilation is Mono (http://www.mono-project.com/). When I tried compiling the osu!sdk, it appeared to depend on the Microsoft XNA framework, which could be provided by Monogame (http://www.monogame.net/). I'm sure there will be other dependency difficulties, but Mono is well-supported, so I'm sure we'll find some cross-platform solution as we start seeing more the code.
The rest of this post are my ideas on how osu! can be \*nix friendly. I'm making this post to start discussion on the subject, and so I appreciate any commentary or criticism of my ideas.
Basics
Every binary on a Unix-like system should, at the very least:
General file placement
Binaries and libraries generally exist in their own directory inside "/usr/lib", and static resources should exist in "/usr/share", so osu! should use "/usr/lib/osu" and "/usr/share/osu". Side note, while we could name the directories "/usr/lib/osu!" and "/usr/share/osu!", I feel we should avoid doing so because (1) using weird characters in "/usr" is frowned upon and (2) '!' is a special character in various shells and there's not point introducing unnecessary headache.
There should be an executable file on the $PATH to allow for easy invocation, and the most obvious choice would be "/usr/bin/osu" (Again, no exclamation point for the reasons named above). I think it should be a symbolic link to "/usr/lib/osu/osu!.exe", where the actual binaries are for reasons I'll discuss in "Updates and builds". (Also I think it's ok for the file to have a '!' character because you're not invoking the file directly from a shell and I want to keep naming conventions as similar as I can)
"/usr/lib/osu" should be only binaries, and "/usr/share/osu" should not have dynamic data, so data files like replays and databases should be located elsewhere. See "Data file locations".
Updates and builds
On Windows, it is the responsibility of every application to keep itself up-to-date. Linux distros provide a nice program called the package manager, which automates this process in a centralized and organized way. For those who don't know, a package manager is a program that you use to install nearly all the software on your computer, and keeps track of the files owned by each program you install. Therefore, making this port play nicely with the package manager is quite important, and makes things much easier in the long term.
osu! has its own update system built-in, which works quite well on Windows. However, I this is not ideal on Linux, as system upgrades should update all the software on your computer. The way I think of resolving this is to disable the osu! auto-updater by default (maybe make an option for it) and release changes as package updates, so they can be updated and upgraded along with the rest of the system. In addition, it provides the benefits of easily keeping track of dependencies and allowing downgrading versions in case the latest has issues.
One issue this create is that having different builds (cutting-edge, stable-fallback, etc.) is more difficult, since we'll need to have the package manager provide this. Here two solutions I thought of:
Each build will be its own package, such as "osu-stable-latest" or "osu-beta", all of which provide "osu" and conflict with each other. Very simple, but I think this puts too much of a burden on package maintainers having to work with lots of different packages.
The other possibility is to have the one true "osu" package have all the builds in it, but use a method of swapping which binaries are actually in use. I think a good solution to this is to use symbolic links. Each different build would have its own directory within "/usr/lib/osu":
Inside "/usr/lib/osu" itself there would be all the files necessary to run the program like usual, but they would actually be symbolic links to the real binary. This way changing the build from, for example, "stable-fallback" to "stable-latest" would just require the replacement of the symbolic links. A person running "stable-fallback" would have a "/usr/lib/osu" directory that looks like this: (A "->" refers to a symbolic link)
Location of songs and skins
Program resources are generally located in "/usr/share", meaning that songs and skins would be located in "/usr/share/osu/songs" and "/usr/share/osu/skins", respectively. However, there could be some merit to storing these files in "~/.osu".
Reasons for "/usr/share/osu":
Unix has always been a multi-user system, so I think it's good design to set up the file structure in such a way that it allows multiple users to play at the same time. This can be accomplished by segregating data files like scores into user-specific folders. (Which it should anyways, since the contents of "/usr" should not store non-static data.
This is the part I'm least sure about. The FHS specifies "/var/game" as a location for "variable data relating to games in /usr". (http://www.tldp.org/LDP/Linux-Filesystem-Hierarchy/html/var.html) The other location where it would be appropriate would be in the user's home directory in "~/.osu", if we decide to go that route. (See above). I've listed what I think each would look like.
The big concern I have with "~/.osu" is bloat. I don't think having a dotfolder in your home directory that is more than a gigabyte is good, and should be avoided if possible.
Run time files
Temporary files should be located in "/tmp" or "/run". Since multiple users may be running osu!, the directory should be user-specific. So either "/tmp/$USER-osu" or "/run/user/$UID/osu" should be used. (Some systems lack a "/run", so in those cases "/var/run" should be used instead).
There are a few files that could reside in this directory other than temporary files:
"/run/user/$USER/osu/pid" - PID (process id) file for osu!, to easily determine if it's already running
"/run/user/$USER/osu/fifo" - A control FIFO (aka named pipe) to allow scripts to send simple commands to osu!
"/run/user/$USER/osu/socket" - A control socket to allow programs to interact with and send commands to osu!. Could be extended to add the API as well.
Linux-specific features
Finally, a list of a few random things I thought of that may or may not be worth looking into:
Introduction
Since the announcement of osu! becoming open source, I've been thinking about how to best make osu! available natively for Linux. Peppy's blog post on osu! going open source (http://blog.ppy.sh/post/143727030323/demystifying-open-source-osu) mentioned interest in having the community bring the game to different platforms. So I think it would be a good time to discuss how to best structure it all. Unix-like systems are very different than Windows, so we should try to make osu! play nicely with these sorts of environments. For instance, following the Linux Filesystem Hiearchy (http://www.tldp.org/LDP/Linux-Filesystem-Hierarchy/html/) and aiming for POSIX compatibility are important to making osu! run like any other native program.
osu! is written in C#, so the natural choice for cross-platform compilation is Mono (http://www.mono-project.com/). When I tried compiling the osu!sdk, it appeared to depend on the Microsoft XNA framework, which could be provided by Monogame (http://www.monogame.net/). I'm sure there will be other dependency difficulties, but Mono is well-supported, so I'm sure we'll find some cross-platform solution as we start seeing more the code.
The rest of this post are my ideas on how osu! can be \*nix friendly. I'm making this post to start discussion on the subject, and so I appreciate any commentary or criticism of my ideas.
Basics
Every binary on a Unix-like system should, at the very least:
- Accept "--help" and "--version" as options.
- Have a man page.
- Respond appropriately to SIGTERM (and other signals).
General file placement
Binaries and libraries generally exist in their own directory inside "/usr/lib", and static resources should exist in "/usr/share", so osu! should use "/usr/lib/osu" and "/usr/share/osu". Side note, while we could name the directories "/usr/lib/osu!" and "/usr/share/osu!", I feel we should avoid doing so because (1) using weird characters in "/usr" is frowned upon and (2) '!' is a special character in various shells and there's not point introducing unnecessary headache.
There should be an executable file on the $PATH to allow for easy invocation, and the most obvious choice would be "/usr/bin/osu" (Again, no exclamation point for the reasons named above). I think it should be a symbolic link to "/usr/lib/osu/osu!.exe", where the actual binaries are for reasons I'll discuss in "Updates and builds". (Also I think it's ok for the file to have a '!' character because you're not invoking the file directly from a shell and I want to keep naming conventions as similar as I can)
"/usr/lib/osu" should be only binaries, and "/usr/share/osu" should not have dynamic data, so data files like replays and databases should be located elsewhere. See "Data file locations".
Updates and builds
On Windows, it is the responsibility of every application to keep itself up-to-date. Linux distros provide a nice program called the package manager, which automates this process in a centralized and organized way. For those who don't know, a package manager is a program that you use to install nearly all the software on your computer, and keeps track of the files owned by each program you install. Therefore, making this port play nicely with the package manager is quite important, and makes things much easier in the long term.
osu! has its own update system built-in, which works quite well on Windows. However, I this is not ideal on Linux, as system upgrades should update all the software on your computer. The way I think of resolving this is to disable the osu! auto-updater by default (maybe make an option for it) and release changes as package updates, so they can be updated and upgraded along with the rest of the system. In addition, it provides the benefits of easily keeping track of dependencies and allowing downgrading versions in case the latest has issues.
One issue this create is that having different builds (cutting-edge, stable-fallback, etc.) is more difficult, since we'll need to have the package manager provide this. Here two solutions I thought of:
Each build will be its own package, such as "osu-stable-latest" or "osu-beta", all of which provide "osu" and conflict with each other. Very simple, but I think this puts too much of a burden on package maintainers having to work with lots of different packages.
The other possibility is to have the one true "osu" package have all the builds in it, but use a method of swapping which binaries are actually in use. I think a good solution to this is to use symbolic links. Each different build would have its own directory within "/usr/lib/osu":
- /usr/lib/osu/beta
- /usr/lib/osu/cutting-edge
- /usr/lib/osu/stable-latest
- /usr/lib/osu/stable-fallback
- etc.
Inside "/usr/lib/osu" itself there would be all the files necessary to run the program like usual, but they would actually be symbolic links to the real binary. This way changing the build from, for example, "stable-fallback" to "stable-latest" would just require the replacement of the symbolic links. A person running "stable-fallback" would have a "/usr/lib/osu" directory that looks like this: (A "->" refers to a symbolic link)
- /usr/lib/osu/osu!.exe -> stable-fallback/osu!.exe
- /usr/lib/osu/something.dll -> stable-fallback/something.dll
- /usr/lib/osu/something2.dll -> stable-fallback/something2.dll
- etc.
Location of songs and skins
Program resources are generally located in "/usr/share", meaning that songs and skins would be located in "/usr/share/osu/songs" and "/usr/share/osu/skins", respectively. However, there could be some merit to storing these files in "~/.osu".
Reasons for "/usr/share/osu":
- Installed beatmaps and skins are available to all users
- Prevents the home directory from getting too big
- No special permissions required (see the root:games explanation above)
- Acts as a kind of "portable mode" by just moving your ".osu" around
Unix has always been a multi-user system, so I think it's good design to set up the file structure in such a way that it allows multiple users to play at the same time. This can be accomplished by segregating data files like scores into user-specific folders. (Which it should anyways, since the contents of "/usr" should not store non-static data.
This is the part I'm least sure about. The FHS specifies "/var/game" as a location for "variable data relating to games in /usr". (http://www.tldp.org/LDP/Linux-Filesystem-Hierarchy/html/var.html) The other location where it would be appropriate would be in the user's home directory in "~/.osu", if we decide to go that route. (See above). I've listed what I think each would look like.
- /var/games/osu
- /var/games/osu/$USER/chat
- /var/games/osu/$USER/data
- /var/games/osu/$USER/db/collection.db
- /var/games/osu/$USER/db/osu!.db
- /var/games/osu/$USER/log
- /var/games/osu/$USER/replays
- ~/.osu
- ~/.osu/chat
- ~/.osu/db
- ~/.osu/log
- ~/.osu/replays
- ~/.osu/screenshots
The big concern I have with "~/.osu" is bloat. I don't think having a dotfolder in your home directory that is more than a gigabyte is good, and should be avoided if possible.
Run time files
Temporary files should be located in "/tmp" or "/run". Since multiple users may be running osu!, the directory should be user-specific. So either "/tmp/$USER-osu" or "/run/user/$UID/osu" should be used. (Some systems lack a "/run", so in those cases "/var/run" should be used instead).
There are a few files that could reside in this directory other than temporary files:
"/run/user/$USER/osu/pid" - PID (process id) file for osu!, to easily determine if it's already running
"/run/user/$USER/osu/fifo" - A control FIFO (aka named pipe) to allow scripts to send simple commands to osu!
"/run/user/$USER/osu/socket" - A control socket to allow programs to interact with and send commands to osu!. Could be extended to add the API as well.
Linux-specific features
Finally, a list of a few random things I thought of that may or may not be worth looking into:
- Fancy IPC (inter-process communication, see above)
- Wayland support
- Conf-style config files.
- DBus server
- X11-based cursor (I think X allows for very large cursor sizes)
- osu!-related scripts in "/usr/bin" (backing up beatmaps, etc.)