godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.15k stars 97 forks source link

Add the ability to read `stdin` from the console #2322

Closed ArronGIT closed 2 years ago

ArronGIT commented 3 years ago

Describe the project you are working on

like an IDE, a text editor, after editing a file, passes the file address to another program for processing and receiving the result from it

Describe the problem or limitation you are having in your project

there is only writing to the console print (), but no input () reading from the console

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

it was not bad to implement reading as in python

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

var text = input () var num = int (input())

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

in the script, I did not find the read from console function, most likely there is an opportunity to do this through native code, but I am not good at this

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

if there is a tutorial then there is no reason.

Calinou commented 3 years ago

See also #216.

YuriSizov commented 3 years ago

It's very cool to use Godot for non-gaming apps, but since this is a game engine first and foremost, what would be the use-case for gaming or game development?

Zireael07 commented 3 years ago

MUD engines come to mind immediately, as well as debug/cheat consoles.

Calinou commented 3 years ago

Being able to read stdin would be useful for dedicated game servers where you can input commands as an administrator (see Minecraft).

In the meantime, you could make the server read from a text file every so often (every 10-30 seconds, possibly more often if a command was recently input). If the file isn't empty, execute its contents as a command and remove the file's contents (but do not remove the file entirely). With modern text editors reloading files automatically when they change on the filesystem, the user experience won't be so bad (while still not being great).

Another alternative is to use the WebSocketServer class and send command requests using a WebSockets client. Or you can use a REST API by hosting a HTTP server from the game server with a GDScript HTTP server implementation.

merriam commented 3 years ago

In Python, reading keys from stdin is an infrequently answered question. There are dozens of StackOverflow questions with variations of "how do a read a key in Python" and most are unanswered or have non-working answers. You get dozens of questions that reflect some of the underlying issues about buffering and compatibility.

Limitations are hard to understand. Major differences are reading characters when line buffered versus character buffered versus a piped stream; reading when the originating terminal, a created child window, or other window has focus; reading individual characters and its relationship to line buffering; buffer lengths and refill policies; and interactions between event libraries (like Godot) and stdin. For example, read(1) will often return one key, but Python will force line buffering, which is also forced by the OS, but Godot would probably remove the key preemptively to fire keyboard events, but pushing back into that buffer creates ordering problems.

Handling is specific to minor versions of the operating system. The answers specific to MacOs 10.15 are not the same as MacOS 10.14, and permission requirement changed slightly during MacOS 10.14 updates. On Windows, an extra DLL is required from Microsoft to read the keyboard. It's a drain on energy dealing with keyloggers built in your game engine. Many answers depend on specific operating system settings, with MacOS being particularly, and increasingly, persnickety about reading the keyboard from anything but a newly created window.

I feel that there needs to be a strong user case for this feature.

sesopenko commented 3 years ago

Reading stdin would be great. Websockets provide a workaround but they're far more complex than simply reading stdin. Management of game servers in an MMO is a good example. If one could send json strings through stdin to give commands to a server instance, it'd be possible to orchestrate game systems across multiple multiplayer servers, all running as sub-processes of a larger system.

Faless commented 2 years ago

It's very cool to use Godot for non-gaming apps, but since this is a game engine first and foremost, what would be the use-case for gaming or game development?

Just come across this proposal with a decent(?) use case. Now that we have headless mode, it's pretty easy to create command line tools in GDScript to manage your game backend (in my case, creating/deleting/backing up a database). Since some of those operations can be destructive (drop database) or costly (starting a backup process) it is pretty common to add at least a confirmation prompt for them.

Right now I'm faking this with a very ugly hack, forcing the script to be run with the local debugger active (--debug) adding a breakpoint right after asking confirmation, and letting the user continue (c) or quit (q) from the debugger.

I think having something like python input() (which blocks execution) could help in this case (and others where you might want to read some information, e.g. entering the DB password, which I now read from an environment variable)

My ugly hack:

extends SceneTree

func _initialize():
    if not EngineDebugger.is_active():
        push_error("Please run the script with the --debug option")
        quit.call_deferred()
        return
    var options = {
        create = true,
        drop = false,
        cascade = false
    }
    print("Creating database at %s with options %s. Press 'c' to continue, 'q' to exit" % [URL, options])
    breakpoint
Calinou commented 2 years ago

I think having something like python input() (which blocks execution) could help in this case (and others where you might want to read some information, e.g. entering the DB password, which I now read from an environment variable)

Blocking execution is problematic for dedicated server consoles that can accept commands at any times, so it should be optional.

Faless commented 2 years ago

Blocking execution is problematic for dedicated server consoles that can accept commands at any times, so it should be optional.

Yeah, the "dedicated server console" is a different use case and honestly I'm not sure it's a good idea to handle both with the same function.

It's also kinda weird to have a console attached to a dedicated server process directly since they are usually spawned as system services. You'd probably need something like screen or tmux to detach/attach to it, and having dealt with those in the past, I'd rather use a dedicated admin process that communicate with it via TCP/websocket/UNIX socket/etc like most dedicated servers do.

akien-mga commented 2 years ago

This seems to already be implemented as OS::get_stdin_string(bool p_block). It would just need to be exposed to bindings via core_bind::OS.