Skip to content

Conversation

@tonygiang
Copy link
Contributor

@tonygiang tonygiang commented Apr 7, 2021

I use the Command Console feature extensively for work projects. Among the commands I have written, I identified a few commands that are universally helpful to the purpose of runtime testing no matter which project I use this package for. It makes sense to me that these universally-helpful commands should be shipped by default. This can be the beginning of more than just help and sysinfo being shipped by default with In-game Debug Console (IGDC). The command groups I created are:

PlayerPrefsCommands: There is actually no readily-available tool to read and modify PlayerPrefs in-game for Unity. So I thought: with very minimal code addition, IGDC could just fill that gap. The commands are now prefs.int, prefs.float, prefs.string, prefs.delete, prefs.clear.

TimeCommands: Just a command to get and set the game's time scale value and to read the current time scale: time.scale. I use this to manipulate time during debug session without creating an extra button on the UI for each scene context.

SceneCommands: 4 commands to load, unload and restart scenes. They are scene.load, scene.loadasync, scene.unload, scene.restart. scene.load and scene.loadasync accept a load mode parameter too.

Because IGDC is particularly useful for mobile test environment where typing is really a chore, I tried to make command names short and parameters as case-insensitive as possible. We can update the documentation to reflect the new commands later, but fortunately, help command already listed all commands by default. The command names are denoted with "namespaces" as you can see. This was symptomatic of our work projects due to short command names, high chance of command naming conflicts, which led to us segmenting the commands into namespaces. Turns out IGDC has no problem accepting . character in command names so we rolled with it. You can amend these names if you don't like the namespaces.

Copy link
Owner

@yasirkula yasirkula left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the PR! Please take a look at the suggested changes.

}

[ConsoleMethod( "scene.unload", "Unload a scene", "sceneName" )]
public static void UnloadScene( string sceneName ) =>
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Old Unity versions that use C# 4.0 doesn't support this method declaration syntax, it needs to be fixed
  • Similar to scene.load, this command should have a separate scene.unloadasync variant
  • A helper scene.restart command would also be nice. It shouldn't take any parameters and simply reload the currently active scene. You can define a separate scene.restartasync variant, if you wish

{
if ( SceneManager.GetSceneByName( sceneName ).IsValid() )
{
Debug.Log( $"Scene {sceneName} already loaded" );
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Old Unity versions that use C# 4.0 doesn't support interpolated strings, it needs to be fixed. I plan to maintain Unity 5.6 support for as long as possible.

Comment on lines 20 to 24
[ConsoleMethod( "pp.set",
"Set the value of a PlayerPrefs field",
"key",
"type",
"value" )]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parameter names in ConsoleMethod are optional. Since the entered parameter names are the same as the actual parameter names here, we can simply omit these optional parameter names from ConsoleMethod and convert it to a single-line attribute.

{
public class PlayerPrefsCommands
{
[ConsoleMethod( "pp.get",
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of pp, prefs would be much easier to understand.

public class SceneCommands
{
[ConsoleMethod( "scene.load", "Load a scene", "sceneName", "mode" )]
public static void LoadScene( string sceneName, string mode )
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • I see that you've defined mode's type as string so that it can be parsed case-insensitively. I'll update the internal enum parse code so that it will support case insensitive enums. So please change mode's type to LoadSceneMode
  • This function should be split into 4 different functions: 2 of them use LoadScene and the other 2 use LoadSceneAsync (command name can be "scene.loadasync"). And 2 of these functions should take LoadSceneMode mode parameter while the rest should only take string sceneName parameter

Comment on lines 7 to 11
[ConsoleMethod( "time.scale", "Set the Time.timeScale value", "value" )]
public static void SetTimeScale( float value ) => Time.timeScale = value;

[ConsoleMethod( "time.currentscale", "Get the current Time.timeScale value" )]
public static float GetCurrentScale() => Time.timeScale;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • These can both be time.scale. The console already supports console method overloads
  • While assigning to timeScale, value must be Mathf.Max'ed to make sure that it is never negative

"Get the value of a PlayerPrefs field",
"key",
"type" )]
public static string PlayerPrefsGet( string key, string type )
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like the "string type" approach. How about this:

  • prefs.int: is connected PlayerPrefsGetInt and PlayerPrefsSetInt functions. So if user types prefs.int key, it returns that key's int pref. If user types prefs.int key 1, it sets that key's int pref to 1.
  • Similarly, prefs.float and prefs.string

if ( type.ToLower() == "int" ) PlayerPrefs.SetInt( key, int.Parse( value ) );
}

[ConsoleMethod( "pp.del", "Delete a PlayerPrefs field", "key" )]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prefs.delete would be more preferable

public class PlayerPrefsCommands
{
[ConsoleMethod( "pp.get",
"Get the value of a PlayerPrefs field",
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use present tense to be consistent with help and sysinfo. Instead of Get, prefer Returns

…4 compatible, omit optional parameter names in command attributes, add scene.restart command.
@tonygiang
Copy link
Contributor Author

I didn't know about command overloading, good to know. I'm incorporating your requested changes, but I do have one concern about picking async/sync mode for scene unload: SceneManager.UnloadScene has been obsoleted by Unity with the following warning message: Use SceneManager.UnloadSceneAsync. This function is not safe to use during triggers and under other circumstances. See Scripting reference for more details.

Are you sure you still want a sync mode for scene unload moving forward?

@yasirkula
Copy link
Owner

Didn't know about that. We don't need UnloadScene in that case.

@tonygiang
Copy link
Contributor Author

The requested changes are live for review.

@yasirkula
Copy link
Owner

Thank you for the changes!

@yasirkula yasirkula merged commit dda9bd3 into yasirkula:master Apr 10, 2021
yasirkula added a commit that referenced this pull request Feb 18, 2024
…s better to have these commands opt-in rather than opt-out. Built-in commands can be reactivated by adding IDB_ENABLE_HELPER_COMMANDS compiler directive in Player Settings
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants