11-01-2015, 12:05 AM
I'd like to open a discussion about implementing the various kinds of commands. Right now I'm aware of three distinct kinds that each has a slightly different behavior:
- console commands (given by the server owner directly on the server's console screen)
- in-game commands (given by any player connected to the server)
- command block commands (executed by command blocks in the game)
The console commands have no connection to any player or world. The in-game commands are usually bound to a specific player or world. The command block commands are somewhere in between - they are bound to a world, but don't have any player connection.
Cuberite currently implements only the first two kinds. They have separate API functions that are used to register them, and have different callback signatures; it is possible to register a console command without its in-game counterpart and vice versa. Now the question is, how do we add the third kind, command block commands? Do we add third set of API for it, or do we try to bend one of the existing ones towards it?
One more thought about the command handlers. With the advent of InfoReg.lua usage, they command handlers in the plugins are actually slowly drifting towards a common signature. The console commands are currently (erroneously) called with an extra parameter that is always nil, in the place where the in-game command handlers have their cPlayer parameter. This was an accident in my initial implementation, but has gone too long unnoticed and it's kinda late to fix it. It also kinda makes sense - there's no cPlayer object for the command, so just send a nil instead. The command block commands could re-use this and send the originating command block instead of the cPlayer object.
Return values of the command handlers are currently slightly different as well. In-game commands return only status - was it executed or not? Console commands return status, and an optional message to output to the console as the command's result. Command blocks' command handlers should also output some form of a result string. Should we unify this behavior somehow?
Side note regarding console command handlers. There is a growing need of an "semi-asynchronous" command handling - the command handler itself terminates, but it needs to process something on the background (typically wait for a chunk to load) and then finalize itself. A similar situation could develop with in-game commands (e. g. teleport command waiting for the chunks to load before teleporting). A solution has been proposed to this - add another parameter that handles the command output and termination; as long as the command doesn't explicitly terminate, more output can be sent to the object.
Personally, I'm inclined to take this opportunity (adding another command kind) and unify the callbacks' signatures, as well as add the CommandOutput object as a parameter. I'd keep the registration API separate, though.
Thoughts?
- console commands (given by the server owner directly on the server's console screen)
- in-game commands (given by any player connected to the server)
- command block commands (executed by command blocks in the game)
The console commands have no connection to any player or world. The in-game commands are usually bound to a specific player or world. The command block commands are somewhere in between - they are bound to a world, but don't have any player connection.
Cuberite currently implements only the first two kinds. They have separate API functions that are used to register them, and have different callback signatures; it is possible to register a console command without its in-game counterpart and vice versa. Now the question is, how do we add the third kind, command block commands? Do we add third set of API for it, or do we try to bend one of the existing ones towards it?
One more thought about the command handlers. With the advent of InfoReg.lua usage, they command handlers in the plugins are actually slowly drifting towards a common signature. The console commands are currently (erroneously) called with an extra parameter that is always nil, in the place where the in-game command handlers have their cPlayer parameter. This was an accident in my initial implementation, but has gone too long unnoticed and it's kinda late to fix it. It also kinda makes sense - there's no cPlayer object for the command, so just send a nil instead. The command block commands could re-use this and send the originating command block instead of the cPlayer object.
Return values of the command handlers are currently slightly different as well. In-game commands return only status - was it executed or not? Console commands return status, and an optional message to output to the console as the command's result. Command blocks' command handlers should also output some form of a result string. Should we unify this behavior somehow?
Side note regarding console command handlers. There is a growing need of an "semi-asynchronous" command handling - the command handler itself terminates, but it needs to process something on the background (typically wait for a chunk to load) and then finalize itself. A similar situation could develop with in-game commands (e. g. teleport command waiting for the chunks to load before teleporting). A solution has been proposed to this - add another parameter that handles the command output and termination; as long as the command doesn't explicitly terminate, more output can be sent to the object.
Personally, I'm inclined to take this opportunity (adding another command kind) and unify the callbacks' signatures, as well as add the CommandOutput object as a parameter. I'd keep the registration API separate, though.
function HandleIGCmdHello(a_Split, a_Player, a_EntireCmd, a_CommandOutput) -- In-game command handler, a_Player is a cPlayer object return true, "SomeMessage" -- SomeMessage is sent to the player; nothing gets sent if an empty string or nil is returned end function HandleConCmdHello(a_Split, a_Nil, a_EntireCmd, a_CommandOutput) -- Console command handler, a_Nil is always nil return true, "SomeMessage" -- SomeMessage is output to the console end function HandleCBCmdHello(a_Split, a_CommandBlockEntity, a_EntireCmd, a_CommandOutput) -- Command block command handler, a_CommandBlockEntity is the cCommandBlockEntity executing the command return true, "SomeMessage" -- SomeMessage is set as the command's output (shown in the UI) endIf the command handler returns a string as the second parameter, the command is assumed to have terminated, the server automatically sets a_CommandOutput as terminated. If only the bool value is returned, the command output stays "open" and the plugin is expected to call a_CommandOutput:Terminate() at some point.
Thoughts?