godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.14k stars 96 forks source link

Allow restricting exported game to be a single-instance process #10208

Open lostminds opened 3 months ago

lostminds commented 3 months ago

Describe the project you are working on

An editor application

Describe the problem or limitation you are having in your project

On windows if you select the top item in the task-bar menu for a running exported godot project this will create a new instance of the game application, so you now have two copies of the game running. While there may be testing cases where this is desirable, most games I would guess are not meant to have multiple instances running at the same time and I reported this as a bug.

While trying to implement file type support for my project, to allow opening files via drag and drop or double click from the OS, I encountered the issue again: When opening a file from the OS while the application was running, the file would not be sent to the running process and activate that. Instead a new instance of the application would be launched to open the file sent from the OS. Again this was an unexpected and in my case undesirable duplication of the application process, since it is not designed to have multiple running instances. In this case the duplication of the processes happened on both windows and macOS when files were opened, and on macOS this is especially out of place with how applications usually work.

After discussions it turns out that this is because exported Godot games aren't restricted to having a single running instance. However, in my case, and I'm guessing in most released game cases, this is not desirable and will only cause user confusion (at best) and corrupted states (at worst) if multiple instances are reading/writing to the same resources at the same time.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

While having multiple instances running may be useful is some cases, there should at least be a way to turn this off in exported projects for when it is not.

So I'm proposing to add a new project setting for controlling if you want to allow the exported project to run restricted to a single instance, or if multiple instances of the game should be allowed to run in parallel.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

A new project setting, for example allow_multiple_instances in Application/run is used to control that the exported binary is marked appropriately for each platform as allowing multiple instances or restricting to a single instance.

For backwards compatibility this new setting should then be set to true as default, as this seems to be the current implementation.

However, my guess is that a better default would probably be no, even if this would break compatibility. Since for most exported projects the developers probably just don't know multiple instances of the game can be launched, but that doing so might cause issues.

If this enhancement will not be used often, can it be worked around with a few lines of script?

No

Is there a reason why this should be core and not an add-on in the asset library?

Project export is a core functionality, and this is pretty low level.

lostminds commented 3 months ago

A method to implement this if the OS starts multiple instances could be to add a process_info file in user:// where the ID of the running process is saved while a process is running, and removed when the process exits normally. First thing when launching a new process this file can be checked if multiple processes aren't allowed, validating if the process is still running. And if so instead send a message to the original running process to forward the launch arguments for the new duplicate process (for cases like opening a new file) and then terminating the new process before staring up the engine.

I've considered implementing something like this in a script in a project where I'd like this single-instance restriction, since it might be possible to do at least the first steps of recording and validating if the process is running using OS.get_process_id() and OS.is_process_running(). However, it's less than ideal since this code will then be run after the engine and project has started up, which takes a while and will looks quite strange. And communicating back to the original process will also likely require some slightly hacky solution like having a shared message file that is periodically monitored for changes.

Calinou commented 3 months ago

A method to implement this if the OS starts multiple instances could be to add a process_info file in user:// where the ID of the running process is saved while a process is running, and removed when the process exits normally.

IPC mechanisms like dbus on Linux make this file-based approach redundant. I believe all desktop platforms have something like this in place.

Godot already uses dbus on Linux for things like screensaver inhibition.

lostminds commented 1 month ago

If this would be implemented this would also be another strong argument for a files_opened signal as proposed and discussed in this PR to add one for sandboxed apps on macOS, https://github.com/godotengine/godot/pull/94909 but make it more general for all desktop platforms. As it would then be needed for other platforms as well to accept opened files from the OS while they are running.