├── .gitignore ├── CHANGELOG.md ├── CHANGELOG.md.meta ├── Documentation~ └── images │ └── playmodeinspector.png ├── LICENSE.md ├── LICENSE.md.meta ├── README.md ├── README.md.meta ├── Runtime.meta ├── Runtime ├── CommandLine.PlayModeInspector.cs ├── CommandLine.PlayModeInspector.cs.meta ├── CommandLine.cs ├── CommandLine.cs.meta ├── Unity.CommandLine.Runtime.asmdef └── Unity.CommandLine.Runtime.asmdef.meta ├── Tests.meta ├── Tests ├── Editor.meta └── Editor │ ├── CommandLineTests.cs │ ├── CommandLineTests.cs.meta │ ├── Unity.CommandLine.Editor.Tests.asmdef │ └── Unity.CommandLine.Editor.Tests.asmdef.meta ├── package.json └── package.json.meta /.gitignore: -------------------------------------------------------------------------------- 1 | [Aa]rtifacts/ 2 | [Bb]uild/ 3 | [Ll]ibrary/ 4 | [Oo]bj/ 5 | [Tt]emp/ 6 | [Ll]og/ 7 | [Ll]ogs/ 8 | .vs 9 | .vscode 10 | .idea 11 | .DS_Store 12 | *.aspx 13 | *.browser 14 | *.csproj 15 | *.exe 16 | *.ini 17 | *.map 18 | *.mdb 19 | *.npmrc 20 | *.pyc 21 | *.resS 22 | *.sdf 23 | *.sln 24 | *.sublime-project 25 | *.sublime-workspace 26 | *.suo 27 | *.userprefs 28 | .npmrc 29 | *.leu 30 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this package are documented in this file. 3 | 4 | The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) 5 | and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). 6 | 7 | ## [1.2.0] - 2023-04-16 8 | ### Added 9 | - Added new Unity Runner Test, that checks when querying a non-existent CommandLine option, that it returns the specified defaultValue. 10 | 11 | ### Fixed 12 | - When querying a non-existent CommandLine option, it now returns the specified defaultValue, instead of the defaultValue from the first method call. 13 | 14 | Previous behavior: 15 | ```csharp 16 | CommandLine.GetString("-KeyDoesNotExist", "Hello"); // returns "Hello" (correct) 17 | CommandLine.GetString("-KeyDoesNotExist", "World"); // returns "Hello" (wrong) 18 | ``` 19 | 20 | New/fixed behavior: 21 | ```csharp 22 | CommandLine.GetString("-KeyDoesNotExist", "Hello"); // returns "Hello" (correct) 23 | CommandLine.GetString("-KeyDoesNotExist", "World"); // returns "World" (correct) 24 | ``` 25 | 26 | 27 | ## [1.1.0] - 2021-05-08 28 | ### Added 29 | - Added ```CommandLine.onInitialized``` event that's invoked after calling ```CommandLine.Init()```. 30 | 31 | ## [1.0.0] - 2020-11-07 32 | - First public release 33 | -------------------------------------------------------------------------------- /CHANGELOG.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a16744cd071fe5e45ba90ddb3a0d9e65 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Documentation~/images/playmodeinspector.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pschraut/UnityCommandLine/7fbd238e1633a8f146ea4a1f3ea2cd05d724224f/Documentation~/images/playmodeinspector.png -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-2024 Peter Schraut (http://www.console-dev.de) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /LICENSE.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5ca650bc1cf5ed244b1d009e9cf6775c 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CommandLine for Unity 2 | 3 | The CommandLine for Unity package provides the ability to query key-value pairs, very similar to Unity's [PlayerPrefs](https://docs.unity3d.com/ScriptReference/PlayerPrefs.html) API. 4 | The CommandLine options can be stored in a text file, for example: 5 | ```csharp 6 | -InfiniteHealth true 7 | //-InfiniteArmor true 8 | -DamageMultiplier 8.5 9 | ``` 10 | In order to query if ```-InfiniteHealth``` is set, you use: 11 | ```csharp 12 | CommandLine.GetBool("-InfiniteHealth", false); 13 | ``` 14 | The first argument ```-InfiniteHealth``` represents the key. The second argument, in this case ```false```, represents the default value that is returned, 15 | if the key could not be found in the commandline. 16 | 17 | CommandLine supports the following types: 18 | * ```float``` 19 | * ```int``` 20 | * ```bool``` 21 | * ```enum``` 22 | * ```string``` (use quotes to provide strings with spaces) 23 | 24 | CommandLine supports C-like comments in your text file: 25 | * ```// line comments``` 26 | * ```/* block comments */``` 27 | 28 | 29 | # Installation 30 | 31 | As of Unity 2019.3, Unity supports to add packages from git through the Package Manager window. 32 | In Unity's Package Manager, choose "Add package from git URL" and insert one of the Package URL's you can find below. 33 | 34 | ## Package URL's 35 | 36 | | Version | Link | 37 | |----------|---------------| 38 | | 1.2.0 | https://github.com/pschraut/UnityCommandLine.git#1.2.0 | 39 | | 1.1.0 | https://github.com/pschraut/UnityCommandLine.git#1.1.0 | 40 | | 1.0.0 | https://github.com/pschraut/UnityCommandLine.git#1.0.0 | 41 | 42 | 43 | # Credits 44 | 45 | If you find this package useful, please mention my name in your credits screen. 46 | Something like "CommandLine by Peter Schraut" or "Thanks to Peter Schraut" would be very much appreciated. 47 | 48 | 49 | # Integration 50 | 51 | * Create a text file in your project that is used to provide commandline options. I prefer ```Assets/StreamingAssets/CommandLine.txt```, but you can use any path you like. 52 | * Load the commandline file using your favorite API during application/game startup. 53 | * Call ```CommandLine.Init(text)``` with the text of the commandline file. 54 | * Call ```CommandLine.GetBool(key, defaultValue)``` and friends to query commandline options. 55 | 56 | Please see the video below where I show the integration steps. 57 | 58 | [![](http://img.youtube.com/vi/HdA2vDiHHWM/0.jpg)](http://www.youtube.com/watch?v=HdA2vDiHHWM "") 59 | 60 | # Examples 61 | 62 | ## How to load from file 63 | The simplest way to load a commandline file is to use ```System.IO```, which works on many or perhaps most platforms. 64 | 65 | However, on Android you can't use ```System.IO``` and you must use ```UnityWebRequest``` instead, which isn't shown in the example below. 66 | 67 | On some systems/consoles that require to mount a device before you can access it, you probably can't use the exact 68 | code below as well and need to modify the ```RuntimeInitializeLoadType``` option or call that method in your own application startup 69 | code. 70 | ```csharp 71 | [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)] 72 | static void LoadCommandLine() 73 | { 74 | // Use commandline options passed to the application 75 | var text = System.Environment.CommandLine + "\n"; 76 | 77 | // Load the commandline file content. 78 | // You need to adjust the path to where the file is located in your project. 79 | var path = System.IO.Path.Combine(Application.streamingAssetsPath, "CommandLine.txt"); 80 | if (System.IO.File.Exists(path)) 81 | { 82 | text += System.IO.File.ReadAllText(path); 83 | } 84 | else 85 | { 86 | #if UNITY_EDITOR || DEVELOPMENT_BUILD 87 | Debug.LogErrorFormat("Could not find commandline file '{0}'.", path); 88 | #endif 89 | } 90 | 91 | // Initialize the CommandLine 92 | Oddworm.Framework.CommandLine.Init(text); 93 | } 94 | ``` 95 | Using the [StreamingAssets](https://docs.unity3d.com/Manual/StreamingAssets.html) folder has the benefit that you can modify the commandline file in a build as well. 96 | You don't need to create a new build, if you just want to start the game with different commandline options. 97 | 98 | I don't provide a built-in method to load the CommandLine, because file loading code is very often project specific. 99 | 100 | 101 | ## I don't need a commandline file, I just want the options passed to the application 102 | OK, in this case it's even simpler: 103 | ```csharp 104 | [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)] 105 | static void LoadCommandLine() 106 | { 107 | Oddworm.Framework.CommandLine.Init(System.Environment.CommandLine); 108 | } 109 | ``` 110 | While the above code does work in a build perfectly, but in the editor, it only uses the commandline options that were passed to the Unity editor. 111 | 112 | 113 | ## How to use it 114 | Once the CommandLine has been initialized, see example above, you can query it pretty much the same way 115 | you use Unity's [PlayerPrefs](https://docs.unity3d.com/ScriptReference/PlayerPrefs.html). 116 | 117 | Let's assume the CommandLine.txt file contains these options: 118 | ```csharp 119 | -InfiniteHealth true 120 | //-InfiniteArmor true 121 | -DamageMultiplier 8.5 122 | ``` 123 | I prefer to write one option per line, but you can also have multiple options on the same line. 124 | ```csharp 125 | -InfiniteHealth true /*-InfiniteArmor true*/ -DamageMultiplier 8.5 126 | ``` 127 | 128 | The C# code to query above options would be: 129 | ```csharp 130 | using UnityEngine; 131 | using Oddworm.Framework; 132 | 133 | public class CommandLineExample : MonoBehaviour 134 | { 135 | void Start() 136 | { 137 | var infiniteHealth = CommandLine.GetBool("-InfiniteHealth", false); 138 | Debug.LogFormat("InfiniteHealth: {0}", infiniteHealth); 139 | 140 | var infiniteArmor = CommandLine.GetBool("-InfiniteArmor", false); 141 | Debug.LogFormat("InfiniteArmor: {0}", infiniteArmor); 142 | 143 | var damageMultiplier = CommandLine.GetFloat("-DamageMultiplier", 1); 144 | Debug.LogFormat("DamageMultiplier: {0}", damageMultiplier); 145 | } 146 | } 147 | ``` 148 | The output of above code is: 149 | ``` 150 | InfiniteHealth: True 151 | InfiniteArmor: False 152 | DamageMultiplier: 8.5 153 | ``` 154 | ```InfiniteArmor``` is false, because the commandline option was commented out 155 | via ```//``` and thus the specified default value ```false``` was used instead. 156 | 157 | The ```-``` symbol infront of each commandline option is just my personal preference, but it could be any other symbol too, 158 | or you could drop it entirely. The CommandLine code is not bound to any prefix. 159 | If you don't like prefixes, just don't use them. If you prefer different symbol(s), you can use them too. 160 | 161 | ## How to query enum options 162 | Let's assume the CommandLine.txt file contains these options: 163 | ```csharp 164 | -Fruit Pineapple 165 | -Fruits "Apple, Coconut, Kiwi" 166 | ``` 167 | 168 | The C# code to query above options would be: 169 | ```csharp 170 | enum Fruit 171 | { 172 | None, 173 | Banana, 174 | Apple, 175 | Coconut, 176 | Pineapple, 177 | Kiwi 178 | } 179 | 180 | CommandLine.GetEnum("-Fruit", Fruit.None); 181 | 182 | 183 | [System.Flags] 184 | enum Fruits 185 | { 186 | Banana = 1 << Fruit.Banana, 187 | Apple = 1 << Fruit.Apple, 188 | Coconut = 1 << Fruit.Coconut, 189 | Pineapple = 1 << Fruit.Pineapple, 190 | Kiwi = 1 << Fruit.Kiwi 191 | } 192 | 193 | CommandLine.GetEnum("-Fruits", 0); 194 | ``` 195 | 196 | 197 | ## Disable CommandLine 198 | You can turn off CommandLine with: 199 | ```csharp 200 | CommandLine.isEnabled = false; 201 | ``` 202 | This will cause: 203 | * CommandLine.HasKey returns false 204 | * CommandLine.Get... calls return the default value 205 | * CommandLine.onInitialize gets still invoked 206 | 207 | 208 | ## Strip CommandLine code from release builds 209 | If you don't want to support CommandLine in release builds or whatever specific builds you might have, 210 | you can add ```ODDWORM_COMMANDLINE_DISABLE``` to the ```Scripting Define Symbols``` found under 211 | ```Edit > Project Settings > Player > Other```. 212 | 213 | This will cause: 214 | * CommandLine.isEnabled returns false 215 | * CommandLine.HasKey returns false 216 | * CommandLine.Get... calls return the default value 217 | * CommandLine method bodies are stripped 218 | * CommandLine.onInitialize gets still invoked 219 | 220 | ## Full example 221 | The full example in a single text block can be found below. Copy/paste, save it as ```CommandLineExample.cs``` in your project and you're good to go. 222 | ```csharp 223 | using UnityEngine; 224 | using Oddworm.Framework; 225 | 226 | public class CommandLineExample : MonoBehaviour 227 | { 228 | void Start() 229 | { 230 | CommandLine.isEnabled = true; 231 | 232 | var infiniteHealth = CommandLine.GetBool("-InfiniteHealth", false); 233 | Debug.LogFormat("InfiniteHealth: {0}", infiniteHealth); 234 | 235 | var infiniteArmor = CommandLine.GetBool("-InfiniteArmor", false); 236 | Debug.LogFormat("InfiniteArmor: {0}", infiniteArmor); 237 | 238 | var damageMultiplier = CommandLine.GetFloat("-DamageMultiplier", 1); 239 | Debug.LogFormat("DamageMultiplier: {0}", damageMultiplier); 240 | } 241 | 242 | // On many platforms you can simply use System.IO to load a file as shown below. 243 | // On Android you can't use System.IO though, you need to use UnityWebRequest instead. 244 | [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)] 245 | static void LoadCommandLine() 246 | { 247 | // Use commandline options passed to the application 248 | var text = System.Environment.CommandLine + "\n"; 249 | 250 | // Load the commandline file content. 251 | // You need to adjust the path to where the file is located in your project. 252 | var path = System.IO.Path.Combine(Application.streamingAssetsPath, "CommandLine.txt"); 253 | if (System.IO.File.Exists(path)) 254 | { 255 | text += System.IO.File.ReadAllText(path); 256 | } 257 | else 258 | { 259 | #if UNITY_EDITOR || DEVELOPMENT_BUILD 260 | Debug.LogErrorFormat("Could not find commandline file '{0}'.", path); 261 | #endif 262 | } 263 | 264 | // Initialize the CommandLine 265 | Oddworm.Framework.CommandLine.Init(text); 266 | } 267 | 268 | #if UNITY_EDITOR 269 | [UnityEditor.MenuItem("File/Open Commandline", priority = 1000)] 270 | static void OpenCommandLineMenuItem() 271 | { 272 | // The CommandLine.txt file location 273 | var path = System.IO.Path.Combine(Application.streamingAssetsPath, "CommandLine.txt"); 274 | 275 | // If the directory does not exist, create it. 276 | var directory = System.IO.Path.GetDirectoryName(path); 277 | if (!System.IO.Directory.Exists(directory)) 278 | System.IO.Directory.CreateDirectory(directory); 279 | 280 | // If the CommandLine.txt does not exist, create it. 281 | if (!System.IO.File.Exists(path)) 282 | { 283 | System.IO.File.WriteAllText(path, "Need help? See https://github.com/pschraut/UnityCommandLine", System.Text.Encoding.UTF8); 284 | UnityEditor.AssetDatabase.Refresh(); 285 | } 286 | 287 | // Open the CommandLine.txt file 288 | UnityEditor.EditorUtility.OpenWithDefaultApp(path); 289 | } 290 | #endif 291 | } 292 | 293 | ``` 294 | 295 | 296 | # Tips 297 | 298 | ## Menu Item 299 | Create a menu item to easily open the commandline text file in your project. 300 | ```csharp 301 | #if UNITY_EDITOR 302 | [UnityEditor.MenuItem("File/Open Commandline", priority = 1000)] 303 | static void OpenCommandLineMenuItem() 304 | { 305 | // The CommandLine.txt file location 306 | var path = System.IO.Path.Combine(Application.streamingAssetsPath, "CommandLine.txt"); 307 | 308 | // If the directory does not exist, create it. 309 | var directory = System.IO.Path.GetDirectoryName(path); 310 | if (!System.IO.Directory.Exists(directory)) 311 | System.IO.Directory.CreateDirectory(directory); 312 | 313 | // If the CommandLine.txt does not exist, create it. 314 | if (!System.IO.File.Exists(path)) 315 | { 316 | System.IO.File.WriteAllText(path, "Need help? Please see https://github.com/pschraut/UnityCommandLine", System.Text.Encoding.UTF8); 317 | UnityEditor.AssetDatabase.Refresh(); 318 | } 319 | 320 | // Open the CommandLine.txt file 321 | UnityEditor.EditorUtility.OpenWithDefaultApp(path); 322 | } 323 | #endif 324 | ``` 325 | 326 | ## PlayMode Inspector 327 | If you have my [PlayMode Inspector](https://github.com/pschraut/UnityPlayModeInspector) packages installed, 328 | you can also see the internals of CommandLine as shown in the image below. 329 | For this open PlayMode Inspector from ```Window > Analysis > PlayMode Inspector``` and use the ```Static...``` drop-down to select 330 | ```CommandLine.PlayModeInspectorMethod```. 331 | ![alt text](Documentation~/images/playmodeinspector.png "PlayMode Inspector") 332 | -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b79c898dfabc1bd49a0c52f8f45b96d1 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Runtime.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5edd4e92ca559804985f6edf6bad7259 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/CommandLine.PlayModeInspector.cs: -------------------------------------------------------------------------------- 1 | // 2 | // CommandLine for Unity. Copyright (c) 2020-2024 Peter Schraut (www.console-dev.de). See LICENSE.md 3 | // https://github.com/pschraut/UnityCommandLine 4 | // 5 | #pragma warning disable IDE1006, IDE0017 6 | #pragma warning disable IDE0051 // Remove unused private members 7 | #pragma warning disable IDE0052 // Remove unread private members 8 | #pragma warning disable IDE0032 // Use auto property 9 | #pragma warning disable CS0649 // Field 'xxx' is never assigned to, and will always have its default value 10 | 11 | namespace Oddworm.Framework 12 | { 13 | public static partial class CommandLine 14 | { 15 | #if PLAYMODEINSPECTOR_PRESENT && UNITY_EDITOR 16 | // Install the PlayMode Inspector package to use this code: 17 | // https://github.com/pschraut/UnityPlayModeInspector 18 | [Oddworm.Framework.PlayModeInspectorMethod] 19 | static void PlayModeInspectorMethod() 20 | { 21 | UnityEditor.EditorGUILayout.Toggle("Is Enabled", isEnabled); 22 | 23 | // Display the cached/retrieved params. 24 | // Here we actually know type, so we can display them properly. 25 | // We know the type, because the particuler Get... method stored it. 26 | UnityEditor.EditorGUILayout.LabelField("Cached", UnityEditor.EditorStyles.boldLabel); 27 | for (var n = 0; n < s_Cached.Count; ++n) 28 | { 29 | UnityEditor.EditorGUI.indentLevel++; 30 | var param = s_Cached[n]; 31 | switch (param.type) 32 | { 33 | case Param.Type.String: 34 | param.stringValue = UnityEditor.EditorGUILayout.TextField(param.key, param.stringValue); 35 | break; 36 | 37 | case Param.Type.Bool: 38 | param.boolValue = UnityEditor.EditorGUILayout.Toggle(param.key, param.boolValue); 39 | break; 40 | 41 | case Param.Type.Int: 42 | param.intValue = UnityEditor.EditorGUILayout.IntField(param.key, param.intValue); 43 | break; 44 | 45 | case Param.Type.Float: 46 | param.floatValue = UnityEditor.EditorGUILayout.FloatField(param.key, param.floatValue); 47 | break; 48 | 49 | case Param.Type.Enum: 50 | if (param.enumValue.GetType().GetCustomAttributes(typeof(System.FlagsAttribute), true).Length > 0) 51 | param.enumValue = UnityEditor.EditorGUILayout.EnumFlagsField(param.key, param.enumValue); 52 | else 53 | param.enumValue = UnityEditor.EditorGUILayout.EnumPopup(param.key, param.enumValue); 54 | break; 55 | } 56 | UnityEditor.EditorGUI.indentLevel--; 57 | 58 | s_Cached[n] = param; 59 | } 60 | 61 | UnityEditor.EditorGUILayout.Space(); 62 | 63 | // The raw text that was passed to CommandLine to parse 64 | UnityEditor.EditorGUILayout.LabelField("RAW (Read only)", UnityEditor.EditorStyles.boldLabel); 65 | UnityEditor.EditorGUI.indentLevel++; 66 | UnityEditor.EditorGUILayout.TextArea(s_Text); 67 | UnityEditor.EditorGUI.indentLevel--; 68 | 69 | UnityEditor.EditorGUILayout.Space(); 70 | 71 | // Display parsed paramters. We don't know the type, thus we just display each one as text. 72 | UnityEditor.EditorGUILayout.LabelField("Parsed (Read only)", UnityEditor.EditorStyles.boldLabel); 73 | UnityEditor.EditorGUI.indentLevel++; 74 | for (var n = 0; n < s_Parsed.Count; ++n) 75 | UnityEditor.EditorGUILayout.TextField(s_Parsed[n]); 76 | UnityEditor.EditorGUI.indentLevel--; 77 | } 78 | #endif // PLAYMODEINSPECTOR_PRESENT 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /Runtime/CommandLine.PlayModeInspector.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c028ac1d6ac057a4781818044519dd35 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/CommandLine.cs: -------------------------------------------------------------------------------- 1 | // 2 | // CommandLine for Unity. Copyright (c) 2020-2024 Peter Schraut (www.console-dev.de). See LICENSE.md 3 | // https://github.com/pschraut/UnityCommandLine 4 | // 5 | #pragma warning disable IDE1006, IDE0017 6 | #pragma warning disable IDE0051 // Remove unused private members 7 | #pragma warning disable IDE0052 // Remove unread private members 8 | #pragma warning disable IDE0032 // Use auto property 9 | #pragma warning disable CS0649 // Field 'xxx' is never assigned to, and will always have its default value 10 | using System; 11 | using System.Collections.Generic; 12 | using UnityEngine; 13 | 14 | namespace Oddworm.Framework 15 | { 16 | /// 17 | /// The CommandLine class provides the ability to parse a "Key/Value-pair like" text document, 18 | /// whose values can be queried in strongly typed fashion. It supports the types string, int, float, bool and enum. 19 | /// It supports C# like single and multi-line comments, as well quoted arguments, if they span across multiple words. 20 | /// 21 | public static partial class CommandLine 22 | { 23 | /// 24 | /// Gets/sets whether the CommandLine is enabled. A disabled CommandLine returns the defaultValue always. 25 | /// Use the ODDWORM_COMMANDLINE_DISABLE scripting define symbol to let the compiler remove the CommandLine method bodies. 26 | /// If the ODDWORM_COMMANDLINE_DISABLE scripting define symbol has been set, it returns false always. 27 | /// 28 | public static bool isEnabled 29 | { 30 | get 31 | { 32 | #if ODDWORM_COMMANDLINE_DISABLE 33 | return false; 34 | #else 35 | return s_Enabled; 36 | #endif 37 | } 38 | set 39 | { 40 | #if ODDWORM_COMMANDLINE_DISABLE 41 | // Do nothing 42 | #else 43 | s_Enabled = value; 44 | #endif 45 | } 46 | } 47 | 48 | /// 49 | /// Gets the text that was passed to Init(). 50 | /// If the ODDWORM_COMMANDLINE_DISABLE scripting define symbol has been set, it returns an empty string always. 51 | /// 52 | public static string text 53 | { 54 | get 55 | { 56 | #if ODDWORM_COMMANDLINE_DISABLE 57 | return ""; 58 | #else 59 | return s_Text; 60 | #endif 61 | } 62 | } 63 | 64 | /// 65 | /// An event that is invoked after Commandline.Init has been called. 66 | /// This event is invoked even if the ODDWORM_COMMANDLINE_DISABLE scripting define symbol has been set. 67 | /// 68 | public static Action onInitialized 69 | { 70 | // Didn't mark as "event" on purpose, so user-code can also reset it (clear all handlers) 71 | get; 72 | set; 73 | } 74 | 75 | #if !ODDWORM_COMMANDLINE_DISABLE 76 | static bool s_Enabled; // Whether the command-line is enabled 77 | static string s_Text = ""; // The text passed to Init() 78 | static readonly List s_Parsed = new List(16); // The parses text as one "token" per entry 79 | static readonly List s_Cached = new List(16); // The params already queried from the user 80 | 81 | struct Param 82 | { 83 | public enum Type 84 | { 85 | None, 86 | String, 87 | Int, 88 | Float, 89 | Bool, 90 | Enum 91 | } 92 | 93 | public string key; 94 | public int keyHash; 95 | public Type type; 96 | 97 | public string stringValue; 98 | public int intValue; 99 | public float floatValue; 100 | public bool boolValue; 101 | public Enum enumValue; 102 | 103 | public override string ToString() 104 | { 105 | return string.Format("key: {0}, type: {1}", key, type); 106 | } 107 | } 108 | #endif // !ODDWORM_COMMANDLINE_DISABLE 109 | 110 | static CommandLine() 111 | { 112 | #if ODDWORM_COMMANDLINE_DISABLE 113 | isEnabled = false; 114 | #else 115 | isEnabled = true; 116 | #endif 117 | } 118 | 119 | /// 120 | /// Initialize the CommandLine with the specified text. 121 | /// 122 | /// The text that contains all the command-line parameters. 123 | /// 124 | /// A "LoadFromFile" method isn't provided, because it needs to be handled on various 125 | /// platforms differently, depending where the file is located. 126 | /// Thus, it's up to user-code to load the file and pass the content to Init() instead. 127 | /// 128 | public static void Init(string text) 129 | { 130 | #if !ODDWORM_COMMANDLINE_DISABLE 131 | // Clear the parsed and cached values always. 132 | // The parse list gets populated right in this method. 133 | // The cached list gets populated as values are queried from the CommandLine. 134 | s_Parsed.Clear(); 135 | s_Cached.Clear(); 136 | 137 | // Remember the text. We do this, in case user code wants to call 138 | // Init() multiple times (which is valid) to concatenate the command-line text, like: 139 | // CommandLine.Init(CommandLine.text + "\n" + newCommandLine); 140 | s_Text = text; 141 | 142 | var sb = new System.Text.StringBuilder(256); // the currently parsed word 143 | var i = 0; // the current index into the raw text 144 | 145 | // Parse the text... 146 | while (!string.IsNullOrEmpty(s_Text) && i < s_Text.Length) 147 | { 148 | var c = s_Text[i++]; 149 | 150 | // A white-space character indicates a new argument on the command-line 151 | if (char.IsWhiteSpace(c)) 152 | { 153 | if (sb.Length > 0) 154 | { 155 | s_Parsed.Add(sb.ToString()); 156 | sb.Clear(); 157 | } 158 | continue; 159 | } 160 | 161 | // A quote represents a string that is allowed to contain white-space characters 162 | if (c == '\"') 163 | { 164 | // Read until a quote occurs again 165 | while (i < s_Text.Length) 166 | { 167 | c = s_Text[i++]; 168 | 169 | // Two quotes in succession represent a single quote in a quoted string 170 | // "This is ""great""." 171 | if (c == '\"' && i < s_Text.Length && s_Text[i] == '\"') 172 | { 173 | sb.Append(c); 174 | i++; 175 | continue; 176 | } 177 | else if (c == '\"') // end-quote 178 | { 179 | break; 180 | } 181 | 182 | // Otherwise just use the character 183 | sb.Append(c); 184 | } 185 | 186 | continue; 187 | } 188 | 189 | // Skip C-style block comments like /* This is a comment */ 190 | // Check if we found the starting character sequence /* 191 | if (c == '/' && i < s_Text.Length && s_Text[i] == '*') 192 | { 193 | // If there is no space between the last world and the comment, 194 | // then we need to flush the current stringbuffer. 195 | if (sb.Length > 0) 196 | { 197 | s_Parsed.Add(sb.ToString()); 198 | sb.Clear(); 199 | } 200 | 201 | // Read until closing character sequence */ occurs 202 | while (i < s_Text.Length) 203 | { 204 | c = s_Text[i++]; 205 | 206 | if (c == '*' && i < s_Text.Length && s_Text[i] == '/') 207 | { 208 | i++; 209 | break; 210 | } 211 | } 212 | 213 | continue; 214 | } 215 | 216 | // Skip C-style line comment like // This is a comment 217 | if (c == '/' && i < s_Text.Length && s_Text[i] == '/') 218 | { 219 | // If there is no space between the last world and the comment, 220 | // then we need to flush the current stringbuffer. 221 | if (sb.Length > 0) 222 | { 223 | s_Parsed.Add(sb.ToString()); 224 | sb.Clear(); 225 | } 226 | 227 | // Read until closing character sequence occurs 228 | while (i < s_Text.Length) 229 | { 230 | c = s_Text[i++]; 231 | 232 | // Line end? 233 | if (c == '\n' || c == '\r' || c == '\0') 234 | { 235 | i--; // decrement so char.IsWhiteSpace at the beginning of the loop kicks in 236 | break; 237 | } 238 | } 239 | 240 | continue; 241 | } 242 | 243 | sb.Append(c); 244 | } 245 | 246 | // In case there is no whitespace as last character, the string buffer 247 | // can still contain something. So we check if it has content. 248 | if (sb.Length > 0) 249 | { 250 | s_Parsed.Add(sb.ToString()); 251 | sb.Clear(); 252 | } 253 | #endif 254 | // Raise the event always, even when disabled. This is to allow subscribed code 255 | // to get executed rather than ending up uninitialized. Subscribed code will then 256 | // most likely query CommandLine options and if ODDWORM_COMMANDLINE_DISABLE is present, 257 | // would receive default values as expected. 258 | onInitialized?.Invoke(); 259 | } 260 | 261 | /// 262 | /// Gets whether the specified key exists in the command-line. 263 | /// 264 | /// The key. 265 | /// true if it exists, false otherwise. 266 | public static bool HasKey(string key) 267 | { 268 | #if ODDWORM_COMMANDLINE_DISABLE 269 | return false; 270 | #else 271 | if (!isEnabled) 272 | return false; 273 | 274 | for (var n = s_Parsed.Count - 1; n >= 0; --n) 275 | { 276 | if (string.Equals(s_Parsed[n], key, StringComparison.OrdinalIgnoreCase)) 277 | return true; 278 | } 279 | return false; 280 | #endif 281 | } 282 | 283 | /// 284 | /// Gets the value corresponding to the specified key. 285 | /// 286 | /// The key. 287 | /// The return value if the key does not exist. 288 | /// The value if the key exists, otherwise the defaultValue. 289 | public static string GetString(string key, string defaultValue) 290 | { 291 | #if ODDWORM_COMMANDLINE_DISABLE 292 | return defaultValue; 293 | #else 294 | if (!isEnabled) 295 | return defaultValue; 296 | 297 | // Check if it's in the cache already 298 | if (TryGetParam(key, Param.Type.String, out Param param)) 299 | return param.stringValue; 300 | 301 | // It's not in the cache yet. Scan the command-line strings for the requested key 302 | var value = defaultValue; 303 | var hasKey = false; 304 | for (var n = 0; n < s_Parsed.Count - 1; ++n) 305 | { 306 | if (!string.Equals(s_Parsed[n], key, StringComparison.OrdinalIgnoreCase)) 307 | continue; 308 | 309 | value = s_Parsed[n + 1]; 310 | hasKey = true; 311 | break; 312 | } 313 | 314 | if (hasKey) 315 | { 316 | // Add the param to the cache only when the key was found. 317 | // This is to support to pass different default values when no key for it exists. 318 | var newParam = new Param(); 319 | newParam.key = key; 320 | newParam.keyHash = Animator.StringToHash(key); 321 | newParam.type = Param.Type.String; 322 | newParam.stringValue = value; 323 | s_Cached.Add(newParam); 324 | } 325 | 326 | return value; 327 | #endif 328 | } 329 | 330 | /// 331 | /// Gets the value corresponding to the specified key. 332 | /// 333 | /// The key. 334 | /// The return value if the key does not exist. 335 | /// The value if the key exists, otherwise the defaultValue. 336 | public static float GetFloat(string key, float defaultValue) 337 | { 338 | #if ODDWORM_COMMANDLINE_DISABLE 339 | return defaultValue; 340 | #else 341 | if (!isEnabled) 342 | return defaultValue; 343 | 344 | // Check if it's in the cache already 345 | if (TryGetParam(key, Param.Type.Float, out Param param)) 346 | return param.floatValue; 347 | 348 | // It's not in the cache yet. Scan the command-line strings for the requested key 349 | var value = defaultValue; 350 | var hasKey = false; 351 | for (var n = 0; n < s_Parsed.Count - 1; ++n) 352 | { 353 | if (!string.Equals(s_Parsed[n], key, StringComparison.OrdinalIgnoreCase)) 354 | continue; 355 | 356 | if (!float.TryParse(s_Parsed[n + 1], out value)) 357 | value = defaultValue; 358 | 359 | hasKey = true; 360 | break; 361 | } 362 | 363 | if (hasKey) 364 | { 365 | // Add the param to the cache 366 | var newParam = new Param(); 367 | newParam.key = key; 368 | newParam.keyHash = Animator.StringToHash(key); 369 | newParam.type = Param.Type.Float; 370 | newParam.floatValue = value; 371 | s_Cached.Add(newParam); 372 | } 373 | 374 | return value; 375 | #endif 376 | } 377 | 378 | /// 379 | /// Gets the value corresponding to the specified key. 380 | /// 381 | /// The key. 382 | /// The return value if the key does not exist. 383 | /// The value if the key exists, otherwise the defaultValue. 384 | public static int GetInt(string key, int defaultValue) 385 | { 386 | #if ODDWORM_COMMANDLINE_DISABLE 387 | return defaultValue; 388 | #else 389 | if (!isEnabled) 390 | return defaultValue; 391 | 392 | // Check if it's in the cache already 393 | if (TryGetParam(key, Param.Type.Int, out Param param)) 394 | return param.intValue; 395 | 396 | // It's not in the cache yet. Scan the command-line strings for the requested key 397 | var value = defaultValue; 398 | var hasKey = false; 399 | for (var n = 0; n < s_Parsed.Count - 1; ++n) 400 | { 401 | if (!string.Equals(s_Parsed[n], key, StringComparison.OrdinalIgnoreCase)) 402 | continue; 403 | 404 | if (!int.TryParse(s_Parsed[n + 1], out value)) 405 | value = defaultValue; 406 | 407 | hasKey = true; 408 | break; 409 | } 410 | 411 | if (hasKey) 412 | { 413 | // Add the param to the cache 414 | var newParam = new Param(); 415 | newParam.key = key; 416 | newParam.keyHash = Animator.StringToHash(key); 417 | newParam.type = Param.Type.Int; 418 | newParam.intValue = value; 419 | s_Cached.Add(newParam); 420 | } 421 | 422 | return value; 423 | #endif 424 | } 425 | 426 | /// 427 | /// Gets the value corresponding to the specified key. 428 | /// 429 | /// The key. 430 | /// The return value if the key does not exist. 431 | /// The value if the key exists, otherwise the defaultValue. 432 | public static bool GetBool(string key, bool defaultValue) 433 | { 434 | #if ODDWORM_COMMANDLINE_DISABLE 435 | return defaultValue; 436 | #else 437 | if (!isEnabled) 438 | return defaultValue; 439 | 440 | // Check if it's in the cache already 441 | if (TryGetParam(key, Param.Type.Bool, out Param param)) 442 | return param.boolValue; 443 | 444 | // It's not in the cache yet. Scan the command-line strings for the requested key. 445 | var value = defaultValue; 446 | var hasKey = false; 447 | for (var n = 0; n < s_Parsed.Count - 1; ++n) 448 | { 449 | if (!string.Equals(s_Parsed[n], key, StringComparison.OrdinalIgnoreCase)) 450 | continue; 451 | 452 | // We allow to specify bool values as 0,false and 1,true 453 | if (int.TryParse(s_Parsed[n + 1], out int b)) 454 | { 455 | // Everything else than 0 is true 456 | value = b != 0; 457 | } 458 | else 459 | { 460 | // Everything else than false is true 461 | value = !string.Equals(s_Parsed[n + 1], "false", StringComparison.OrdinalIgnoreCase); 462 | } 463 | 464 | hasKey = true; 465 | break; 466 | } 467 | 468 | if (hasKey) 469 | { 470 | // Add the param to the cache 471 | var newParam = new Param(); 472 | newParam.key = key; 473 | newParam.keyHash = Animator.StringToHash(key); 474 | newParam.type = Param.Type.Bool; 475 | newParam.boolValue = value; 476 | s_Cached.Add(newParam); 477 | } 478 | 479 | return value; 480 | #endif 481 | } 482 | 483 | /// 484 | /// Gets the value corresponding to the specified key. 485 | /// 486 | /// The Enum type. 487 | /// The key. 488 | /// The return value if the key does not exist. 489 | /// The value if the key exists, otherwise the defaultValue. 490 | public static TEnum GetEnum(string key, TEnum defaultValue) 491 | where TEnum : struct, System.Enum, IConvertible 492 | { 493 | #if ODDWORM_COMMANDLINE_DISABLE 494 | return defaultValue; 495 | #else 496 | if (!isEnabled) 497 | return defaultValue; 498 | 499 | // Check if it's in the cache already 500 | if (TryGetParam(key, Param.Type.Enum, out Param param)) 501 | return (TEnum)param.enumValue; 502 | 503 | TEnum value = defaultValue; 504 | var hasKey = false; 505 | for (var n = 0; n < s_Parsed.Count - 1; ++n) 506 | { 507 | if (!string.Equals(s_Parsed[n], key, StringComparison.OrdinalIgnoreCase)) 508 | continue; 509 | 510 | if (!Enum.TryParse(s_Parsed[n + 1], true, out value)) 511 | value = defaultValue; 512 | 513 | hasKey = true; 514 | break; 515 | } 516 | 517 | // Add the param to the cache 518 | if (hasKey) 519 | { 520 | var newParam = new Param(); 521 | newParam.key = key; 522 | newParam.keyHash = Animator.StringToHash(key); 523 | newParam.type = Param.Type.Enum; 524 | newParam.enumValue = value; 525 | s_Cached.Add(newParam); 526 | } 527 | 528 | return value; 529 | #endif 530 | } 531 | 532 | #if !ODDWORM_COMMANDLINE_DISABLE 533 | static bool TryGetParam(string key, Param.Type type, out Param param) 534 | { 535 | var keyHash = Animator.StringToHash(key); 536 | 537 | for (var n = 0; n < s_Cached.Count; ++n) 538 | { 539 | param = s_Cached[n]; 540 | 541 | if (param.type != type) 542 | continue; 543 | 544 | if (param.keyHash != keyHash) 545 | continue; 546 | 547 | if (!string.Equals(param.key, key, StringComparison.OrdinalIgnoreCase)) 548 | continue; 549 | 550 | return true; 551 | } 552 | 553 | param = new Param(); 554 | return false; 555 | } 556 | #endif 557 | } 558 | } 559 | -------------------------------------------------------------------------------- /Runtime/CommandLine.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 660f60dbc70c8774c83c67cec3d3b8c6 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Unity.CommandLine.Runtime.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Unity.CommandLine.Runtime", 3 | "references": [ 4 | "GUID:e028a5ff6e66c3948862cb135cce531c" 5 | ], 6 | "includePlatforms": [], 7 | "excludePlatforms": [], 8 | "allowUnsafeCode": false, 9 | "overrideReferences": false, 10 | "precompiledReferences": [], 11 | "autoReferenced": true, 12 | "defineConstraints": [], 13 | "versionDefines": [ 14 | { 15 | "name": "com.oddworm.playmodeinspector", 16 | "expression": "0.0.0", 17 | "define": "PLAYMODEINSPECTOR_PRESENT" 18 | } 19 | ], 20 | "noEngineReferences": false 21 | } -------------------------------------------------------------------------------- /Runtime/Unity.CommandLine.Runtime.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 82cc1078feb314f48a831e2beecfdba0 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Tests.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0f93c574e1e2d2b4eb40fcd14af37f28 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Tests/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9257e07956e0c3a46854167aefab1dbe 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Tests/Editor/CommandLineTests.cs: -------------------------------------------------------------------------------- 1 | // 2 | // CommandLine for Unity. Copyright (c) 2020-2024 Peter Schraut (www.console-dev.de). See LICENSE.md 3 | // https://github.com/pschraut/UnityCommandLine 4 | // 5 | #pragma warning disable IDE1006, IDE0017 6 | using NUnit.Framework; 7 | using Oddworm.Framework; 8 | 9 | namespace Oddworm.EditorFramework.Tests 10 | { 11 | class CommandLineTests 12 | { 13 | enum Fruit 14 | { 15 | None, 16 | Banana, 17 | Apple, 18 | Coconut, 19 | Pineapple, 20 | Kiwi 21 | } 22 | 23 | [System.Flags] 24 | enum Fruits 25 | { 26 | Banana = 1 << Fruit.Banana, 27 | Apple = 1 << Fruit.Apple, 28 | Coconut = 1 << Fruit.Coconut, 29 | Pineapple = 1 << Fruit.Pineapple, 30 | Kiwi = 1 << Fruit.Kiwi 31 | } 32 | 33 | const string k_CommandLine1 = @" 34 | -Fruit Pineapple 35 | -Fruits ""Apple, Coconut, Kiwi"" 36 | -String Yes 37 | -QuotedString ""Hello World"" 38 | -Int 1337 // a comment 39 | -NegativeInt -7331 40 | // another comment 41 | -Float 3.21 42 | -NegativeFloat -1.23 43 | -Bool 1/* a block comment... 44 | ...*/-BoolString true 45 | "; 46 | 47 | const string k_CommandLine2 = @"-Fruit Pineapple -Fruits ""Apple, Coconut, Kiwi"" -String Yes -QuotedString ""Hello World"" -Int 1337 -NegativeInt -7331 -Float 3.21 -NegativeFloat -1.23 -Bool 1 -BoolString true"; 48 | const string k_CommandLine3 = @"-Fruit Pineapple -Fruits ""Apple, Coconut, Kiwi"" -String Yes -Int 1337 -NegativeInt -7331 -Float 3.21 -NegativeFloat -1.23 -Bool 1 -BoolString true -QuotedString ""Hello World"""; 49 | const string k_CommandLine4 = @"-Fruit Pineapple -String Yes -Int 1337 -NegativeInt -7331 -Float 3.21 -NegativeFloat -1.23 -Bool 1 -BoolString true -QuotedString ""Hello World"" -Fruits ""Apple, Coconut, Kiwi"""; 50 | const string k_CommandLine5 = @"/*comment*/-Fruit Pineapple/*comment*/ /*comment*/-String Yes/*comment*/ /*comment*/-Int 1337/*comment*/ /*comment*/-NegativeInt -7331/*comment*/ /*comment*/-Float 3.21/*comment*/ /*comment*/-NegativeFloat/*comment*/ /*comment*/-1.23/*comment*/ /*comment*/-Bool 1/*comment*/ /*comment*/-BoolString true/*comment*/ /*comment*/-QuotedString ""Hello World""/*comment*/ /*comment*/-Fruits ""Apple, Coconut, Kiwi""/*comment*/"; 51 | const string k_CommandLine6 = @"/*comment*/-Fruit/*comment*/Pineapple/*comment*/-Fruits/*comment*/""Apple, Coconut, Kiwi""/*comment*/-String/*comment*/Yes/*comment*/-QuotedString/*comment*/""Hello World""/*comment*/-Int/*comment*/1337/*comment*/-NegativeInt/*comment*/-7331/*comment*/-Float/*comment*/3.21/*comment*/-NegativeFloat/*comment*/-1.23/*comment*/-Bool/*comment*/1/*comment*/-BoolString/*comment*/true/*comment*/"; 52 | 53 | const string k_CommandLine7 = @"// ---------------------- 54 | // this is a comment 55 | // ------------------------------------ 56 | -Fruit Pineapple // comment 57 | //comment 58 | -Fruits ""Apple, Coconut, Kiwi"" //comment 59 | -String Yes//comment 60 | //comment 61 | -QuotedString ""Hello World""// comment /* abc */ 62 | //comment 63 | -Int 1337 // a comment/* 64 | foobar */ 65 | //comment 66 | -NegativeInt -7331 67 | //comment 68 | -Float 3.21 69 | //comment 70 | -NegativeFloat -1.23 71 | //comment 72 | -Bool 1/* a block comment... 73 | ...*/-BoolString true 74 | //comment 75 | "; 76 | 77 | static readonly string[] s_SameCommandLines1 = new string[] 78 | { 79 | k_CommandLine1, k_CommandLine2, k_CommandLine3, 80 | k_CommandLine4, k_CommandLine5, k_CommandLine6, 81 | k_CommandLine7 82 | }; 83 | 84 | [Test] 85 | public void IsEnabled() 86 | { 87 | #if ODDWORM_COMMANDLINE_DISABLE 88 | CommandLine.isEnabled = true; 89 | Assert.AreEqual(CommandLine.isEnabled, false); 90 | 91 | CommandLine.isEnabled = false; 92 | Assert.AreEqual(CommandLine.isEnabled, false); 93 | #else 94 | CommandLine.isEnabled = true; 95 | Assert.AreEqual(CommandLine.isEnabled, true); 96 | 97 | CommandLine.isEnabled = false; 98 | Assert.AreEqual(CommandLine.isEnabled, false); 99 | 100 | CommandLine.isEnabled = true; 101 | Assert.AreEqual(CommandLine.isEnabled, true); 102 | #endif 103 | } 104 | 105 | [Test] 106 | public void DefaultValueWithoutKey() 107 | { 108 | foreach (var enabled in new[] { true, false }) 109 | { 110 | CommandLine.isEnabled = enabled; 111 | 112 | foreach (var s in s_SameCommandLines1) 113 | { 114 | CommandLine.Init(s); 115 | 116 | Assert.AreEqual(CommandLine.GetString("-KeyDoesNotExist", "Hello"), "Hello"); 117 | Assert.AreEqual(CommandLine.GetString("-KeyDoesNotExist", "World"), "World"); 118 | 119 | Assert.AreEqual(CommandLine.GetBool("-KeyDoesNotExist", true), true); 120 | Assert.AreEqual(CommandLine.GetBool("-KeyDoesNotExist", false), false); 121 | 122 | Assert.AreEqual(CommandLine.GetInt("-KeyDoesNotExist", 1), 1); 123 | Assert.AreEqual(CommandLine.GetInt("-KeyDoesNotExist", 0), 0); 124 | 125 | Assert.AreEqual(CommandLine.GetFloat("-KeyDoesNotExist", 1.23f), 1.23f); 126 | Assert.AreEqual(CommandLine.GetFloat("-KeyDoesNotExist", 0), 0); 127 | 128 | Assert.AreEqual(CommandLine.GetEnum("-KeyDoesNotExist", Fruit.Banana), Fruit.Banana); 129 | Assert.AreEqual(CommandLine.GetEnum("-KeyDoesNotExist", Fruit.Apple), Fruit.Apple); 130 | } 131 | } 132 | } 133 | 134 | [Test] 135 | public void String() 136 | { 137 | foreach (var enabled in new[] { true, false }) 138 | { 139 | CommandLine.isEnabled = enabled; 140 | 141 | foreach (var s in s_SameCommandLines1) 142 | { 143 | CommandLine.Init(s); 144 | 145 | if (CommandLine.isEnabled) 146 | Assert.AreEqual(CommandLine.GetString("-String", ""), "Yes"); 147 | else 148 | Assert.AreEqual(CommandLine.GetString("-String", "bla"), "bla"); 149 | } 150 | } 151 | } 152 | 153 | [Test] 154 | public void QuotedString() 155 | { 156 | foreach (var enabled in new[] { true, false }) 157 | { 158 | CommandLine.isEnabled = enabled; 159 | 160 | foreach (var s in s_SameCommandLines1) 161 | { 162 | CommandLine.Init(s); 163 | 164 | if (CommandLine.isEnabled) 165 | Assert.AreEqual(CommandLine.GetString("-QuotedString", ""), "Hello World"); 166 | else 167 | Assert.AreEqual(CommandLine.GetString("-QuotedString", "bla bla"), "bla bla"); 168 | } 169 | } 170 | } 171 | 172 | [Test] 173 | public void Enum() 174 | { 175 | foreach (var enabled in new[] { true, false }) 176 | { 177 | CommandLine.isEnabled = enabled; 178 | 179 | foreach (var s in s_SameCommandLines1) 180 | { 181 | CommandLine.Init(s); 182 | 183 | if (CommandLine.isEnabled) 184 | Assert.AreEqual(CommandLine.GetEnum("-Fruit", Fruit.None), Fruit.Pineapple); 185 | else 186 | Assert.AreEqual(CommandLine.GetEnum("-Fruit", Fruit.None), Fruit.None); 187 | } 188 | } 189 | } 190 | 191 | [Test] 192 | public void FlagsEnum() 193 | { 194 | foreach (var enabled in new[] { true, false }) 195 | { 196 | CommandLine.isEnabled = enabled; 197 | 198 | foreach (var s in s_SameCommandLines1) 199 | { 200 | CommandLine.Init(s); 201 | 202 | if (CommandLine.isEnabled) 203 | Assert.AreEqual(CommandLine.GetEnum("-Fruits", 0), Fruits.Apple | Fruits.Coconut | Fruits.Kiwi); 204 | else 205 | Assert.AreEqual(CommandLine.GetEnum("-Fruits", 0), (Fruits)0); 206 | } 207 | } 208 | } 209 | 210 | [Test] 211 | public void Int() 212 | { 213 | foreach (var enabled in new[] { true, false }) 214 | { 215 | CommandLine.isEnabled = enabled; 216 | 217 | foreach (var s in s_SameCommandLines1) 218 | { 219 | CommandLine.Init(s); 220 | 221 | if (CommandLine.isEnabled) 222 | { 223 | Assert.AreEqual(CommandLine.GetInt("-Int", 0), 1337); 224 | Assert.AreEqual(CommandLine.GetInt("-NegativeInt", 0), -7331); 225 | } 226 | else 227 | { 228 | Assert.AreEqual(CommandLine.GetInt("-Int", 0), 0); 229 | Assert.AreEqual(CommandLine.GetInt("-NegativeInt", 0), 0); 230 | } 231 | } 232 | } 233 | } 234 | 235 | [Test] 236 | public void Float() 237 | { 238 | foreach (var enabled in new[] { true, false }) 239 | { 240 | CommandLine.isEnabled = enabled; 241 | 242 | foreach (var s in s_SameCommandLines1) 243 | { 244 | CommandLine.Init(s); 245 | 246 | if (CommandLine.isEnabled) 247 | { 248 | Assert.AreEqual(CommandLine.GetFloat("-Float", 0), 3.21f); 249 | Assert.AreEqual(CommandLine.GetFloat("-NegativeFloat", 0), -1.23f); 250 | } 251 | else 252 | { 253 | Assert.AreEqual(CommandLine.GetFloat("-Float", 0), 0); 254 | Assert.AreEqual(CommandLine.GetFloat("-NegativeFloat", 0), 0); 255 | } 256 | } 257 | } 258 | } 259 | 260 | [Test] 261 | public void Bool() 262 | { 263 | foreach (var enabled in new[] { true, false }) 264 | { 265 | CommandLine.isEnabled = enabled; 266 | 267 | foreach (var s in s_SameCommandLines1) 268 | { 269 | CommandLine.Init(s); 270 | 271 | if (CommandLine.isEnabled) 272 | { 273 | Assert.AreEqual(CommandLine.GetBool("-Bool", false), true); 274 | Assert.AreEqual(CommandLine.GetBool("-BoolString", false), true); 275 | } 276 | else 277 | { 278 | Assert.AreEqual(CommandLine.GetBool("-Bool", false), false); 279 | Assert.AreEqual(CommandLine.GetBool("-BoolString", false), false); 280 | } 281 | } 282 | } 283 | } 284 | } 285 | } 286 | -------------------------------------------------------------------------------- /Tests/Editor/CommandLineTests.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d1eae9151e3ba454eb8dfd16f75e39eb 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Tests/Editor/Unity.CommandLine.Editor.Tests.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Unity.CommandLine.Editor.Tests", 3 | "references": [ 4 | "GUID:82cc1078feb314f48a831e2beecfdba0" 5 | ], 6 | "optionalUnityReferences": [ 7 | "TestAssemblies" 8 | ], 9 | "includePlatforms": [ 10 | "Editor" 11 | ], 12 | "excludePlatforms": [], 13 | "allowUnsafeCode": false, 14 | "overrideReferences": false, 15 | "precompiledReferences": [], 16 | "autoReferenced": true, 17 | "defineConstraints": [ 18 | "UNITY_INCLUDE_TESTS" 19 | ], 20 | "versionDefines": [], 21 | "noEngineReferences": false 22 | } -------------------------------------------------------------------------------- /Tests/Editor/Unity.CommandLine.Editor.Tests.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c64119e09207be141ae6eb83e43c4188 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.oddworm.commandline", 3 | "version": "1.2.0", 4 | "displayName": "CommandLine", 5 | "description": "The CommandLine class provides the ability to parse a 'Key/Value-pair like' text document, whose values can be queried in strongly typed fashion.\n\nIt supports the types string, int, float, bool and enum. It supports C# like single and multi-line comments, as well quoted arguments, if they span across multiple words.", 6 | "unity": "2019.3", 7 | "documentationUrl": "https://github.com/pschraut/UnityCommandLine", 8 | "dependencies": { 9 | }, 10 | "keywords": [ 11 | "unity", 12 | "debug" 13 | ], 14 | "author": { 15 | "name": "Peter Schraut", 16 | "url": "http://console-dev.de" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "https://github.com/pschraut/UnityCommandLine.git" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9ba9744b2beaa1c4e8ea864e9cb71b07 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | --------------------------------------------------------------------------------