├── .gitattributes ├── .gitignore ├── Assets └── SourceConsole │ ├── Examples.meta │ ├── Examples │ ├── MemeCube.cs │ ├── MemeCube.cs.meta │ ├── Source Console - Example.unity │ └── Source Console - Example.unity.meta │ ├── Scenes.meta │ ├── Scenes │ ├── Just The Console - For Copying.unity │ └── Just The Console - For Copying.unity.meta │ ├── Scripts.meta │ ├── Scripts │ ├── SourceConsole.cs │ ├── SourceConsole.cs.meta │ ├── SourceConsoleHelper.cs │ ├── SourceConsoleHelper.cs.meta │ ├── UI.meta │ └── UI │ │ ├── Buttons.meta │ │ ├── Buttons │ │ ├── CommandOnButtonClick.cs │ │ └── CommandOnButtonClick.cs.meta │ │ ├── Console.meta │ │ └── Console │ │ ├── ConsoleAutoCompletionController.cs │ │ ├── ConsoleAutoCompletionController.cs.meta │ │ ├── ConsoleAutoCompletionManager.cs │ │ ├── ConsoleAutoCompletionManager.cs.meta │ │ ├── ConsoleCanvasController.cs │ │ ├── ConsoleCanvasController.cs.meta │ │ ├── ConsolePanelController.cs │ │ └── ConsolePanelController.cs.meta │ ├── Textures.meta │ └── Textures │ ├── Background.png │ ├── Background.png.meta │ ├── Close Button.png │ ├── Close Button.png.meta │ ├── Text Background.png │ └── Text Background.png.meta ├── LICENSE ├── ProjectSettings ├── AudioManager.asset ├── ClusterInputManager.asset ├── DynamicsManager.asset ├── EditorBuildSettings.asset ├── EditorSettings.asset ├── GraphicsSettings.asset ├── InputManager.asset ├── NavMeshAreas.asset ├── NetworkManager.asset ├── Physics2DSettings.asset ├── PresetManager.asset ├── ProjectSettings.asset ├── ProjectVersion.txt ├── QualitySettings.asset ├── TagManager.asset ├── TimeManager.asset └── UnityConnectSettings.asset └── readme.md /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Credits for this .gitignore to: https://github.com/Tayx94/graphy/blob/master/.gitignore 2 | # Ignore everything. We'll whitelist what we want to pull in. 3 | /* 4 | /*/ 5 | 6 | # Git meta files 7 | !.gitignore 8 | !.gitattributes 9 | !README.md 10 | 11 | # Whitelisted directories/files 12 | !/ProjectSettings/ 13 | !/Assets/ 14 | /Assets/* 15 | !/Assets/SourceConsole/ -------------------------------------------------------------------------------- /Assets/SourceConsole/Examples.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d13b809fc92040b4ab6f524b99ef6ce2 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/SourceConsole/Examples/MemeCube.cs: -------------------------------------------------------------------------------- 1 | using SourceConsole; 2 | using UnityEngine; 3 | 4 | public class MemeCube : MonoBehaviour { 5 | private static MemeCube Singleton; 6 | 7 | private void Awake() 8 | { 9 | Singleton = this; 10 | } 11 | 12 | private void FixedUpdate() 13 | { 14 | transform.rotation *= Quaternion.Euler(SpinRate, 0, SpinRate); 15 | } 16 | 17 | [ConCommand("memeCube_setColor", "Sets the MemeCube's color!")] 18 | public static void SetColor(float r, float g, float b) 19 | { 20 | if (Singleton == null) return; 21 | Singleton.GetComponent().material.color = new Color(r, g, b); 22 | } 23 | 24 | [ConCommand("memeCube_otherTest", "Testing the optional parameters")] 25 | public static int OtherTest(float meme = 2.65f) 26 | { 27 | SourceConsole.SourceConsole.print($"Test meme received float: {meme}"); 28 | return 2; 29 | } 30 | 31 | [ConVar("memeCube_spinRate", "Sets the MemeCube's spinrate!")] 32 | public static int SpinRate { get; set; } 33 | } 34 | -------------------------------------------------------------------------------- /Assets/SourceConsole/Examples/MemeCube.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9b35e6c564d73884fb91f376ff4a3301 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/SourceConsole/Examples/Source Console - Example.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 99c9720ab356a0642a771bea13969a05 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/SourceConsole/Scenes.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4f704ae4b4f98ae41a0bce26658850c1 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/SourceConsole/Scenes/Just The Console - For Copying.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6f6a0dbfbf7850d4fbf43f2532b88f41 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/SourceConsole/Scripts.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 58435b7e778bd7b41bad2e53abe1f076 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/SourceConsole/Scripts/SourceConsole.cs: -------------------------------------------------------------------------------- 1 | using SourceConsole.UI; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Reflection; 6 | using UnityEngine; 7 | using Debug = UnityEngine.Debug; 8 | 9 | namespace SourceConsole 10 | { 11 | public interface ConObject 12 | { 13 | int GetParametersLength(); 14 | string GetName(); 15 | string GetDescription(); 16 | } 17 | 18 | public interface IConCommandAttribute 19 | { 20 | MethodInfo MethodInfo { get; set; } 21 | } 22 | 23 | public class ConCommand : Attribute, IConCommandAttribute, ConObject 24 | { 25 | public string CustomName { get; private set; } 26 | /// 27 | /// The description rendered next to the command name when calling the List command 28 | /// 29 | public string Description { get; private set; } 30 | public MethodInfo MethodInfo { get; set; } 31 | 32 | public string GetName() 33 | { 34 | if (CustomName == "") 35 | { 36 | return MethodInfo.Name.ToLower(); 37 | } 38 | else 39 | { 40 | return CustomName.ToLower(); 41 | } 42 | } 43 | 44 | public int GetParametersLength() 45 | { 46 | return MethodInfo.GetParameters().Length; 47 | } 48 | 49 | public string GetDescription() 50 | { 51 | return Description; 52 | } 53 | 54 | public ConCommand(string name = "", string description = "") 55 | { 56 | CustomName = name; 57 | Description = description; 58 | } 59 | } 60 | 61 | public interface IConVarAttribute 62 | { 63 | FieldInfo FieldInfo { get; set; } 64 | PropertyInfo PropertyInfo { get; set; } 65 | } 66 | 67 | public class ConVar : Attribute, IConVarAttribute, ConObject 68 | { 69 | public string CustomName { get; private set; } 70 | public string Description { get; private set; } 71 | public FieldInfo FieldInfo { get; set; } 72 | public PropertyInfo PropertyInfo { get; set; } 73 | public object DefaultValue { get; set; } 74 | 75 | public MemberInfo GetObjectInfo() 76 | { 77 | if(FieldInfo != null) 78 | { 79 | return FieldInfo; 80 | } 81 | 82 | return PropertyInfo; 83 | } 84 | 85 | public string GetName() 86 | { 87 | if (CustomName == "") 88 | { 89 | return GetObjectInfo().Name.ToLower(); 90 | } 91 | else 92 | { 93 | return CustomName.ToLower(); 94 | } 95 | } 96 | 97 | public int GetParametersLength() 98 | { 99 | if(PropertyInfo != null && PropertyInfo.GetSetMethod(false) != null) 100 | { 101 | return 1; 102 | } 103 | if (FieldInfo != null) return 1; 104 | 105 | return 0; 106 | } 107 | 108 | public string GetDescription() 109 | { 110 | return Description; 111 | } 112 | 113 | public ConVar(string customName = "", string description = "", object defaultValue = null) 114 | { 115 | CustomName = customName; 116 | Description = description; 117 | DefaultValue = defaultValue; 118 | } 119 | } 120 | 121 | public static class SourceConsole 122 | { 123 | private class DuplicateCommandException : Exception 124 | { 125 | public DuplicateCommandException(string message) : base(message) { } 126 | } 127 | 128 | private static List CommandNamesCache = new List(); 129 | private static List Commands; 130 | private static List Convars; 131 | 132 | [ConVar("", "Should the console show the full error stack when an error occurs? Or simply the exception message?")] 133 | public static bool ShowFullErrorStack 134 | { 135 | get; set; 136 | } 137 | 138 | //Ignoring C# name convention to allow for conveniant and fast typing when needing to debug stuff quickly 139 | [ConCommand] 140 | public static void print(object str) 141 | { 142 | ConsolePanelController.print(str); 143 | } 144 | 145 | //Ignoring C# name convention to allow for conveniant and fast typing when needing to debug stuff quickly 146 | [ConCommand] 147 | public static void warn(object str) 148 | { 149 | ConsolePanelController.print($"{str}"); 150 | } 151 | 152 | //Ignoring C# name convention to allow for conveniant and fast typing when needing to debug stuff quickly 153 | [ConCommand] 154 | public static void error(object str) 155 | { 156 | ConsolePanelController.print($"{str}"); 157 | } 158 | 159 | //Ignoring C# name convention to allow for conveniant and fast typing when needing to debug stuff quickly 160 | [ConCommand] 161 | public static void success(object str) 162 | { 163 | ConsolePanelController.print($"{str}"); 164 | } 165 | 166 | [ConCommand] 167 | public static void Quit() 168 | { 169 | Application.Quit(); 170 | } 171 | 172 | [ConCommand("", "Used to test the console's performance when handling a lot of new lines")] 173 | public static void Spam(int amount = 100) 174 | { 175 | for(int i = 0; i < amount; i++) 176 | { 177 | print("Line #" + i); 178 | } 179 | } 180 | 181 | public static int RefreshCommands() 182 | { 183 | return RefreshCommands(new Assembly[] { Assembly.GetAssembly(typeof(SourceConsole)) }); 184 | } 185 | 186 | public static int RefreshCommands(Assembly[] assemblies) 187 | { 188 | float startTime = Time.realtimeSinceStartup; 189 | 190 | CommandNamesCache.Clear(); 191 | 192 | Commands = new List(); 193 | Convars = new List(); 194 | 195 | foreach(var command in SourceConsoleHelper.FindMethodAttributes(assemblies)) 196 | { 197 | string name = command.GetName(); 198 | 199 | if (CommandNamesCache.Contains(name)) 200 | { 201 | error($"Failed to load command '{name}'! A command/convar already exists with that name!"); 202 | throw new DuplicateCommandException($"Failed to load command '{name}'! A command/convar already exists with that name!"); 203 | } 204 | 205 | CommandNamesCache.Add(name); 206 | Commands.Add(command); 207 | } 208 | Commands = Commands.OrderBy(c => c.GetName()).ToList(); 209 | 210 | foreach (var convar in SourceConsoleHelper.FindPropertyAttributes(assemblies)) 211 | { 212 | string name = convar.GetName(); 213 | 214 | if (CommandNamesCache.Contains(name)) 215 | { 216 | error($"Failed to load convar '{name}'! A command/convar already exists with that name!"); 217 | throw new DuplicateCommandException($"Failed to load convar '{name}'! A command/convar already exists with that name!"); 218 | } 219 | 220 | if(convar.DefaultValue != null) 221 | { 222 | try 223 | { 224 | if(convar.PropertyInfo != null) 225 | { 226 | convar.PropertyInfo.SetValue(null, convar.DefaultValue); 227 | } 228 | else 229 | { 230 | convar.FieldInfo.SetValue(null, convar.DefaultValue); 231 | } 232 | } 233 | catch (Exception e) 234 | { 235 | if (ShowFullErrorStack) 236 | { 237 | error(e); 238 | } 239 | else 240 | { 241 | error($"{e.GetType().Name}: {e.Message}"); 242 | } 243 | } 244 | } 245 | 246 | CommandNamesCache.Add(name); 247 | Convars.Add(convar); 248 | } 249 | Convars = Convars.OrderBy(c => c.GetName()).ToList(); 250 | 251 | print("Refreshed Commands in " + (Time.realtimeSinceStartup - startTime).ToString("0.000") + " seconds"); 252 | return Commands.Count + Convars.Count; 253 | } 254 | 255 | public static List GetAllConObjectsThatMatch(string input) 256 | { 257 | List objects = new List(); 258 | 259 | if (input.Trim() == "") return objects; 260 | input = input.ToLower(); 261 | 262 | foreach (var command in Commands) 263 | { 264 | string cleanName = command.GetName().Trim(); 265 | 266 | if(cleanName.StartsWith(input) || SourceConsoleHelper.LevenshteinDistance(cleanName, input) < 2 && cleanName != input) 267 | { 268 | objects.Add(command); 269 | } 270 | } 271 | 272 | foreach (var convar in Convars) 273 | { 274 | string cleanName = convar.GetName().Trim(); 275 | 276 | if (cleanName.StartsWith(input) || SourceConsoleHelper.LevenshteinDistance(cleanName, input) < 2 && cleanName != input) 277 | { 278 | objects.Add(convar); 279 | } 280 | } 281 | 282 | objects = objects.OrderBy(c => c.GetName()).ToList(); 283 | 284 | return objects; 285 | } 286 | 287 | public static ConCommand GetConCommandByName(string name) 288 | { 289 | foreach(var command in Commands) 290 | { 291 | if(command.GetName().Trim() == name.ToLower()) 292 | { 293 | return command; 294 | } 295 | } 296 | 297 | return null; 298 | } 299 | 300 | public static ConVar GetConVarByName(string name) 301 | { 302 | foreach (var convar in Convars) 303 | { 304 | if (convar.GetName().Trim() == name.ToLower()) 305 | { 306 | return convar; 307 | } 308 | } 309 | 310 | return null; 311 | } 312 | 313 | public static ConObject GetConObjectByName(string name) 314 | { 315 | ConCommand command = GetConCommandByName(name); 316 | if (command != null) return command; 317 | ConVar convar = GetConVarByName(name); 318 | if (convar != null) return convar; 319 | 320 | return null; 321 | } 322 | 323 | public static object ExecuteCommand(ConCommand command, params object[] args) 324 | { 325 | //This code is for automatically putting in default parameter values if they exist and weren't specified explicitly by the user 326 | var parameters = command.MethodInfo.GetParameters(); 327 | if (args == null || args.Length < parameters.Length) 328 | { 329 | object[] newArgs = new object[parameters.Length]; 330 | 331 | for (int i = 0; i < newArgs.Length; i++) 332 | { 333 | //if we have inputted args and current i is less than the length of original user-inputted args 334 | if (args != null && i <= args.Length) 335 | { 336 | //Copy old args to new args array 337 | newArgs[i] = args[i]; 338 | } 339 | else //if args is null or we have passed the length of original user-inputted args 340 | { 341 | if (parameters[i].HasDefaultValue) newArgs[i] = parameters[i].DefaultValue; 342 | } 343 | } 344 | args = newArgs; 345 | } 346 | 347 | try 348 | { 349 | if (command.MethodInfo.ReturnType == typeof(void)) 350 | { 351 | command.MethodInfo.Invoke(null, args); 352 | } 353 | else 354 | { 355 | return command.MethodInfo.Invoke(null, args); 356 | } 357 | }catch(Exception e) 358 | { 359 | if (ShowFullErrorStack) 360 | { 361 | error(e); 362 | } 363 | else 364 | { 365 | error($"{e.GetType().Name}: {e.Message}"); 366 | } 367 | } 368 | 369 | return null; 370 | } 371 | 372 | public static object ExecuteConvar(ConVar convar, object arg) 373 | { 374 | if(arg == null) 375 | { 376 | if (convar.PropertyInfo != null) 377 | { 378 | return convar.PropertyInfo.GetMethod.Invoke(null, null); 379 | } 380 | else 381 | { 382 | return convar.FieldInfo.GetValue(null); 383 | } 384 | } 385 | else 386 | { 387 | //if user has inputted multiple arguments into the console input string, we just use the first one 388 | object singleArg = null; 389 | if(arg is object[]) 390 | { 391 | if(((object[])arg).Length > 0) 392 | { 393 | singleArg = ((object[])arg)[0]; 394 | } 395 | } 396 | else 397 | { 398 | singleArg = arg; 399 | } 400 | 401 | try 402 | { 403 | if (convar.PropertyInfo != null) 404 | { 405 | convar.PropertyInfo.SetValue(null, singleArg); 406 | } 407 | else 408 | { 409 | convar.FieldInfo.SetValue(null, singleArg); 410 | } 411 | } 412 | catch (Exception e) 413 | { 414 | if (ShowFullErrorStack) 415 | { 416 | error(e); 417 | } 418 | else 419 | { 420 | error($"{e.GetType().Name}: {e.Message}"); 421 | } 422 | } 423 | } 424 | 425 | return null; 426 | } 427 | 428 | /// 429 | /// Given a string, executes it normally as if it were a console-input 430 | /// 431 | /// 432 | public static void ExecuteString(string input) 433 | { 434 | if (input == "") return; 435 | 436 | string[] parts = input.Split(' '); //split the input string into parts 437 | string commandName = parts[0]; //get just the command name 438 | 439 | var command = GetConObjectByName(commandName); 440 | if (command != null) //if the command exists 441 | { 442 | string[] cleanParts = SourceConsoleHelper.CleanArgumentsArray(parts, command.GetParametersLength()); 443 | 444 | if (command is ConCommand) 445 | { 446 | ExecuteCommand((ConCommand)command, SourceConsoleHelper.CastParameters(cleanParts)); 447 | } 448 | else //if no command, then convar 449 | { 450 | ExecuteConvar((ConVar)command, SourceConsoleHelper.CastParameters(cleanParts)); 451 | } 452 | } 453 | } 454 | } 455 | } 456 | -------------------------------------------------------------------------------- /Assets/SourceConsole/Scripts/SourceConsole.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0e05cdd47e098254bb52c176a90397ec 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/SourceConsole/Scripts/SourceConsoleHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using UnityEngine; 6 | 7 | namespace SourceConsole 8 | { 9 | public static class SourceConsoleHelper 10 | { 11 | public static bool CastParameter(string parameter, out object result) 12 | { 13 | //Bool 14 | bool parsedBool; 15 | bool parsed = bool.TryParse(parameter, out parsedBool); 16 | if (parsed) 17 | { 18 | result = parsedBool; 19 | return true; 20 | } 21 | 22 | //Int 23 | int parsedInt; 24 | parsed = int.TryParse(parameter, out parsedInt); 25 | if (parsed) 26 | { 27 | result = parsedInt; 28 | return true; 29 | } 30 | 31 | //Float 32 | float parsedFloat; 33 | parsed = float.TryParse(parameter, out parsedFloat); 34 | if (parsed) 35 | { 36 | result = parsedFloat; 37 | return true; 38 | } 39 | 40 | //String 41 | result = parameter; 42 | return false; 43 | } 44 | 45 | public static object[] CastParameters(string[] parameters) 46 | { 47 | if (parameters.Length == 0) 48 | { 49 | return null; 50 | } 51 | 52 | object[] result = new object[parameters.Length]; 53 | for (int i = 0; i < parameters.Length; i++) 54 | { 55 | CastParameter(parameters[i], out result[i]); 56 | } 57 | return result; 58 | } 59 | 60 | public static AttributeType[] FindMethodAttributes(Assembly[] assemblies, bool staticOnly = true) where AttributeType : Attribute, IConCommandAttribute 61 | { 62 | List result = new List(); 63 | 64 | for (int current = 0; current < assemblies.Length; current++) 65 | { 66 | MethodInfo[] methods = assemblies[current].GetTypes() 67 | .SelectMany(t => t.GetMethods()) 68 | .Where(m => m.GetCustomAttributes(typeof(AttributeType), true).Length > 0) 69 | .ToArray(); 70 | 71 | for (int i = 0; i < methods.Length; i++) 72 | { 73 | if (staticOnly && !methods[i].IsStatic) 74 | { 75 | continue; 76 | } 77 | 78 | AttributeType attribute = ExtractAttribute(methods[i]); 79 | attribute.MethodInfo = methods[i]; 80 | result.Add(attribute); 81 | } 82 | } 83 | 84 | return result.ToArray(); 85 | } 86 | 87 | public static AttributeType[] FindPropertyAttributes(Assembly[] assemblies) where AttributeType : Attribute, IConVarAttribute 88 | { 89 | List result = new List(); 90 | 91 | for (int current = 0; current < assemblies.Length; current++) 92 | { 93 | PropertyInfo[] properties = assemblies[current].GetTypes() 94 | .SelectMany(t => t.GetProperties()) 95 | .Where(m => m.GetCustomAttributes(typeof(AttributeType), true).Length > 0) 96 | .ToArray(); 97 | 98 | for (int i = 0; i < properties.Length; i++) 99 | { 100 | AttributeType attribute = ExtractAttribute(properties[i]); 101 | attribute.PropertyInfo = properties[i]; 102 | result.Add(attribute); 103 | } 104 | } 105 | 106 | for (int current = 0; current < assemblies.Length; current++) 107 | { 108 | FieldInfo[] properties = assemblies[current].GetTypes() 109 | .SelectMany(t => t.GetFields()) 110 | .Where(m => m.GetCustomAttributes(typeof(AttributeType), true).Length > 0) 111 | .ToArray(); 112 | 113 | for (int i = 0; i < properties.Length; i++) 114 | { 115 | AttributeType attribute = ExtractAttribute(properties[i]); 116 | attribute.FieldInfo = properties[i]; 117 | result.Add(attribute); 118 | } 119 | } 120 | 121 | return result.ToArray(); 122 | } 123 | 124 | public static T ExtractAttribute(MethodInfo method) where T : Attribute 125 | { 126 | object[] attributes = method.GetCustomAttributes(typeof(T), true); 127 | for (int a = 0; a < attributes.Length; a++) 128 | { 129 | if (attributes[a].GetType() == typeof(T)) 130 | { 131 | return (T)attributes[a]; 132 | } 133 | } 134 | return default(T); 135 | } 136 | 137 | public static T ExtractAttribute(PropertyInfo method) where T : Attribute 138 | { 139 | object[] attributes = method.GetCustomAttributes(typeof(T), true); 140 | for (int a = 0; a < attributes.Length; a++) 141 | { 142 | if (attributes[a].GetType() == typeof(T)) 143 | { 144 | return (T)attributes[a]; 145 | } 146 | } 147 | return default(T); 148 | } 149 | 150 | public static T ExtractAttribute(FieldInfo method) where T : Attribute 151 | { 152 | object[] attributes = method.GetCustomAttributes(typeof(T), true); 153 | for (int a = 0; a < attributes.Length; a++) 154 | { 155 | if (attributes[a].GetType() == typeof(T)) 156 | { 157 | return (T)attributes[a]; 158 | } 159 | } 160 | return default(T); 161 | } 162 | 163 | /// 164 | /// Given a string of a command, for example 'print "nice meme"', this simply removes the command name, and returns '"nice meme"' 165 | /// 166 | /// 167 | /// 168 | public static string[] GetArgumentPartsOnly(string[] parts) 169 | { 170 | if (parts.Length <= 1) return new string[0]; //if no args 171 | 172 | string[] argParts = new string[parts.Length - 1]; 173 | 174 | for (int i = 1; i < parts.Length; i++) 175 | { 176 | argParts[i - 1] = parts[i]; 177 | } 178 | 179 | return argParts; 180 | } 181 | 182 | /// 183 | /// removes the first element (the command name), and splits string by space unless it's in quotes and returns the result array 184 | /// 185 | /// 186 | /// 187 | public static string[] CleanArgumentsArray(string[] parts, int maxParameters) 188 | { 189 | string str = string.Join(" ", GetArgumentPartsOnly(parts)); 190 | 191 | var newPartsArray = str.Split('"', '\'') 192 | .Select((element, index) => index % 2 == 0 // If even index 193 | ? element.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries) // Split the item 194 | : new string[] { element }) // Keep the entire item 195 | .SelectMany(element => element).ToList(); 196 | 197 | if (newPartsArray.Count > maxParameters) 198 | { 199 | newPartsArray.RemoveRange(newPartsArray.Count - (newPartsArray.Count - maxParameters), newPartsArray.Count - maxParameters); 200 | } 201 | 202 | return newPartsArray.ToArray(); 203 | } 204 | 205 | //Taken from/credit to: https://www.csharpstar.com/csharp-string-distance-algorithm/ 206 | /// 207 | /// Compute the distance between two strings. 208 | /// 209 | public static int LevenshteinDistance(string s, string t) 210 | { 211 | int n = s.Length; 212 | int m = t.Length; 213 | int[,] d = new int[n + 1, m + 1]; 214 | 215 | // Step 1 216 | if (n == 0) 217 | { 218 | return m; 219 | } 220 | 221 | if (m == 0) 222 | { 223 | return n; 224 | } 225 | 226 | // Step 2 227 | for (int i = 0; i <= n; d[i, 0] = i++) 228 | { 229 | } 230 | 231 | for (int j = 0; j <= m; d[0, j] = j++) 232 | { 233 | } 234 | 235 | // Step 3 236 | for (int i = 1; i <= n; i++) 237 | { 238 | //Step 4 239 | for (int j = 1; j <= m; j++) 240 | { 241 | // Step 5 242 | int cost = (t[j - 1] == s[i - 1]) ? 0 : 1; 243 | 244 | // Step 6 245 | d[i, j] = Math.Min( 246 | Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1), 247 | d[i - 1, j - 1] + cost); 248 | } 249 | } 250 | // Step 7 251 | return d[n, m]; 252 | } 253 | } 254 | } 255 | -------------------------------------------------------------------------------- /Assets/SourceConsole/Scripts/SourceConsoleHelper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 256fbe4e6c770324cb8e3129bba9e857 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/SourceConsole/Scripts/UI.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1e2fe1470189a92438b46edb06b5fb2d 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/SourceConsole/Scripts/UI/Buttons.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: da0f23fe680ccc24db0ab62ef297bf06 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/SourceConsole/Scripts/UI/Buttons/CommandOnButtonClick.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.UI; 3 | 4 | namespace SourceConsole.UI 5 | { 6 | [RequireComponent(typeof(Button))] 7 | public class CommandOnButtonClick : MonoBehaviour 8 | { 9 | [SerializeField] 10 | private string command = ""; 11 | 12 | private Button button; 13 | 14 | private void Awake() 15 | { 16 | button = GetComponent