From 1c897e75303b550dd8be48c73d2f28ed45189fec Mon Sep 17 00:00:00 2001 From: Nathan Adams Date: Sat, 26 May 2012 18:26:46 -0500 Subject: [PATCH 01/11] Starting the integration for XNACC --HG-- branch : xnacc-integration --- axios/Axios_WP7.csproj | 2 + axios/Axios_Windows.csproj | 2 + axios/Axios_Windows.csproj.user | 2 +- axios/Axios_Xbox_360.csproj | 2 + axios/XNACC/CommandConsoleBase.cs | 2951 ++++++++++++++++++ axios/XNACC/CommandConsoleBaseSharedTypes.cs | 123 + 6 files changed, 3081 insertions(+), 1 deletion(-) create mode 100644 axios/XNACC/CommandConsoleBase.cs create mode 100644 axios/XNACC/CommandConsoleBaseSharedTypes.cs diff --git a/axios/Axios_WP7.csproj b/axios/Axios_WP7.csproj index 70983a8..897dcf9 100644 --- a/axios/Axios_WP7.csproj +++ b/axios/Axios_WP7.csproj @@ -232,6 +232,8 @@ + + diff --git a/axios/Axios_Windows.csproj b/axios/Axios_Windows.csproj index 9f27321..195fc78 100644 --- a/axios/Axios_Windows.csproj +++ b/axios/Axios_Windows.csproj @@ -276,6 +276,8 @@ + + diff --git a/axios/Axios_Windows.csproj.user b/axios/Axios_Windows.csproj.user index 76fe5a5..566c009 100644 --- a/axios/Axios_Windows.csproj.user +++ b/axios/Axios_Windows.csproj.user @@ -1,6 +1,6 @@  - ProjectFiles + ShowAllFiles \ No newline at end of file diff --git a/axios/Axios_Xbox_360.csproj b/axios/Axios_Xbox_360.csproj index 4ccbed8..9ce7f6f 100644 --- a/axios/Axios_Xbox_360.csproj +++ b/axios/Axios_Xbox_360.csproj @@ -224,6 +224,8 @@ + + diff --git a/axios/XNACC/CommandConsoleBase.cs b/axios/XNACC/CommandConsoleBase.cs new file mode 100644 index 0000000..604b95e --- /dev/null +++ b/axios/XNACC/CommandConsoleBase.cs @@ -0,0 +1,2951 @@ +#region Using Statements +#if WINDOWS +using System; +using System.Collections.Generic; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Content; +using Microsoft.Xna.Framework.Graphics; +using Microsoft.Xna.Framework.Input; +using System.Text; +using System.Threading; +using System.IO; +using System.ComponentModel; +using System.Reflection; +using JRTS.XNA.Console.BaseTypes; +using System.Diagnostics; +#endif +#endregion + +/* + * CommandConsoleBase.cs + * (C) 2009-2011, James R. Twine of JRTwine Software, LLC + * + * ************************************************************************* + * * THIS CODE IS PROVIDED WITH NO WARRANTY - YOU USE IT AT YOUR OWN RISK! * + * ************************************************************************* + * + * This Code Originated With Code From the "XNA Console Component Sample" by Kevin Jurkowski. + * At The Time Of This Writing, The Original Code Was Available + * From: http://www.ziggyware.com/readarticle.php?article_id=163 + * (But, Ziggyware Is No Longer There! :<) + * + * Changes, (C) 2009, James R. Twine of JRTwine Software, LLC + * Changes: + * Converted to XNA 3.0 + * More input keys supported (Symbols, digits, etc.) + * Better(?) Way of extending supported commands and their handlers, parameters, help, etc. + * Slight Q&D colorizing of output to differenate commands and output + * Extracted keyboard-specific functionality into an iterface + * Command history + * Command completion + * Scrollable log/output + * Base class supports "standard" commands + * Support for "hidden" commands + * Customizable scalable drawing + * Custom functions (basically macros that support parameters) + * Binding commands/functions to -Key combinations (when the console is closed) + * + * And possibly some other fun stuff...! + * + * More Changes, (C) 2010, James R. Twine of JRTwine Software, LLC + * Changes: + * Expanded key bindings to support modifiers + * Converted to XNA 4.0 + * Graphics optimizations + * + * Still MORE Changes, (C) 2011, James R. Twine of JRTwine Software, LLC + * Changes: + * Additional ways to hook into command execution/handling + * Addition of dynamic Console Variables (cvars) + * Support for external managed functions that can manipulate cvars and do... just about anything + * Ability to lock-down functions, bindings and external functions (to prevent tampering with a released game) + * TODO: Wanna wrap command handlers into an "ICCCommand" interface... + * + * + * + * + * +*/ + +//NA: XNACC currently is only supported on Windows due to the fact that SortedDictionary is not avaiable on WP7/Xbox 360 +//NA: Seriously Microsoft? +#if WINDOWS +/// Namespace that contains code related to the XNACC (CommandConsole) component +namespace JRTS.XNA.Console +{ + /// Base functionality of the XNACC (CommandConsole) component + public class CommandConsoleBase : DrawableGameComponent + { + #region EventArgs Object + /// EA object for the CVarModified event + public class CVarModifiedEventArgs : EventArgs + { + /// The actual CVar for this event + public CVar Value + { + get; + protected set; + } + /// Constructor for this object + /// The cvar that has been modified + public CVarModifiedEventArgs(CVar value) + { + Value = value; + return; + } + } + /// EA object for handling console command execution + public class CommandConsoleEventArgs : EventArgs + { + /// The actual command line being executed + public string CmdLine + { + get; + set; + } + /// Flag indicating if the command has been handled by an event handler; if true, no further processing is done on the command + public bool Handled + { + get; + set; + } + /// Constructor for this object + /// The command line being processed + public CommandConsoleEventArgs( string cmdLine ) + { + CmdLine = cmdLine; + Handled = false; + return; + } + } + + #endregion + + #region Command Object + /// This object contains information on a single Command that the console understands. + protected class CmdObject : IComparable< CmdObject > + { + /// Default constructor for the Command Object + public CmdObject() + : this( String.Empty, String.Empty, null, false, String.Empty, 0, 0 ) + { + return; + } + /// Constuct an instance of the Command Object + /// The command identifier (no whitespace, please) + /// The (brief) help for this command + /// The delegate method that fires when the command is encountered + public CmdObject( string command, string help, Action cmdAction ) + : this( command, help, cmdAction, false, String.Empty, 0, 0 ) + { + return; + } + /// Constuct an instance of the Command Object + /// The command identifier (no whitespace, please) + /// The (brief) help for this command + /// The delegate method that fires when the command is encountered + /// Is this a secret command (not shown in the help information) + public CmdObject( string command, string help, Action cmdAction, bool isSecret ) + : this( command, help, cmdAction, isSecret, String.Empty, 0, 0 ) + { + return; + } + /// Constuct an instance of the Command Object + /// The command identifier (no whitespace, please) + /// The (brief) help for this command + /// The delegate method that fires when the command is encountered + /// Is this a secret command (not shown in the help information) + /// The detailed help for this command + public CmdObject( string command, string help, Action cmdAction, bool isSecret, string detailedHelp ) + : this( command, help, cmdAction, isSecret, detailedHelp, 0, 0 ) + { + return; + } + /// Constuct an instance of the Command Object + /// The command identifier (no whitespace, please) + /// The (brief) help for this command + /// The delegate method that fires when the command is encountered + /// Is this a secret command (not shown in the help information) + /// The detailed help for this command + /// The minimum number of parameters for this command (0 == no minimum) + /// The maximum number of parameters for this command (0 == no maximum) + public CmdObject( string command, string help, Action cmdAction, bool isSecret, string detailedHelp, int minParams, int maxParams ) + { + Command = command; + CommandHelp = help; + if( cmdAction != null ) + { + CmdEvent += cmdAction; + } + IsSecret = isSecret; + CommandHelpDetailed = detailedHelp; + MinParameters = minParams; + MaxParameters = maxParams; + + return; + + } + /// Required - The command (single word, no spaces, and all commands will be converted to lowercase) + public String Command { get; set; } + + /// Optional - Summary help information that briefly describes the command + public String CommandHelp { get; set; } + + /// Optional - Detailed help information that explains the command and its usage + public String CommandHelpDetailed { get; set; } + + /// The minimum number of parameters the command expects (set to zero for no minimum) + public int MinParameters { get; set; } + + /// The maximum number of parameters the command expects (set to zero for no maximum) + public int MaxParameters { get; set; } + + /// Indicates if this command is secret -- if so, it will not appear when the user types + /// "help" and will not participate in command completion + public bool IsSecret { get; set; } + + /// The event fired when the associated command is received + public event Action CmdEvent; + + /// This method fires the associated Delegate + /// The complete command line. Not just the command's parameters! + /// This method is public to allow for artificial triggering of commands. + public void TriggerEvent( String[] cmdLine ) + { + if( CmdEvent != null ) + { + CmdEvent.Invoke( cmdLine ); + } + } + #region IComparable Members + + /// Compare this object with another object instance + /// The object to compare to + /// The result of comparing the object's Command strings + public int CompareTo( CmdObject other ) + { + return( Command.CompareTo( other.Command ) ); + } + #endregion + } + #endregion + + #region Function Object + /// This object contains information on a custom function that the console understands. + protected class FuncObject : IComparable< FuncObject > + { + /// The function name + public String Function + { + get; + protected set; + } + /// The code to execute when the function executes + public IList FunctionImpl + { + get; + protected set; + } + /// Constructor for the Function Object + /// The name of the Function + /// The implementation of the Function + public FuncObject( string funcName, string[] funcImpl ) + { + if( String.IsNullOrWhiteSpace( funcName ) ) + { + throw new ArgumentException( "The function name must not be whitespace.", "funcName" ); + } + Function = funcName.Trim().ToLowerInvariant(); + FunctionImpl = new List( funcImpl ); + + return; + } + /// Indicates if this function is secret -- it will not appear when the user types "help" + public bool IsSecret + { + get; + set; + } + /// Provide a string representation of this object + /// A string containing a representation of the object + public override string ToString() + { + StringBuilder sbCmdLine = new StringBuilder( FunctionImpl.Count * 32 ); + + foreach( string line in FunctionImpl ) + { + if( sbCmdLine.Length > 0 ) + { + sbCmdLine.Append( "; " ); + } + sbCmdLine.Append( line ); + } + return ( String.Format( "{0} -> {1}", Function, sbCmdLine.ToString() ) ); + } + + #region IComparable Members + + /// Compare this object with another object instance + /// The object to compare to + /// The result of comparing the object's Function strings + public int CompareTo( FuncObject other ) + { + return( Function.CompareTo( other.Function ) ); + } + + #endregion + } + #endregion + + #region External Function Object + /// This object contains information on an external function (implemented in a .NET assembly) that the console understands. + protected class ExternalFuncObject : IComparable + { + /// Collection Of Known Class Instances + static protected Dictionary< string, object > ms_classInstances = new Dictionary( 8 ); + + /// The method name + public String MethodName + { + get; + set; + } + /// Is this external function secret? + public bool IsSecret + { + get; + protected set; + } + /// Command line used to create the function + public String CommandLine + { + get; + set; + } + /// The actual method metadata + protected MethodInfo m_method; + /// The actual class instance + protected object m_classInstance; + /// Construct an instance of this object, storing information on the specified method + /// The name/path of the assembly/DLL to load from + /// The fully qualified, case-sensitive class name + /// The case-sensitive name of the method to get + public ExternalFuncObject( string assembly, string className, string methodName ) + : this( assembly, className, methodName, false ) + { + return; + } + /// Construct an instance of this object, storing information on the specified method + /// The name/path of the assembly/DLL to load from + /// The fully qualified, case-sensitive class name + /// The case-sensitive name of the method to get + /// Is this a secret/hidden ExFunc? + public ExternalFuncObject( string assembly, string className, string methodName, bool isSecret ) + { + Type classType = null; + + // See If We Already Have An Instance Of This Class + if( ms_classInstances.TryGetValue( className, + out m_classInstance ) == false ) + { // We Do Not, So Create And Store One + + Assembly asm = null; + + try + { + asm = Assembly.LoadFrom( assembly ); + } + catch( FileNotFoundException ) + { + asm = Assembly.LoadFrom( assembly + ".dll" ); + } + classType = asm.GetType( className, false ); + if( classType == null ) + { + classType = asm.GetType( assembly + "." + className, true ); + } + m_classInstance = Activator.CreateInstance( classType ); + ms_classInstances[ methodName ] = m_classInstance; + } + // Store Name Of Method And + MethodName = methodName; + m_method = classType.GetMethod( methodName ); + IsSecret = isSecret; + + return; + } + + /// Attempt to invoke the previously loaded method dynamically + /// Parameters that should be passed to the method, or null if none + /// A string return value from the method, or String.Empty if a null is returned or if the method returns void + public string Invoke( params object[] parameters ) + { + string ret; + + try + { + object returnVal = m_method.Invoke( m_classInstance, parameters ); + + ret = ( returnVal != null ) ? returnVal.ToString() : String.Empty; + } + catch( Exception ex ) + { + ret = ex.Message; + } + return( ret ); + } + /// Provide a string representation of this object + /// A string containing a representation of the object + public override string ToString() + { + return ( String.Format( "{0}::{1}", m_classInstance, MethodName ) ); + } + #region IComparable Members + + /// Compare this object with another object instance + /// The object to compare to + /// The result of comparing the object's MethodName strings + public int CompareTo( ExternalFuncObject other ) + { + return ( MethodName.CompareTo( other.MethodName ) ); + } + + #endregion + } + #endregion + + #region Binding Object + /// This object stores information on a bound key + protected class BindingObject : IComparable< BindingObject > + { + /// Modifier keys for this key-binding + [Flags] + public enum EModifier + { + /// No modifier keys associated with this Binding + None = 0, + /// CTRL modifier key is associated with this Binding + Ctrl = 1, + /// SHIFT modifier key is associated with this Binding + Shift = 2, + /// ALT modifier key is associated with this Binding + Alt = 4, + } + /// The command/function to execute when the bound key is hit + public string _text; + /// The key that the command/function is bound to + public Keys _key; + /// The modifier key for _key (Ctrl, Alt, Shift) - modifiers use the LEFT version of the key identifier + public EModifier _modifierKeys; + /// Gets the modifier key(s) in human readable form + /// A string representing this binding's modifiers, or an empty string if none + public string GetModifierString() + { + StringBuilder sb = new StringBuilder( 32 ); + bool usesCtrl = ( ( _modifierKeys & EModifier.Ctrl ) == EModifier.Ctrl ); + bool usesShift = ( ( _modifierKeys & EModifier.Shift ) == EModifier.Shift ); + bool usesAlt = ( ( _modifierKeys & EModifier.Alt ) == EModifier.Alt ); + bool first = false; + + if( usesCtrl ) + { + sb.Append( "CTRL" ); + first = false; + } + if( usesAlt ) + { + if( !first ) + { + sb.Append( '+' ); + } + sb.Append( "ALT" ); + } + if( usesShift ) + { + if( !first ) + { + sb.Append( '+' ); + } + sb.Append( "SHIFT" ); + } + if( sb.Length > 0 ) + { + sb.Append( '+' ); + } + return( sb.ToString() ); + } + /// Convert this binding object into an informational string + /// The informational string + public override string ToString() + { + return ( String.Format( "<{0}{1}> -> {2}", GetModifierString(), _key, _text ) ); + } + + #region IComparable Members + + /// Compare this object with another object instance + /// The object to compare to + /// Nothing - Not Implemented Yet + public int CompareTo( BindingObject other ) + { + throw new NotImplementedException(); + } + + #endregion + } + #endregion + + #region Fields + #region Command Processing + // -- Command Processing-Related Fields... + /// Collection Of Command Objects. + protected static SortedDictionary ms_commands = new SortedDictionary(); + /// Collection Of function Objects. + protected static SortedDictionary ms_functions = new SortedDictionary(); + /// Collection Of External Functions. + protected static SortedDictionary ms_externalFunctions = new SortedDictionary(); + /// Collection Of Binding Objects. + protected static List ms_bindings = new List( 8 ); + + /// Colleciton Of Partial Command Matches + protected static List ms_partialCmdMatches = new List( 8 ); + /// Symbol table for the console variables + protected Dictionary m_cVars = new Dictionary( 8 ); + /// Match index for the last partial command + protected int m_cmdMatchIndex = 0; + /// The last command match found + protected string m_lastCmdMatch = String.Empty; + /// The command line itself + protected string m_commandLine = String.Empty; + + /// Function-related functions are locked out + protected bool m_functionsLocked = false; + /// Binding-related functions are locked out + protected bool m_bindingsLocked = false; + /// External-Function-related functions are locked out + protected bool m_exfunsLocked = false; + #endregion + + #region Drawing and Graphics + // -- Drawing/Graphics-Related Fields... + /// Drawing object + protected SpriteBatch m_spriteBatch; + /// Font used for drawing the console's text + protected SpriteFont m_consoleFont; + /// Rectangle for the console area + protected Rectangle m_consoleRect; + /// Location of the command line + protected Vector2 m_commandPos; + /// Hight for the current console font + protected Vector2 m_stringHeight; + /// Offset for the command line + protected float m_commandStringHeightOffset; + /// Number of characters that can fit in the console area's width + protected int m_screenCharWidth; + /// Width of the console area + protected int m_width; + /// Height of the console area + protected int m_height; + /// Scale for drawing the console + protected float m_scale = 1.0f; + #endregion + + #region Scrolling and Logging + // -- Scrolling-Related Fields... + /// The number of lines that are visible in the console area + protected int m_linesVisibleOnScreen; + /// Used for drawing an indicator to show that lines are scrolled above + protected bool m_linesAbove; + /// Used for drawing an indicator to show that lines are scrolled below + protected bool m_linesBelow; + /// Where the log starts at (for scrolling) + protected int m_logStart = 0; + /// Specifies the limit of the log buffer + protected int m_logLimit = 512; + + // -- Logging-Related Fields... + /// The path to the log shadow (copy of all logged lines) + protected string m_logShadowFilePath = String.Empty; + /// Flag indicating that the log is being shadowed + protected bool m_logShadowEnabled = false; + /// The stream for shadowing the log to + protected StreamWriter m_logShadowFile = null; + /// Storage for the log + protected List m_log = new List( 256 ); + #endregion + + #region Command History + // Command History-Related Fields + /// Specifies the limit of the command history + protected int m_cmdHistoryLimit = 512; + /// Collection of command history + protected List m_cmdHistory = new List( 128 ); + /// Current index in the command history + protected int m_cmdHistoryIndex = 0; + /// Scanning (up/down) index in of the command history + protected int m_cmdHistoryScanIndex = 0; + #endregion + + #region Input Processing + // Input related fields + /// Time for key repeat + protected DateTime m_keyRepeatTime = DateTime.MinValue; + /// Character translation for ALL keyboard keys - contains an element for all values in the Keys enumeration + protected List m_xlateAllKeys; + /// Character translation for ALL keyboard keys, shifted - contains an element for all values in the Keys enumeration + protected List m_xlateAllKeysShifted; + #endregion + #endregion + + #region Events + /// Event fired right before handling/execution of a command. Allows interception of normal command processing. + public event EventHandler PreCommandExecutedEvent; + /// Event fired when a console variable has been created/modified + public event EventHandler CVarModifiedEvent; + #endregion + + #region Properties + /// Interface to the keyboard used for console input + public IConsoleKeyboard Keyboard + { + get; + protected set; + } + /// Image/Texture used to fade the text underneath the console's text area + public Texture2D FadeImage + { + get; + set; + } + /// The color used to produce the fade + public Color FadeColor + { + get; + set; + } + /// Drawing scale for the console + public float Scale + { + get + { + return m_scale; + } + set + { + m_scale = value; + m_stringHeight = Vector2.Zero; + } + } + /// Indicates if the console is active or not + public bool Active + { + get; + set; + } + /// The prompt shown for the command line + public string Prompt + { + get; + set; + } + /// The color used to display entered commands + public Color CommandColor + { + get; + set; + } + /// The color used to display error messages + public Color ErrorColor + { + get; + set; + } + /// The color used to display output from executed commands + public Color OutputColor + { + get; + set; + } + /// The color used to display "normal" output messages + public Color NormalColor + { + get; + set; + } + /// The font used for text display + public SpriteFont Font + { + get { return( m_consoleFont ); } + set + { + m_consoleFont = value; + m_stringHeight = Vector2.Zero; + } + } + /// Sets/Gets the height of the console window + public int Height + { + get + { + return( m_height ); + } + set + { + m_height = value; + m_stringHeight = Vector2.Zero; + } + } + /// Sets/Gets the width of the console window + public int Width + { + get + { + return( m_width ); + } + set + { + m_width = value; + m_stringHeight = Vector2.Zero; + } + } + #endregion + + #region Initialization + /// Constructor for this base class + /// The Game object for the owning/managing game + public CommandConsoleBase( Game game ) + : this( game, null ) + { + return; + } + /// Constructor for this base class + /// The Game object for the owning/managing game + /// The font that the console should use to draw its text + public CommandConsoleBase( Game game, SpriteFont fontToUse ) + : base( game ) + { + m_consoleFont = fontToUse; + Prompt = "_>"; + CommandColor = Color.SteelBlue; + ErrorColor = Color.Firebrick; + OutputColor = Color.Yellow; + NormalColor = Color.Silver; + + return; + } + /// Primary initialization function + public override void Initialize() + { + base.Initialize(); + // OK - This Seems Very Heavyweight, And It Kinda Is. But It Allows For + // Easy Mapping Of A "Keys" Value To Any String, Which Makes It Possible + // To Create Single Key Macros, Like Binding On Steroids, And Also Makes + // It Easy To Handle Non-US Or Gaming Keyboards. + + // The Format Of The Lines Below Is A Comment Line That Identifies The Array + // Indices, Which Correspond To Values In The "Keys" Enumeration, And Then + // The Actual Values For Those Indices. + m_xlateAllKeys = new List( new[] { + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , + // 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 + "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , + // 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 + " ", "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , + // 48 49 50 51 52 53 54 55 56 57 58 59 60 61 63 63 + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "" , "" , "" , "" , "" , "" , + // 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 + "" , "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", + // 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 + "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "" , "" , "" , "" , "" , + // 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "*", "+", ",", "-", ".", "/", + // 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 + "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , + // 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 + "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , + // 144 145 146 147 148 149 150 151 152 153 154 155 156 157 159 159 + "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , + // 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 + "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , + // 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 + "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , ";", "=", ",", "-", ".", "/", + // 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 + "", "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , + // 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 + "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "[", "\\","]", "'", "8", + // 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 + "" , "" ,"|", "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , + // 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 + "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , + } ); + + // Create Collection Of Characters (Strings) For All Possible SHIFTED Key Values... + m_xlateAllKeysShifted = new List( new[] { + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , + // 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 + "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , + // 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 + " ", "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , + // 48 49 50 51 52 53 54 55 56 57 58 59 60 61 63 63 + ")", "!", "@", "#", "$", "%", "^", "&", "*", "(", "" , "" , "" , "" , "" , "" , + // 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 + "" , "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", + // 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 + "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "" , "" , "" , "" , "" , + // 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "*", "+", ",", "-", ".", "/", + // 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 + "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , + // 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 + "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , + // 144 145 146 147 148 149 150 151 152 153 154 155 156 157 159 159 + "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , + // 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 + "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , + // 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 + "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , ":", "+", "<", "_", ">", "?", + // 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 + "", "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , + // 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 + "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "{", "|", "}","\"", "*", + // 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 + "" , "" ,"\\", "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , + // 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 + "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , + } ); + return; + } + #endregion + + #region Graphics Content + /// Load content for this component + /// The ContentManager that should be used + public virtual void LoadContent( ContentManager content ) + { + m_spriteBatch = new SpriteBatch( GraphicsDevice ); + + m_width = GraphicsDevice.Viewport.Width; + m_height = ( GraphicsDevice.Viewport.Height / 3 ); + + InitializeCommands(); + base.LoadContent(); + + return; + } + #endregion + + #region Update and Draw + /// + /// Recalculates measurements required for text display and wrapping. Sets the m_consoleRect, + /// m_commandPos and m_linesVisibleOnScreen fields. + /// + protected virtual void RecalculateHeightSettings() + { + m_consoleRect = new Rectangle( 0, 0, m_width, m_height ); + m_commandPos = new Vector2( 10.0f, m_height - m_commandStringHeightOffset ); + m_linesVisibleOnScreen = ( (int)( m_height / m_stringHeight.Y ) - 1 ); + + return; + } + /// Update this component + /// Game's time + public override void Update( GameTime gameTime ) + { + CheckInput(); + + base.Update( gameTime ); + } + /// Draw the console + /// Game's time + public override void Draw( GameTime gameTime ) + { + m_linesAbove = m_linesBelow = false; + + if( Active == true ) + { + m_spriteBatch.Begin( SpriteSortMode.Deferred, BlendState.AlphaBlend ); + + if( FadeImage != null ) + { + // Fade The Console Area With The Specified Texture/Image... + m_spriteBatch.Draw( FadeImage, m_consoleRect, FadeColor ); + } + // + // Cache Pre-Calculatable Values... + // + if( m_stringHeight == Vector2.Zero ) + { + m_stringHeight = Vector2.Multiply( m_consoleFont.MeasureString( Prompt ), Scale ); + m_screenCharWidth = (int)( ( m_width / m_stringHeight.X ) * 2 ); + m_commandStringHeightOffset = ( ( m_stringHeight.Y * 2.0f ) - 4.0f ); + RecalculateHeightSettings(); + } + // Draw command string + m_spriteBatch.DrawString( m_consoleFont, Prompt + m_commandLine, + m_commandPos, Color.Yellow, 0.0f, Vector2.Zero, + Scale, SpriteEffects.None, 0.0f ); + + // Draw log + Vector2 linePos = new Vector2( m_consoleRect.Left + 10.0f, ( m_commandPos.Y - m_stringHeight.Y ) ); + + int endLine = Math.Max( 0, ( ( m_log.Count - m_logStart ) - 1 ) ); + + if( m_logStart != 0 ) + { + m_linesBelow = true; + } + for( int i = endLine; i > 0; i-- ) + { + if( linePos.Y <= m_consoleRect.Top ) + { + m_linesAbove = true; + break; + } + String line = m_log[ i ]; + + if( line.Length == 0 ) + { + continue; + } + Char firstChar = line[ 0 ]; + + if( firstChar <= '\x03' ) + { + Color outColor = OutputColor; + + if( firstChar == '\x01' ) + { + outColor = CommandColor; + } + else if( firstChar == '\x02' ) + { + outColor = ErrorColor; + } + else if( firstChar == '\x03' ) + { + outColor = OutputColor; + } + m_spriteBatch.DrawString( m_consoleFont, line.Substring( 1 ), + linePos, outColor, 0.0f, Vector2.Zero, Scale, + SpriteEffects.None, 0.0f ); + } + else + { + m_spriteBatch.DrawString( m_consoleFont, line, linePos, + NormalColor, 0.0f, Vector2.Zero, Scale, + SpriteEffects.None, 0.0f ); + } + linePos.Y -= m_stringHeight.Y; + } + if( m_linesAbove ) + { + Vector2 starPos = new Vector2( m_width - 10.0f, m_consoleRect.Top ); + + m_spriteBatch.DrawString( m_consoleFont, "^", starPos, + ErrorColor, 0.0f, Vector2.Zero, Scale, + SpriteEffects.None, 0.0f ); + } + if( m_linesBelow ) + { + Vector2 starPos = new Vector2( m_width - 10.0f, ( m_commandPos.Y - m_stringHeight.Y ) ); + + m_spriteBatch.DrawString( m_consoleFont, "V", starPos, + ErrorColor, 0.0f, Vector2.Zero, Scale, + SpriteEffects.None, 0.0f ); + } + m_spriteBatch.End(); + } + base.Draw( gameTime ); + + return; + } + #endregion + + #region Input Handling + /// Process a keyboard key. Assumes that the Keyboard property is not null! + /// The key to process + protected virtual void ProcessKey( Keys key ) + { + // Space - Special Handling To Eliminate Leading Whitespace + if( ( key == Keys.Space ) && ( !String.IsNullOrWhiteSpace( m_commandLine ) ) ) + { + m_commandLine += " "; + ms_partialCmdMatches.Clear(); + m_lastCmdMatch = String.Empty; + } + // Command History... + else if( key == Keys.Up ) + { + if( m_cmdHistory.Count == 0 ) + { + return; + } + m_cmdHistoryScanIndex--; + if( m_cmdHistoryScanIndex < 0 ) + { + m_cmdHistoryScanIndex = 0; + } + m_commandLine = m_cmdHistory[ m_cmdHistoryScanIndex ]; + ms_partialCmdMatches.Clear(); + } + else if( key == Keys.Down ) + { + if( m_cmdHistory.Count == 0 ) + { + return; + } + m_cmdHistoryScanIndex++; + if( m_cmdHistoryScanIndex >= m_cmdHistory.Count ) + { + m_cmdHistoryScanIndex = ( m_cmdHistory.Count - 1 ); + } + m_commandLine = m_cmdHistory[ m_cmdHistoryScanIndex ]; + ms_partialCmdMatches.Clear(); + } + // Log Scrolling... + else if( ( key == Keys.PageUp ) && ( m_linesVisibleOnScreen < m_log.Count ) ) + { + m_logStart += ( m_linesVisibleOnScreen - 1 ); + if( m_logStart >= ( m_log.Count - m_linesVisibleOnScreen ) ) + { + m_logStart = ( m_log.Count - m_linesVisibleOnScreen + 1 ); + } + } + else if( ( key == Keys.PageDown ) && ( m_linesVisibleOnScreen < m_log.Count ) ) + { + m_logStart -= ( m_linesVisibleOnScreen - 1 ); + if( m_logStart < 0 ) + { + m_logStart = 0; + } + } + // Check input for Escape + else if( key == Keys.Escape ) + { + m_commandLine = String.Empty; + ms_partialCmdMatches.Clear(); + m_lastCmdMatch = String.Empty; + } + // Check input for Backspace + else if( ( key == Keys.Back ) && ( !String.IsNullOrEmpty( m_commandLine ) ) && + ( m_commandLine != Prompt ) ) + { + m_commandLine = m_commandLine.Remove( m_commandLine.Length - 1, 1 ); + ms_partialCmdMatches.Clear(); + m_lastCmdMatch = String.Empty; + } + // Check input for Tab + else if( ( key == Keys.Tab ) && ( !String.IsNullOrEmpty( m_commandLine ) ) && + ( m_commandLine != Prompt ) ) + { + // Rebuild Partial Command Matches If List Is Empty/Reset + if( ms_partialCmdMatches.Count == 0 ) + { + BuildCommandMatches( m_commandLine ); + m_cmdMatchIndex = 0; + } + // If We Have Partial Matches, Circularly Iterate Over Them And Show Them + if( ms_partialCmdMatches.Count > 0 ) + { + if( m_cmdMatchIndex >= ms_partialCmdMatches.Count ) + { + m_cmdMatchIndex = 0; + } + m_commandLine = ms_partialCmdMatches[ m_cmdMatchIndex++ ]; + } + } + // Enter - Commit Command Line + else if( ( key == Keys.Enter ) && ( !String.IsNullOrWhiteSpace( m_commandLine ) ) ) + { + AddToLog( "\x01" + m_commandLine ); + m_logStart = 0; + ExecuteCommandLine( true ); + m_commandLine = String.Empty; + } + // Any Other Key, Process As Character (Even If Not A Real Character Key) + else + { + // Handle Shifted Chars + if( ( Keyboard.CurrentKeyboardState.IsKeyDown( Keys.LeftShift ) ) || + ( Keyboard.CurrentKeyboardState.IsKeyDown( Keys.RightShift ) ) ) + { + m_commandLine += m_xlateAllKeysShifted[ (int)key ]; + } + else + { + m_commandLine += m_xlateAllKeys[ (int)key ]; + } + ms_partialCmdMatches.Clear(); + m_lastCmdMatch = String.Empty; + } + return; + } + + /// Check input from the provided keyboard interface + protected virtual void CheckInput() + { + //InputManager im = InputManager.Instance; + + // If No Interface To The Keyboard, Stop Here + if( Keyboard == null ) + { + return; + } + // Toggle the console menu on or off + if( Keyboard.NewlyPressedKeys.Contains( Keys.OemTilde ) ) + { + Active = !Active; + return; + } + // Only Check Bindings If The Console Is Not Active + if( Active == false ) + { + CheckBindings(); + return; + } + if( Keyboard.HeldKeys.Count > 0 ) + { + if( DateTime.Now > m_keyRepeatTime ) + { + ProcessKey( Keyboard.HeldKeys[ 0 ] ); + m_keyRepeatTime = DateTime.Now.AddMilliseconds( 100 ); + } + } + if( Keyboard.NewlyPressedKeys.Count > 0 ) + { + ProcessKey( Keyboard.NewlyPressedKeys[ 0 ] ); + m_keyRepeatTime = DateTime.Now.AddMilliseconds( 250 ); + } + return; + } + + /// Get binding information from a "binding string" input by the user + /// The binding string to parse + /// ref - the modifier keys for the binding + /// ref - the key for the binding + /// true if the binding string was understood, false if not + bool GetKeyBindingInfo( string bindString, ref BindingObject.EModifier bindModifiers, ref Keys bindKey ) + { + bindString = bindString.ToUpper(); + if( bindString.Length == 1 ) + { + char keyChar = ( bindString.Trim().ToUpper()[ 0 ] ); + int keyOffset = keyChar - 'A'; + bindKey = ( Keys.A + keyOffset ); + // Default To ALT Binding... + // bindModifiers = BindingObject.EModifier.Alt; + + if( ( bindKey >= Keys.A ) && ( bindKey <= Keys.Z ) ) + { + return( true ); + } + else + { + return( false ); + } + } + string[] keyTokens = bindString.Split( '+' ); + bool parsed = false; + + foreach( string ktoken in keyTokens ) + { + if( ktoken == "ALT" ) + { + bindModifiers |= BindingObject.EModifier.Alt; + continue; + } + if( ktoken == "CTRL" ) + { + bindModifiers |= BindingObject.EModifier.Ctrl; + continue; + } + if( ktoken == "SHIFT" ) + { + bindModifiers |= BindingObject.EModifier.Shift; + continue; + } + if( ktoken.Length == 1 ) + { + int keyOffset = ktoken[ 0 ] - 'A'; + bindKey = ( Keys.A + keyOffset ); + if( ( bindKey >= Keys.A ) && ( bindKey <= Keys.B ) ) + { + parsed = true; + } + else + { + parsed = false; + } + break; + } + else if( ( ( ktoken.Length == 2 ) || ( ktoken.Length == 3 ) ) && ( ktoken[ 0 ] == 'F' ) ) + { + // F-Key Binding... + int fNumber = int.Parse( ktoken.Substring( 1 ) ); + Keys fKey = ( Keys.Divide + fNumber ); + + if( ( fKey >= Keys.F1 ) && ( fKey <= Keys.F24 ) ) + { + bindKey = fKey; + parsed = true; + } + else + { + parsed = false; + } + break; + } + else + { + break; + } + } + return ( parsed ); + } + /// Check for bound keys - bound keys use the <ALT> modifier + protected virtual void CheckBindings() + { + // Stop Here If No Bindings Are Set, Or No Interface To The Keyboard + if( ( ms_bindings.Count == 0 ) || ( Keyboard == null ) ) + { + return; + } + //InputManager im = InputManager.Instance; + + BindingObject.EModifier modifierKeys = BindingObject.EModifier.None; + bool altDown = ( ( Keyboard.CurrentKeyboardState.IsKeyDown( Keys.LeftAlt ) ) || ( Keyboard.CurrentKeyboardState.IsKeyDown( Keys.RightAlt ) ) ); + bool ctrlDown = ( ( Keyboard.CurrentKeyboardState.IsKeyDown( Keys.LeftControl ) ) || ( Keyboard.CurrentKeyboardState.IsKeyDown( Keys.RightControl ) ) ); + bool shiftDown = ( ( Keyboard.CurrentKeyboardState.IsKeyDown( Keys.LeftShift ) ) || ( Keyboard.CurrentKeyboardState.IsKeyDown( Keys.RightShift ) ) ); + + if( altDown ) modifierKeys |= BindingObject.EModifier.Alt; + if( ctrlDown ) modifierKeys |= BindingObject.EModifier.Ctrl; + if( shiftDown ) modifierKeys |= BindingObject.EModifier.Shift; + + foreach( BindingObject bs in ms_bindings ) + { + // See if the Binding's modifier keys are down, and its command key. If so, execute the command. + if( ( ( bs._modifierKeys & modifierKeys ) == modifierKeys ) && + ( Keyboard.NewlyPressedKeys.Contains( bs._key ) ) ) + { + m_commandLine = bs._text; + ExecuteCommandLine( false ); + m_commandLine = String.Empty; + } + } + return; + } + + /// Build command matches for the specified (sub)string. + /// The partial command to try to match + /// Nothing + /// Resets the ms_partialCmdMatches collection + protected virtual void BuildCommandMatches( string cmdMatch ) + { + ms_partialCmdMatches.Clear(); + + // Iterate Over Commands And Store Non-Secret Commands That Match Substring + foreach( CmdObject cmd in ms_commands.Values ) + { + if( ( !cmd.IsSecret ) && ( cmd.Command.StartsWith( cmdMatch ) ) ) + { + ms_partialCmdMatches.Add( cmd.Command ); + } + } + // Iterate Over Funcitons And Store Non-Secret Functions That Match Substring + foreach( FuncObject func in ms_functions.Values ) + { + if( ( !func.IsSecret ) && ( func.Function.StartsWith( cmdMatch ) ) ) + { + ms_partialCmdMatches.Add( func.Function ); + } + } + // Iterate Over External Funcitons And Store Non-Secret Functions That Match Substring + foreach( ExternalFuncObject extFunc in ms_externalFunctions.Values ) + { + if( ( extFunc.IsSecret ) && ( extFunc.MethodName.StartsWith( cmdMatch ) ) ) + { + ms_partialCmdMatches.Add( extFunc.MethodName ); + } + } + return; + } + + #endregion + + #region Log Output + /// Add executed command output to the log. + /// The output text to add + public void AddOutputToLog( string text ) + { + if( String.IsNullOrEmpty( text ) ) + { + return; + } + AddToLog( "\x03" + DateTime.Now.ToString( "hh:mm:ss.fff" ) + "-" + text ); + + return; + } + + /// Add error output to the log. + /// The error text to add + public void AddErrorToLog( string text ) + { + if( String.IsNullOrEmpty( text ) ) + { + return; + } + AddToLog( "\x02" + DateTime.Now.ToString( "hh:mm:ss.fff" ) + "-" + text ); + + return; + } + + /// Add executed command to the log. + /// The command text to add + public void AddCommandToLog( string text ) + { + if( String.IsNullOrEmpty( text ) ) + { + return; + } + AddToLog( "\x01" + DateTime.Now.ToString( "hh:mm:ss.fff" ) + "-" + text ); + + return; + } + + /// Method to add generic output text to the log + /// The text to add + public void AddToLog( string text ) + { + if( String.IsNullOrEmpty( text ) ) + { + return; + } + if( m_logShadowEnabled ) + { + m_logShadowFile.WriteLine( text ); + } + lock( m_log ) + { + if( ( m_screenCharWidth == 0 ) || ( text.Length < m_screenCharWidth ) ) + { + m_log.Add( text ); + return; + } + List lines = BreakTextIntoList( text, m_consoleFont, ( m_consoleRect.Width - 10 ), Scale ); + + foreach( String line in lines ) + { + m_log.Add( line ); + } + if( m_log.Count > m_logLimit ) + { + int remove = Math.Max( 32, ( m_log.Count - m_logLimit ) ); + + remove--; + m_log.RemoveRange( 0, remove ); + } + } + return; + } + + // JRT Only Evaluate This Once... + private static readonly char[] DELIMITERS = " .:,/\\-+=_[]{}()?!><|".ToCharArray(); + + /// + /// Break text up into separate lines to make it fit. + /// (Originally From MS Provided Code - RBG Starter Kit/Template - Text Helper Methods) + /// + /// The text to be broken up. + /// The font used to measure the width of the text. + /// The maximum width of each line, in pixels. + /// Scale that should be used for the lines. + protected static List BreakTextIntoList( string text, SpriteFont font, + int rowWidth, float scale ) + { + // check parameters + if( String.IsNullOrEmpty( text ) ) + { + return( new List( new[] { String.Empty } ) ); + } + if( font == null ) + { + throw new ArgumentNullException( "font" ); + } + if( rowWidth <= 0 ) + { + throw new ArgumentOutOfRangeException( "rowWidth" ); + } + // create the list + List lines = new List( text.Length / rowWidth ); + + // check for trivial text + if( String.IsNullOrEmpty( text ) ) + { + lines.Add( String.Empty ); + return lines; + } + char cLead = text[ 0 ]; + + // + // JRT Q&D Way To Get Rid Of The Coloring Characters - They Are Not Written + // Out To The Screen, Anyway... + // + if( ( cLead == '\x01' ) || ( cLead == '\x02' ) || ( cLead == '\x03' ) ) + { + text = text.Substring( 1 ); + } + else + { + cLead = '\x00'; + } + // check for text that fits on a single line + if( ( font.MeasureString( text ).X * scale ) <= rowWidth ) + { + if( cLead != '\x00' ) + { + text = text.Insert( 0, cLead.ToString() ); + } + return lines; + } + + StringBuilder sb = new StringBuilder( 256 ); + int textIndex = 0; + int currentDelimiterIndex = 0; + + // JRT This Loop Will Cause The Occasional Leading Delimiter Character If The + // Line Break Occurs At A Place Where To Delimiters Are Next To Each + // Other, But I Consider This An Acceptable Tradeoff. + // + // Lines That Cannot Be Broken-Up Will Wrap, But The Wrapping Will Not + // Be Optimal. + while( textIndex < text.Length ) + { + String appendedString; + int lastLen = textIndex; + + currentDelimiterIndex = text.IndexOfAny( DELIMITERS, textIndex ); + if( currentDelimiterIndex == -1 ) + { + appendedString = text.Substring( textIndex ); + } + else + { + appendedString = text.Substring( textIndex, ( currentDelimiterIndex - textIndex + 1 ) ); + } + sb.Append( appendedString ); + if( ( font.MeasureString( sb.ToString() ).X * scale ) > rowWidth ) + { + sb.Remove( ( sb.Length - appendedString.Length ), appendedString.Length ); + if( cLead != '\x00' ) + { + sb.Insert( 0, cLead ); + } + lines.Add( sb.ToString() ); + sb.Length = 0; + text = text.Substring( textIndex ); + textIndex = 0; + } + else + { + textIndex += appendedString.Length; + } + } + if( sb.Length > 0 ) + { + lines.Add( sb.ToString() ); + } + return( lines ); + } + #endregion + + #region Built-In Commands + /// Sets up the standard/built-in commands. + protected void InitializeStandardCommands() + { + CmdObject cmdStruct = new CmdObject(); + + cmdStruct.Command = "help"; + cmdStruct.CommandHelp = "show game console help, or help for a specific command"; + cmdStruct.CommandHelpDetailed = "help [command]"; + cmdStruct.CmdEvent += new Action( CommandConsoleBase_Help ); + ms_commands[ cmdStruct.Command ] = cmdStruct; + + cmdStruct = new CmdObject(); + cmdStruct.Command = "quit"; + cmdStruct.CommandHelp = "immediately quit the game"; + cmdStruct.CmdEvent += new Action( CommandConsoleBase_Quit ); + ms_commands[ cmdStruct.Command ] = cmdStruct; + + cmdStruct = new CmdObject(); + cmdStruct.Command = "close"; + cmdStruct.CommandHelp = "close the command console."; + cmdStruct.CmdEvent += new Action( CommandConsoleBase_Close ); + ms_commands[ cmdStruct.Command ] = cmdStruct; + + cmdStruct = new CmdObject(); + cmdStruct.Command = "consoleheight"; + cmdStruct.MinParameters = 0; + cmdStruct.MaxParameters = 1; + cmdStruct.CommandHelp = "set the height of the console window in pixels"; + cmdStruct.CommandHelpDetailed = "consoleheight "; + cmdStruct.CmdEvent +=new Action(CommandConsoleBase_ConsoleHeight); + ms_commands[ cmdStruct.Command ] = cmdStruct; + + cmdStruct = new CmdObject(); + cmdStruct.Command = "consolescale"; + cmdStruct.MinParameters = 0; + cmdStruct.MaxParameters = 1; + cmdStruct.CommandHelp = "set the scale of the console window (1.0=100%, 0.75=75%, 0.5=50%, etc.)"; + cmdStruct.CommandHelpDetailed = "consolescale"; + cmdStruct.CmdEvent += new Action( CommandConsoleBase_ConsoleScale ); + ms_commands[ cmdStruct.Command ] = cmdStruct; + + cmdStruct = new CmdObject(); + cmdStruct.Command = "cvar"; + cmdStruct.MinParameters = 1; + cmdStruct.MaxParameters = 3; + cmdStruct.CommandHelp = "add a new console variable (cvar), or modify an existing one"; + cmdStruct.CommandHelpDetailed = "cvar [Type] -- examples: cvar myVar MyValue, cvar myInt Int32 42"; + cmdStruct.CmdEvent += new Action( CommandConsoleBase_CVar ); + ms_commands[ cmdStruct.Command ] = cmdStruct; + + cmdStruct = new CmdObject(); + cmdStruct.Command = "cvars"; + cmdStruct.MinParameters = 0; + cmdStruct.MaxParameters = 0; + cmdStruct.CommandHelp = "view the available console variables (cvars)"; + cmdStruct.CmdEvent += new Action( CommandConsoleBase_CVars ); + ms_commands[ cmdStruct.Command ] = cmdStruct; + + cmdStruct = new CmdObject(); + cmdStruct.Command = "gc"; + cmdStruct.CommandHelp = "immediately perform full garbage collection"; + cmdStruct.CmdEvent += new Action( CommandConsoleBase_GC ); + ms_commands[ cmdStruct.Command ] = cmdStruct; + + cmdStruct = new CmdObject(); + cmdStruct.Command = "shadowlog"; + cmdStruct.MinParameters = 0; + cmdStruct.MaxParameters = 2; + cmdStruct.CommandHelp = "shadows the log to an external file, optionally truncating the external file first"; + cmdStruct.CommandHelpDetailed = "shadowlog "; + cmdStruct.CmdEvent += new Action( CommandConsoleBase_ShadowLog ); + ms_commands[ cmdStruct.Command ] = cmdStruct; + + cmdStruct = new CmdObject(); + cmdStruct.Command = "noshadowlog"; + cmdStruct.CommandHelp = "turns off shadowing of the log to an external file"; + cmdStruct.CmdEvent += new Action( CommandConsoleBase_NoShadowLog ); + ms_commands[ cmdStruct.Command ] = cmdStruct; + + cmdStruct = new CmdObject(); + cmdStruct.Command = "clear"; + cmdStruct.CommandHelp = "clears the console log"; + cmdStruct.CmdEvent += new Action( CommandConsoleBase_Clear ); + ms_commands[ cmdStruct.Command ] = cmdStruct; + + cmdStruct = new CmdObject(); + cmdStruct.Command = "loglimit"; + cmdStruct.MaxParameters = 1; + cmdStruct.CommandHelp = "sets the console log (buffer) limit"; + cmdStruct.CommandHelpDetailed = "loglimit "; + cmdStruct.CmdEvent += new Action( CommandConsoleBase_LogLimit ); + ms_commands[ cmdStruct.Command ] = cmdStruct; + + cmdStruct = new CmdObject(); + cmdStruct.Command = "memoryinfo"; + cmdStruct.CommandHelp = "display memory info"; + cmdStruct.CmdEvent += new Action( CommandConsoleBase_MemInfo ); + ms_commands[ cmdStruct.Command ] = cmdStruct; + + cmdStruct = new CmdObject(); + cmdStruct.Command = "exfunc"; + cmdStruct.CommandHelp = "load external function from an assembly"; + cmdStruct.CommandHelpDetailed = "exfunc "; + cmdStruct.MinParameters = 3; + cmdStruct.MaxParameters = 3; + cmdStruct.CmdEvent += new Action( CommandConsoleBase_ExFunc ); + ms_commands[ cmdStruct.Command ] = cmdStruct; + + cmdStruct = new CmdObject(); + cmdStruct.Command = "systeminfo"; + cmdStruct.CommandHelp = "display system info"; + cmdStruct.CmdEvent += new Action( CommandConsoleBase_SystemInfo ); + ms_commands[ cmdStruct.Command ] = cmdStruct; + + cmdStruct = new CmdObject(); + cmdStruct.Command = "sleep"; + cmdStruct.MinParameters = 1; + cmdStruct.MaxParameters = 1; + cmdStruct.CommandHelp = "eause execution of the command console"; + cmdStruct.CommandHelpDetailed = "sleep "; + cmdStruct.CmdEvent += new Action( CommandConsoleBase_Sleep ); + ms_commands[ cmdStruct.Command ] = cmdStruct; + + cmdStruct = new CmdObject(); + cmdStruct.Command = "exec"; + cmdStruct.MinParameters = 1; + cmdStruct.MaxParameters = 1; + cmdStruct.CommandHelp = "execute contents of a file as commands in this console"; + cmdStruct.CommandHelpDetailed = "exec "; + cmdStruct.CmdEvent += new Action( CommandConsoleBase_Exec ); + ms_commands[ cmdStruct.Command ] = cmdStruct; + + cmdStruct = new CmdObject(); + cmdStruct.Command = "savelog"; + cmdStruct.MinParameters = 1; + cmdStruct.MaxParameters = 1; + cmdStruct.CommandHelp = "save the console log to a file"; + cmdStruct.CommandHelpDetailed = "savelog "; + cmdStruct.CmdEvent += new Action( CommandConsoleBase_SaveLog ); + ms_commands[ cmdStruct.Command ] = cmdStruct; + + cmdStruct = new CmdObject(); + cmdStruct.Command = "functions"; + cmdStruct.CommandHelp = "display all current functions"; + cmdStruct.CmdEvent += new Action( CommandConsoleBase_Functions ); + ms_commands[ cmdStruct.Command ] = cmdStruct; + + cmdStruct = new CmdObject(); + cmdStruct.Command = "nofunctions"; + cmdStruct.CommandHelp = "disable the ability to add/remove functions"; + cmdStruct.CmdEvent += new Action( CommandConsoleBase_NoFunctions ); + ms_commands[ cmdStruct.Command ] = cmdStruct; + + cmdStruct = new CmdObject(); + cmdStruct.Command = "exfuncs"; + cmdStruct.CommandHelp = "display all current external functions"; + cmdStruct.CmdEvent += new Action( CommandConsoleBase_ExFuncs ); + ms_commands[ cmdStruct.Command ] = cmdStruct; + + cmdStruct = new CmdObject(); + cmdStruct.Command = "noexfuncs"; + cmdStruct.CommandHelp = "disable the ability to add/remove exfuncs"; + cmdStruct.CmdEvent += new Action( CommandConsoleBase_NoExFunctions ); + ms_commands[ cmdStruct.Command ] = cmdStruct; + + cmdStruct = new CmdObject(); + cmdStruct.Command = "bindings"; + cmdStruct.CommandHelp = "display all current key bindings"; + cmdStruct.CmdEvent += new Action( CommandConsoleBase_Bindings ); + ms_commands[ cmdStruct.Command ] = cmdStruct; + + cmdStruct = new CmdObject(); + cmdStruct.Command = "nobindings"; + cmdStruct.CommandHelp = "disable the ability to add/remove bindings"; + cmdStruct.CmdEvent += new Action( CommandConsoleBase_NoBindings ); + ms_commands[ cmdStruct.Command ] = cmdStruct; + + cmdStruct = new CmdObject(); + cmdStruct.Command = "resetbindings"; + cmdStruct.CommandHelp = "clear all key bindings"; + cmdStruct.CmdEvent += new Action( CommandConsoleBase_ResetBindings ); + ms_commands[ cmdStruct.Command ] = cmdStruct; + + cmdStruct = new CmdObject(); + cmdStruct.Command = "resetexfuncs"; + cmdStruct.CommandHelp = "clear all external functions"; + cmdStruct.CmdEvent += new Action( CommandConsoleBase_ResetExFuncs ); + ms_commands[ cmdStruct.Command ] = cmdStruct; + + cmdStruct = new CmdObject(); + cmdStruct.Command = "resetfunctions"; + cmdStruct.CommandHelp = "clear all functions"; + cmdStruct.CmdEvent += new Action( CommandConsoleBase_ResetFunctions); + ms_commands[ cmdStruct.Command ] = cmdStruct; + + cmdStruct = new CmdObject(); + cmdStruct.Command = "bind"; + cmdStruct.MinParameters = 2; + cmdStruct.MaxParameters = 0; + cmdStruct.CommandHelp = "bind an key to a command or function"; + cmdStruct.CommandHelpDetailed = "bind -- examples: 'bind ALT+G gc', 'bind CTRL+SHIFT+Q quit'"; + cmdStruct.CmdEvent += new Action( CommandConsoleBase_Bind ); + ms_commands[ cmdStruct.Command ] = cmdStruct; + + cmdStruct = new CmdObject(); + cmdStruct.Command = "unbind"; + cmdStruct.MinParameters = 1; + cmdStruct.MaxParameters = 1; + cmdStruct.CommandHelp = "remove a previous key binding"; + cmdStruct.CommandHelpDetailed = "unbind "; + cmdStruct.CmdEvent += new Action( CommandConsoleBase_UnBind ); + ms_commands[ cmdStruct.Command ] = cmdStruct; + + cmdStruct = new CmdObject(); + cmdStruct.Command = "function"; + cmdStruct.MinParameters = 1; + cmdStruct.MaxParameters = 0; + cmdStruct.CommandHelp = "create a new function"; + cmdStruct.CommandHelpDetailed = "function ;;<...>"; + cmdStruct.CmdEvent += new Action( CommandConsoleBase_Function ); + ms_commands[ cmdStruct.Command ] = cmdStruct; + + cmdStruct = new CmdObject(); + cmdStruct.Command = "exportfunctions"; + cmdStruct.MinParameters = 1; + cmdStruct.MaxParameters = 1; + cmdStruct.CommandHelp = "export functions to a file that can be EXEC-ed"; + cmdStruct.CommandHelpDetailed = "exportfunctions "; + cmdStruct.CmdEvent += new Action( CommandConsoleBase_ExportFunctions ); + ms_commands[ cmdStruct.Command ] = cmdStruct; + + cmdStruct = new CmdObject(); + cmdStruct.Command = "exportexfuncs"; + cmdStruct.MinParameters = 1; + cmdStruct.MaxParameters = 1; + cmdStruct.CommandHelp = "export exfuncs to a file that can be EXEC-ed"; + cmdStruct.CommandHelpDetailed = "exportexfuncs "; + cmdStruct.CmdEvent += new Action( CommandConsoleBase_ExportExFuncs ); + ms_commands[ cmdStruct.Command ] = cmdStruct; + + cmdStruct = new CmdObject(); + cmdStruct.Command = "exportbindings"; + cmdStruct.MinParameters = 1; + cmdStruct.MaxParameters = 1; + cmdStruct.CommandHelp = "export binding information to a file that can be EXEC-ed"; + cmdStruct.CommandHelpDetailed = "exportbindings "; + cmdStruct.CmdEvent += new Action( CommandConsoleBase_ExportBindings ); + ms_commands[ cmdStruct.Command ] = cmdStruct; + + cmdStruct = new CmdObject(); + cmdStruct.Command = "exportstate"; + cmdStruct.MinParameters = 1; + cmdStruct.MaxParameters = 1; + cmdStruct.CommandHelp = "export the console's complete state information to a file that can be EXEC-ed, so that the state can be restored later"; + cmdStruct.CommandHelpDetailed = "exportstate "; + cmdStruct.CmdEvent += new Action( CommandConsoleBase_ExportState ); + ms_commands[ cmdStruct.Command ] = cmdStruct; + + return; + } + + /// + /// Overridable method used to add custom commands to the console. + /// + public virtual void InitializeCustomCommands() + { + return; + } + + /// Initialize the Console's Commands -- is normally called via + public void InitializeCommands() + { + InitializeStandardCommands(); + + InitializeCustomCommands(); + + return; + } + + /// + /// Add a command to the internal collection of commands. Throws an exception if duplicate identifiers are detected. + /// + /// Command object to add + protected void AddCommand( CmdObject cmdStruct ) + { + cmdStruct.Command = cmdStruct.Command.Trim().ToLowerInvariant(); + + if( ms_commands.ContainsKey( cmdStruct.Command ) ) + { + throw( new InvalidOperationException( String.Format( + "Command {0} already exists in the command list.", + cmdStruct.Command ) ) ); + } + if( ms_functions.ContainsKey( cmdStruct.Command ) ) + { + throw ( new InvalidOperationException( String.Format( + "Command {0} already exists as a function.", + cmdStruct.Command ) ) ); + } + ms_commands[ cmdStruct.Command ] = cmdStruct; + + return; + } + + /// + /// Add a function to the internal collection of functions. Throws an exception if duplicate identifiers are detected. + /// + /// Function object to add + protected void AddFunction( FuncObject fnStruct ) + { + if( ms_commands.ContainsKey( fnStruct.Function ) ) + { + throw ( new InvalidOperationException( String.Format( + "Function {0} already exists as a command.", + fnStruct.Function ) ) ); + } + if( ms_functions.ContainsKey( fnStruct.Function ) ) + { + throw ( new InvalidOperationException( String.Format( + "Function {0} already exists in the function list.", + fnStruct.Function ) ) ); + } + ms_functions[ fnStruct.Function ] = fnStruct; + + return; + } + #endregion + + #region Command Processing + /// Execute the specified Function + /// Function to execute + /// Parameters for the function + protected void ExecuteFunction( FuncObject fnStruct, string[] parameters ) + { + foreach( string line in fnStruct.FunctionImpl ) + { + m_commandLine = line; + // If Function Parameters Exist, And Function Takes Parameters + if( ( parameters != null ) && ( m_commandLine.IndexOf( '%' ) != -1 ) ) + { + int count = 0; + + // Build The Resulting Command Line + foreach( string param in parameters ) + { + m_commandLine = m_commandLine.Replace( "%" + count, parameters[ count ] ); + count++; + } + } + AddToLog( "\x01-> " + m_commandLine ); + ExecuteCommandLine( false ); + m_commandLine = String.Empty; + } + return; + } + + /// Evaluates and executes the command line stored in the "_command" field. + public virtual void ExecuteCommandLine( bool addToHistory ) + { + string trimmedCmdLine = m_commandLine.Trim(); + + // Ignore Empty And Whitespace Command Lines... + if( String.IsNullOrWhiteSpace( trimmedCmdLine ) ) + { + return; + } + // Ignore Comments... + if( trimmedCmdLine[ 0 ] == '#' ) + { + return; + } + // Bang Indicates That This Line Should NOT Be Added To Command History + if (trimmedCmdLine[0] == '!') + { + addToHistory = false; + trimmedCmdLine = trimmedCmdLine.Substring(1); + } + else if( addToHistory ) + { + m_cmdHistory.Add(trimmedCmdLine); + if( m_cmdHistory.Count > m_cmdHistoryLimit ) + { + m_cmdHistory.RemoveAt(m_cmdHistoryLimit); + } + m_cmdHistoryIndex = m_cmdHistory.Count; + // m_cmdHistoryIndex = ( m_cmdHistory.Count - 1 ); + m_cmdHistoryScanIndex = m_cmdHistoryIndex; + } + // If A PreCommand Execution Handling Delegate Has Been Set, + // Execute The Delegate And See If The Command Was Handled + // Externally. + if( PreCommandExecutedEvent != null ) + { + CommandConsoleEventArgs ea = new CommandConsoleEventArgs( trimmedCmdLine ); + + try + { + PreCommandExecutedEvent( this, ea ); + trimmedCmdLine = ea.CmdLine; + } + catch( Exception ex ) + { + AddErrorToLog( "** PreCommandExecuted delegate(s) thrown an exception: " + ex.Message ); + } + if( ea.Handled ) + { + return; + } + } + try + { + CmdObject cs; + String[] cmds = trimmedCmdLine.Split( ' ' ); + String cmd = cmds[ 0 ].ToLowerInvariant(); + bool found = false; + + // Commands Are more Common Then Functions, So Check them First. + if( ms_commands.TryGetValue( cmd, out cs ) ) + { + found = ExecuteCommand( cs, cmds, cmd ); + } + // Next, Try External Functions... + if( ( !found ) && ( ms_externalFunctions.Count > 0 ) ) + { + found = ExecuteExternalFunc( cmds, cmd ); + } + // Next, Try Internal Functions... + if( ( !found ) && ( ms_functions.Count > 0 ) ) + { + found = ExecuteInternalFunc( cmds, cmd ); + } + // Lastly, See If A Console Variable... + if( ( !found ) && ( m_cVars.Count > 0 ) ) + { + found = HandleCVar( cmds, cmd ); + } + // If STILL Not Found... + if( !found ) + { + AddErrorToLog( "** Unknown command: " + trimmedCmdLine ); + AddErrorToLog( "** type help for commands and usage." ); + } + } + catch( Exception e ) + { + AddErrorToLog( String.Format( "Exception while processing \"{0}\" : {1}", trimmedCmdLine, e.Message ) ); + } + return; + } + + /// Handle set/get cvar + /// Command Line + /// Pre-processed command + /// true if command was handled by this function + private bool HandleCVar( String[] cmds, String cmd ) + { + CVar cvar; + bool found = false; + + lock( m_cVars ) + { + if( m_cVars.TryGetValue( cmd, out cvar ) ) + { + found = true; + if( cmds.Length == 1 ) + { + AddOutputToLog( String.Format( "{0} ({1}) = {2}", + cvar.Name, cvar.ValueType.ToString(), cvar.Value.ToString() ) ); + } + else + { + cvar.Value = GetObjFromString( cvar.ValueType, cmds[ 1 ] ); + if( CVarModifiedEvent != null ) + { + CVarModifiedEvent.Invoke( this, new CVarModifiedEventArgs( cvar ) ); + } + } + } + } + return( found ); + } + + /// Execute an internal function + /// Command Line + /// Pre-processed command + /// true if command was handled by this function + private bool ExecuteInternalFunc( String[] cmds, String cmd ) + { + FuncObject fs; + bool found = false; + + if( ms_functions.TryGetValue( cmd, out fs ) ) + { + string[] parameters = new string[ cmds.Length - 1 ]; + for( int param = 1; param < cmds.Length; param++ ) + { + parameters[ param - 1 ] = cmds[ param ]; + } + ExecuteFunction( fs, parameters ); + found = true; + } + return( found ); + } + + /// Execute a previously loaded external function + /// Command Line + /// Pre-processed command + /// true if command was handled by this function + private bool ExecuteExternalFunc( String[] cmds, String cmd ) + { + ExternalFuncObject efs; + bool found = false; + + // If Not Found, Try To Match Against External Functions + if( ms_externalFunctions.TryGetValue( cmd, out efs ) ) + { + string[] parameters = new string[ cmds.Length - 1 ]; + List cVarParams = new List( 2 ); + bool doInvoke = true; + + for( int param = 1; param < cmds.Length; param++ ) + { + try + { + cVarParams.Add( m_cVars[ cmds[ param ].ToLowerInvariant() ] ); + } + catch( Exception ex ) + { + doInvoke = false; + AddErrorToLog( "Exception while building parameters for external function: " + ex.Message ); + } + } + if( doInvoke ) + { + string ret = efs.Invoke( cVarParams.ToArray() ); + + if( CVarModifiedEvent != null ) + { + foreach( CVar invokedVar in cVarParams ) + { + CVarModifiedEvent.Invoke( this, + new CVarModifiedEventArgs( invokedVar ) ); + } + } + if( String.IsNullOrWhiteSpace( ret ) == false ) + { + AddOutputToLog( ret ); + } + } + found = true; + } + return found; + } + + /// Execute a normal command + /// Command Object + /// Command Line + /// Pre-processed command + /// true if command was handled by this function + private bool ExecuteCommand( CmdObject cs, String[] cmds, String cmd ) + { + int parameters = ( cmds.Length - 1 ); + + // Validate the parameter counts + if( ( cs.MinParameters != 0 ) && ( parameters < cs.MinParameters ) ) + { + AddErrorToLog( "Not enough parameters specified for the " + cmd + " command." ); + if( !String.IsNullOrEmpty( cs.CommandHelpDetailed ) ) + { + AddToLog( cs.CommandHelpDetailed ); + } + } + else if( ( cs.MaxParameters != 0 ) && ( parameters > cs.MaxParameters ) ) + { + AddErrorToLog( "Too many parameters specified for the " + cmd + " command." ); + if( !String.IsNullOrEmpty( cs.CommandHelpDetailed ) ) + { + AddToLog( cs.CommandHelpDetailed ); + } + } + else + { + // Fire The Delegate! + cs.TriggerEvent( cmds ); + } + return( true ); + } + #endregion + + #region Parsing Helpers + /// Try to extract a double/Double value from the string + /// Value to parse + /// out - receives the value parsed from the string + /// Error msg to log if parsing fails + /// True if parsed successfully, false otherwise + protected bool TryParseDouble( string value, out double parsedValue, string errorIfParsingFails ) + { + if( !Double.TryParse( value, out parsedValue ) ) + { + AddErrorToLog( errorIfParsingFails ); + return ( false ); + } + return ( true ); + } + /// Try to extract a float/Single value from the string + /// Value to parse + /// out - receives the value parsed from the string + /// Error msg to log if parsing fails + /// True if parsed successfully, false otherwise + protected bool TryParseFloat( string value, out float parsedValue, string errorIfParsingFails ) + { + if( !Single.TryParse( value, out parsedValue ) ) + { + AddErrorToLog( errorIfParsingFails ); + return ( false ); + } + return ( true ); + } + /// Try to extract an int/Int32 value from the string + /// Value to parse + /// out - receives the value parsed from the string + /// Error msg to log if parsing fails + /// True if parsed successfully, false otherwise + protected bool TryParseInt( string value, out int parsedValue, string errorIfParsingFails ) + { + if( !Int32.TryParse( value, out parsedValue ) ) + { + AddErrorToLog( errorIfParsingFails ); + return ( false ); + } + return ( true ); + } + #endregion + #region Standard Command Handlers + void CommandConsoleBase_Help( string[] cmdLine ) + { + if( cmdLine.Length == 1 ) + { + StringBuilder sb = new StringBuilder( 512 ); + bool first = true; + + sb.Append( "Commands: " ); + foreach( CmdObject cs in ms_commands.Values ) + { + if( ( String.IsNullOrEmpty( cs.Command ) ) || + ( cs.IsSecret ) ) + { + continue; + } + if( !first ) + { + sb.Append( ", " ); + } + first = false; + sb.Append( cs.Command ); + } + AddToLog( sb.ToString() ); + } + else if( cmdLine.Length == 2 ) + { + CmdObject cs; + String helpCommand = cmdLine[ 1 ]; + bool found = false; + + if( ms_commands.TryGetValue( helpCommand, out cs ) ) + { + AddToLog( cs.Command + " - " + cs.CommandHelp ); + if( !String.IsNullOrEmpty( cs.CommandHelpDetailed ) ) + { + AddToLog( cs.CommandHelpDetailed ); + } + found = true; + } + if( !found ) + { + AddErrorToLog( "Unknown command: " + helpCommand ); + } + } + else + { + AddErrorToLog( "Too many parameters specified. Try help or help ." ); + } + return; + } + void CommandConsoleBase_Quit( string[] cmdLine ) + { + // Stop -- no questions asked! + Game.Exit(); + + return; + } + void CommandConsoleBase_Exec( string[] cmdLine ) + { + string scriptFile = cmdLine[ 1 ]; + + if( !File.Exists( scriptFile ) ) + { + AddErrorToLog( "Unable to execute " + scriptFile + ", the file cannot be found." ); + return; + } + string[] commandLines = File.ReadAllLines( cmdLine[ 1 ] ); + + if( commandLines.Length == 0 ) + { + AddErrorToLog( "File: " + scriptFile + " contains no lines." ); + return; + } + AddOutputToLog( "<--- Starting execution of commands from: " + scriptFile + " at " + DateTime.Now.ToString( "hh:mm:ss.fff" ) ); + + bool bAddToHistory = commandLines[ 0 ].StartsWith( "!!" ); + + foreach( string cmd in commandLines ) + { + string cmdFixed = cmd.Trim(); + + AddToLog( "\x01-> " + cmd ); + if( cmdFixed.Length == 0 ) + { + continue; + } + m_logStart = 0; + m_commandLine = cmdFixed; + ExecuteCommandLine( bAddToHistory ); + m_commandLine = String.Empty; + } + AddOutputToLog( "<--- Ended execution of commands from: " + scriptFile + " at " + DateTime.Now.ToString( "hh:mm:ss.fff" ) ); + + return; + } + void CommandConsoleBase_SaveLog( string[] cmdLine ) + { + string[] lines = new String[ m_log.Count ]; + + m_log.CopyTo( lines ); + File.WriteAllLines( cmdLine[ 1 ], lines ); + AddOutputToLog( "<--- Log has been written to: " + cmdLine[ 1 ] ); + + return; + } + void CommandConsoleBase_GC( string[] cmdLine ) + { + AddOutputToLog( "Forcing Garbage Collection..." ); + DateTime now = DateTime.Now; + + GC.Collect( 3, GCCollectionMode.Forced ); + GC.Collect( 2, GCCollectionMode.Forced ); + GC.Collect( 1, GCCollectionMode.Forced ); + + TimeSpan delta = DateTime.Now.Subtract( now ); + AddOutputToLog( "Garbage Collection took ~" + delta.TotalMilliseconds + "ms" ); + + return; + } + void CommandConsoleBase_MemInfo( string[] cmdLine ) + { + AddOutputToLog( "WSMem: " + Environment.WorkingSet ); + AddOutputToLog( "GCC1 : " + GC.CollectionCount( 0 ) ); + AddOutputToLog( "GCC2 : " + GC.CollectionCount( 1 ) ); + AddOutputToLog( "GCC3 : " + GC.CollectionCount( 2 ) ); + AddOutputToLog( "Total: " + GC.GetTotalMemory( false ) ); + + return; + } + + void CommandConsoleBase_ExFunc( string[] cmdLine ) + { + if( m_exfunsLocked ) + { + AddErrorToLog( "ExFunc-related actions have been disabled." ); + return; + } + string assembly = cmdLine[ 1 ]; + string className = cmdLine[ 2 ]; + string funcName = cmdLine[ 3 ]; + bool isSecret = false; + + isSecret = ( ( cmdLine.Length == 5 ) && + ( cmdLine[ 4 ].ToLowerInvariant() == "secret" ) ); + try + { + ExternalFuncObject efo = new ExternalFuncObject( assembly, className, funcName ); + + efo.CommandLine = String.Format( + "exfunc {0} {1} {2}{3}", + assembly, className, funcName, + isSecret ? "secret" : String.Empty ); + ms_externalFunctions.Add( funcName.ToLowerInvariant(), efo ); + AddOutputToLog( String.Format( + "Added external function {0}::{1}::{2}", + assembly, className, funcName ) ); + } + catch( Exception ex ) + { + AddErrorToLog( String.Format( + "Unable to load/add {0}::{1}::{2} = {3}", + assembly, className, funcName, ex.Message ) ); + } + return; + } + + void CommandConsoleBase_SystemInfo( string[] cmdLine ) + { + AddOutputToLog( "Name : " + Environment.MachineName ); + AddOutputToLog( "OSVer : " + Environment.OSVersion ); + AddOutputToLog( "64BitOS : " + Environment.Is64BitOperatingSystem ); + AddOutputToLog( "64BitProcess : " + Environment.Is64BitProcess ); + AddOutputToLog( "PageFile : " + Environment.SystemPageSize ); + AddOutputToLog( "CPUs : " + Environment.ProcessorCount ); + AddOutputToLog( "CLRVer : " + Environment.Version ); + + return; + } + + /// Type converter helper - tries to convert the specified string to the specified type + /// The target type to convert to + /// The source string to try to convert + /// A reference to the successfully converted object, or null if conversion failed + public static object GetObjFromString( Type type, string mystring ) + { + var foo = TypeDescriptor.GetConverter( type ); + + // Try To Convert From String To The Target Type Using Both Culture-Sensitive + // And The Culture-Insensitive Conversion. If Both Fail, Default To String + // Type. + try + { + return ( foo.ConvertFromString( mystring ) ); + } + catch( Exception ) + { + try + { + return ( foo.ConvertFromInvariantString( mystring ) ); + } + catch( Exception ) + { + // Just Eat This One + } + } + // If Conversion Fails, Fall Back To String Type + return ( mystring ); + } + + void CommandConsoleBase_CVar( string[] cmdLine ) + { + CVar cvar = null; + + lock( m_cVars ) + { + string cvarName = cmdLine[ 1 ].ToLowerInvariant(); + + if( m_cVars.TryGetValue( cvarName, out cvar ) ) + { + AddErrorToLog( "CVar " + cmdLine[ 1 ] + + " already exists with a value of: " + cvar.Value ?? "(null" ); + return; + } + if( cmdLine.Length == 4 ) + { + string typeName = cmdLine[ 2 ]; + Type cvarType = Type.GetType( typeName, false ); + + if( cvarType == null ) + { + cvarType = Type.GetType( "System." + typeName, false ); + } + if( cvarType == null ) + { + AddErrorToLog( "Cannot resolve type " + typeName + + " -- try a fully qualified type name" ); + return; + } + object objValue = GetObjFromString( cvarType, cmdLine[ 3 ] ); + + cvar = new CVar( cvarName, objValue ); + } + else if( cmdLine.Length == 3 ) + { + cvar = new CVar( cvarName, cmdLine[ 2 ] ); + } + else + { + cvar = new CVar( cvarName ); + } + m_cVars[ cvarName ] = cvar; + + AddOutputToLog( "CVar " + cvarName + " has been added" ); + } + if( ( cvar != null ) && ( CVarModifiedEvent != null ) ) + { + CVarModifiedEvent.Invoke(this, new CVarModifiedEventArgs(cvar)); + } + return; + } + void CommandConsoleBase_CVars( string[] cmdLine ) + { + AddOutputToLog( "cvars:" ); + lock( m_cVars ) + { + foreach( CVar cvar in m_cVars.Values ) + { + if( cvar.Value != null ) + { + AddOutputToLog( String.Format( "{0} ({1}) = {2}", + cvar.Name, cvar.ValueType.ToString(), cvar.Value.ToString() ) ); + } + else + { + AddOutputToLog( cvar.Name + " (null) = null" ); + } + } + } + return; + } + void CommandConsoleBase_ConsoleScale( string[] cmdLine ) + { + if( cmdLine.Length < 2 ) + { + AddOutputToLog( "Current ConsoleScale is: " + Scale ); + return; + } + float newScale; + + if( !TryParseFloat( cmdLine[ 1 ], out newScale, + "Invalid scale - the specified value cannot be parsed" ) ) + { + return; + } + if( ( newScale < 0.10f ) || ( newScale > 4.0f ) ) + { + AddErrorToLog( "Invalid scale - must be between 0.10 (10%) and 4.0 (400%)" ); + } + else + { + Scale = newScale; + m_stringHeight = Vector2.Zero; + } + return; + } + void CommandConsoleBase_ConsoleHeight( string[] cmdLine ) + { + if( cmdLine.Length < 2 ) + { + AddOutputToLog( "Current ConsoleHeight value is: " + m_height ); + return; + } + int newHeight; + + if( !TryParseInt( cmdLine[ 1 ], out newHeight, + "Invalid height - the specified value cannot be parsed" ) ) + { + return; + } + if( ( newHeight < 100 ) || ( newHeight > ( GraphicsDevice.Viewport.Height - 100 ) ) ) + { + AddErrorToLog( "Invalid height - must be between 100 and " + ( GraphicsDevice.Viewport.Height - 100 ) ); + } + else + { + m_height = newHeight; + m_stringHeight = Vector2.Zero; + } + return; + } + void CommandConsoleBase_Sleep( string[] cmdLine ) + { + int sleepms; + + if( !TryParseInt( cmdLine[ 1 ], out sleepms, + "Invalid sleep duration - the specified value cannot be parsed" ) ) + { + return; + } + Thread.Sleep( sleepms ); + + return; + } + void CommandConsoleBase_LogLimit( string[] cmdLine ) + { + if( cmdLine.Length < 2 ) + { + AddOutputToLog( "Current LogLimit value is: " + m_logLimit ); + return; + } + int lines; + + if( !TryParseInt( cmdLine[ 1 ], out lines, + "Invalid line count - the specified value cannot be parsed" ) ) + { + return; + } + if( ( lines < 32 ) || ( lines > 10240 ) ) + { + AddErrorToLog( "Invalid line count - must be between 32 and 10240" ); + } + else + { + m_logLimit = lines; + } + return; + } + void CommandConsoleBase_Close( string[] cmdLine ) + { + Active = false; + + return; + } + + void CommandConsoleBase_ShadowLog( string[] cmdLine ) + { + if( cmdLine.Length == 1 ) + { + if( m_logShadowEnabled ) + { + AddOutputToLog( "Log shadowing is enabled, writing to: " + m_logShadowFilePath ); + m_logShadowFile.Flush(); + } + else + { + AddOutputToLog( "Log shadowing is disabled." ); + } + return; + } + string filePath = cmdLine[ 1 ]; + bool truncate = false; + + if( cmdLine.Length == 3 ) + { + if( ( bool.TryParse( cmdLine[ 2 ], out truncate ) ) && ( truncate ) ) + { + File.Delete( cmdLine[ 2 ] ); + } + } + m_logShadowFile = new StreamWriter( filePath, !truncate, Encoding.ASCII ); + m_logShadowFilePath = filePath; + m_logShadowEnabled = true; + + AddOutputToLog( "Log shadowing has been enabled." ); + + return; + } + void CommandConsoleBase_NoShadowLog( string[] cmdLine ) + { + if( m_logShadowEnabled ) + { + m_logShadowFile.Close(); + m_logShadowFile = null; + m_logShadowEnabled = false; + AddOutputToLog( "Log shadowing has been disabled." ); + } + else + { + AddOutputToLog( "Log shadowing was not enabled." ); + } + return; + } + void CommandConsoleBase_Clear( string[] cmdLine ) + { + m_log.Clear(); + + return; + } + + void CommandConsoleBase_NoFunctions( string[] cmdLine ) + { + m_functionsLocked = true; + return; + } + + void CommandConsoleBase_NoBindings( string[] cmdLine ) + { + m_bindingsLocked = true; + return; + } + + void CommandConsoleBase_NoExFunctions( string[] cmdLine ) + { + m_exfunsLocked = true; + return; + } + + void CommandConsoleBase_Bindings( string[] cmdLine ) + { + if( ms_bindings.Count == 0 ) + { + AddOutputToLog( "No bindings have been set." ); + return; + } + StringBuilder sb = new StringBuilder( 255 ); + bool first = true; + + sb.Append( "Bindings: " ); + foreach( BindingObject bs in ms_bindings ) + { + if( !first ) + { + sb.Append( ", " ); + } + first = false; + sb.Append( bs.ToString() ); + } + AddToLog( sb.ToString() ); + return; + } + + void CommandConsoleBase_ResetBindings( string[] cmdLine ) + { + if( m_bindingsLocked ) + { + AddErrorToLog( "Binding-related actions have been disabled." ); + return; + } + if( ms_bindings.Count == 0 ) + { + AddOutputToLog( "No bindings have been set." ); + return; + } + ms_bindings.Clear(); + + AddOutputToLog( "All bindings have been cleared." ); + return; + } + + void CommandConsoleBase_ResetFunctions( string[] cmdLine ) + { + if( m_functionsLocked ) + { + AddErrorToLog( "Function-related actions have been disabled." ); + return; + } + if( ms_functions.Count == 0 ) + { + AddOutputToLog( "No functions have been created." ); + return; + } + ms_functions.Clear(); + + AddOutputToLog( "All functions have been cleared." ); + return; + } + + void CommandConsoleBase_ResetExFuncs( string[] cmdLine ) + { + if( m_exfunsLocked ) + { + AddErrorToLog( "ExFunc-related actions have been disabled." ); + return; + } + if( ms_externalFunctions.Count == 0 ) + { + AddOutputToLog( "No external functions have been added." ); + return; + } + ms_externalFunctions.Clear(); + + AddOutputToLog( "All external functions have been cleared." ); + return; + } + + void CommandConsoleBase_ExFuncs( string[] cmdLine ) + { + if( m_exfunsLocked ) + { + AddErrorToLog( "ExFunc-related actions have been disabled." ); + return; + } + if( ms_externalFunctions.Count == 0 ) + { + AddOutputToLog( "No external functions have been added." ); + return; + } + StringBuilder sb = new StringBuilder( 255 ); + bool first = true; + + sb.Append( "ExFuncs: " ); + foreach( ExternalFuncObject ef in ms_externalFunctions.Values ) + { + if( !first ) + { + sb.Append( ", " ); + } + first = false; + sb.Append( ef.ToString() ); + } + AddToLog( sb.ToString() ); + return; + } + + void CommandConsoleBase_Functions( string[] cmdLine ) + { + if( ms_functions.Count == 0 ) + { + AddOutputToLog( "No functions have been created." ); + return; + } + StringBuilder sb = new StringBuilder( 255 ); + bool first = true; + + sb.Append( "Functions: " ); + foreach( FuncObject fs in ms_functions.Values ) + { + if( !first ) + { + sb.Append( ", " ); + } + first = false; + sb.Append( fs.ToString() ); + } + AddToLog( sb.ToString() ); + return; + } + + private List GetAllExFuncs() + { + List exFuncs = new List( ms_externalFunctions.Count ); + + foreach( ExternalFuncObject efo in ms_externalFunctions.Values ) + { + exFuncs.Add( efo.CommandLine ); + } + return( exFuncs ); + } + + private List GetAllFunctions() + { + List functions = new List( ms_functions.Count ); + + foreach( FuncObject fs in ms_functions.Values ) + { + string fnText = "function " + + fs.ToString().Replace( "-> ", String.Empty ); + + //foreach( string fnline in fs.FunctionImpl ) + //{ + // fnText += fnline; + // fnText += ";"; + //} + //functions.Add( "function " + fs.Function + " " + fnText ); + functions.Add( fnText ); + } + return( functions ); + } + + private List< string > GetAllBindings() + { + List bindings = new List( ms_bindings.Count ); + + foreach( BindingObject bo in ms_bindings ) + { + bindings.Add( "bind " + bo.GetModifierString() + bo._key + " " + bo._text ); + } + return( bindings ); + } + + void CommandConsoleBase_ExportBindings( string[] cmdLine ) + { + if( m_bindingsLocked ) + { + AddErrorToLog( "Binding-related actions have been disabled." ); + return; + } + if( ms_bindings.Count == 0 ) + { + AddErrorToLog( "No bindings have been set." ); + return; + } + string filePath = cmdLine[ 1 ]; + + File.WriteAllLines( filePath, GetAllBindings().ToArray() ); + + AddOutputToLog( "Bindings have been saved to: " + filePath ); + + return; + } + + void CommandConsoleBase_ExportFunctions( string[] cmdLine ) + { + if( m_functionsLocked ) + { + AddErrorToLog( "Function-related actions have been disabled." ); + return; + } + if( ms_functions.Count == 0 ) + { + AddErrorToLog( "No functions have been set." ); + return; + } + string filePath = cmdLine[ 1 ]; + + File.WriteAllLines( filePath, GetAllFunctions().ToArray() ); + AddOutputToLog( "Functions have been saved to: " + filePath ); + + return; + } + + void CommandConsoleBase_ExportExFuncs( string[] cmdLine ) + { + if( m_exfunsLocked ) + { + AddErrorToLog( "ExFunc-related actions have been disabled." ); + return; + } + if( ms_externalFunctions.Count == 0 ) + { + AddErrorToLog( "No ExFuncs have been set." ); + return; + } + string filePath = cmdLine[ 1 ]; + + File.WriteAllLines( filePath, GetAllExFuncs().ToArray() ); + AddOutputToLog( "ExFunc defs have been saved to: " + filePath ); + + return; + } + + /// Special command handler for ExportState command + /// The command line for the command + /// This one is protected virtual so additional state can be stored if necessary by derived classes + protected virtual void CommandConsoleBase_ExportState( string[] cmdLine ) + { + string filePath = cmdLine[ 1 ]; + StreamWriter outFile = new StreamWriter( filePath, false, Encoding.ASCII ); + + if( ms_bindings.Count > 0 ) + { + lock( ms_bindings ) + { + List bindings = GetAllBindings(); + + foreach( string line in bindings ) + { + outFile.WriteLine( line ); + } + } + } + if( ms_functions.Count > 0 ) + { + lock( ms_functions ) + { + List functions = GetAllFunctions(); + + foreach( string line in functions ) + { + outFile.WriteLine( line ); + } + } + } + outFile.Write( "consoleheight " + m_height ); + outFile.Write( "consolescale " + Scale ); + outFile.Write( "loglimit " + m_logLimit ); + outFile.Close(); + outFile.Dispose(); + + + AddOutputToLog( "State has been saved to: " + filePath ); + + return; + } + + void CommandConsoleBase_UnBind( string[] cmdLine ) + { + string bindString = cmdLine[ 1 ]; + Keys bindKey = Keys.None; + BindingObject.EModifier bindKeyModifiers = BindingObject.EModifier.None; + bool parsed = GetKeyBindingInfo( bindString, ref bindKeyModifiers, ref bindKey ); + + if( !parsed ) + { + AddErrorToLog( String.Format( "\"{0}\" was not understood as a proper binding string.", bindString ) ); + return; + } + foreach( BindingObject bs in ms_bindings ) + { + if( ( bindKey == bs._key ) && ( bindKeyModifiers == bs._modifierKeys ) ) + { + ms_bindings.Remove( bs ); + AddOutputToLog( bs.GetModifierString() + " has been unbound." ); + return; + } + } + AddErrorToLog( bindString + " is not bound." ); + + return; + } + + void CommandConsoleBase_Bind( string[] cmdLine ) + { + if( m_bindingsLocked ) + { + AddErrorToLog( "Binding-related actions have been disabled." ); + return; + } + string bindString = cmdLine[ 1 ]; + BindingObject.EModifier bindKeyModifiers = BindingObject.EModifier.None; + Keys bindKey = Keys.None; + bool parsed = GetKeyBindingInfo( bindString, ref bindKeyModifiers, ref bindKey ); + + if( !parsed ) + { + AddErrorToLog( String.Format( "\"{0}\" was not understood as a proper binding string.", bindString ) ); + return; + } + foreach( BindingObject bs in ms_bindings ) + { + if( ( bindKey == bs._key ) && ( bindKeyModifiers == bs._modifierKeys ) ) + { + AddErrorToLog( String.Format( "{0} is already bound.", bindString ) ); + return; + } + } + BindingObject newBS = new BindingObject(); + string cmds = String.Empty; + + for( int cmd = 2; cmd < cmdLine.Length; cmd++ ) + { + cmds += cmdLine[ cmd ]; + cmds += " "; + } + newBS._key = bindKey; + newBS._modifierKeys = bindKeyModifiers; + newBS._text = cmds; + + ms_bindings.Add( newBS ); + + return; + } + + void CommandConsoleBase_Function( string[] cmdLine ) + { + if( m_functionsLocked ) + { + AddErrorToLog( "Function-related actions have been disabled." ); + return; + } + string cmds = String.Empty; + bool isSecret = false; + + // This Is A Bit Heavyweight, Building A command Line And Then + // Breaking It Apart Again, But It Seemed Easier And Less + // Complicated Than Trying To Do It All In One Shot + // + // Build Command Line Minus Command And Secret Option + for( int cmd = 2; cmd < cmdLine.Length; cmd++ ) + { + if( ( cmd == 2 ) && ( cmdLine[ cmd ].ToLowerInvariant() == "secret" ) ) + { + isSecret = true; + continue; + } + cmds += cmdLine[ cmd ]; + cmds += " "; + } + if( String.IsNullOrWhiteSpace( cmds ) ) + { + AddErrorToLog( "Function contains no code to execute." ); + return; + } + string[] ft = cmds.Split( ';' ); + bool hasCode = false; + + // Reassemble Command Lines From Tokens + for( int line = 0; line Namespace that contains shared types related to the XNACC (CommandConsole) component +namespace JRTS.XNA.Console.BaseTypes +{ + #region IConsoleKeyboard + /// Basic keyboard/input functionality required by the CommandConsole(Base) class + public interface IConsoleKeyboard + { + /// The current state of the keyboard as of the last Update + KeyboardState CurrentKeyboardState + { + get; + } + /// Collection of keys that are newly pressed (i.e. not held) as of the last Update + IList NewlyPressedKeys + { + get; + } + /// Collection of keys that are being held fown (i.e. not newly pressed) as of the last Update + IList HeldKeys + { + get; + } + } + #endregion + + #region CVar Object + // JRT: OK - Why Is This In Its Own File? Because Of The Way The Type System Works In .NET. If You Create + // JRT: Two Completely Identical Types, But Put Them In Different Assemblies, They Are Considered To Be + // JRT: Two Completely DIFFERENT Types, Even Though They Are Compatible With One Another. By Putting + // JRT: The CVar Class Into A Separate Assembly, Both The CommandConsole And External Functions + // JRT: Reference The Same Type, Allowing Us To Pass CVars Back And Forth. + /// Object that wraps the functionality of a console variable -- defined separately because external functions will receive CVar instances + public class CVar + { + /// The storage for the Name property + protected string m_name = String.Empty; + /// The storage for the Value property + protected object m_value = null; + + /// The string name for this console variable + public string Name + { + get + { + return (m_name); + } + protected set + { + if (String.IsNullOrWhiteSpace(value)) + { + throw new ArgumentNullException("The name for a console variable cannot be null, empty, or whitespace"); + } + m_name = value; + } + } + /// The actual value for this console variable, as an object, or null + public object Value + { + get + { + return( m_value ); + } + set + { + // Set Value. Set Type To Type.Missing If Value Is null + m_value = value; + if (value == null) + { + ValueType = (Type)Type.Missing; + } + else + { + ValueType = value.GetType(); + } + } + } + /// The actual type of the contained variable, or Type.Missing for null values + public Type ValueType + { + get; + protected set; + } + /// Construct a console variable with a default value of null + /// The name for ths console variable + public CVar(string name ) + : this( name, null ) + { + return; + } + /// Construct a console variable with the specified name and value + /// The name for ths console variable + /// The value for this console variable + public CVar(string name, object value) + { + Name = name; + Value = value; + return; + } + /// Get a string representation of the object (not round-trippable!) + /// A string representation of this CVar + public override string ToString() + { + return( String.Format( "{0} ({1}) = {2}", Name, + ValueType.ToString(), + Value.ToString() ) ); + } + /// Hash code function - needed for the dictionary + /// The hash value of the Name of the cvar + override public int GetHashCode() + { + return(Name.GetHashCode() ); + } + } + #endregion +} +#endif \ No newline at end of file From e9e97dae39ba23f4ac1116486043b749bfda599b Mon Sep 17 00:00:00 2001 From: Nathan Adams Date: Sat, 26 May 2012 18:36:11 -0500 Subject: [PATCH 02/11] Updating support for XNACC Note: It is only for Windows currently --HG-- branch : xnacc-integration --- axios/Axios_Windows.csproj.user | 2 +- axios/Axios_settings.cs | 1 + axios/ScreenSystem/InputState.cs | 64 ++++++++++++++++++++ axios/XNACC/CommandConsoleBase.cs | 4 +- axios/XNACC/CommandConsoleBaseSharedTypes.cs | 2 +- 5 files changed, 69 insertions(+), 4 deletions(-) diff --git a/axios/Axios_Windows.csproj.user b/axios/Axios_Windows.csproj.user index 566c009..76fe5a5 100644 --- a/axios/Axios_Windows.csproj.user +++ b/axios/Axios_Windows.csproj.user @@ -1,6 +1,6 @@  - ShowAllFiles + ProjectFiles \ No newline at end of file diff --git a/axios/Axios_settings.cs b/axios/Axios_settings.cs index b4f4453..003fd61 100644 --- a/axios/Axios_settings.cs +++ b/axios/Axios_settings.cs @@ -91,6 +91,7 @@ * - Fixing bug where loadrecentangleitem wouldn't be called by Gleed2D library * - Changing AxiosTitleFile.GetStream() to return Stream instead of FileStream * - Changing IAxiosFile.GetStream() to return Stream instead of FileStream + * - Adding support for XNACC * */ #endregion diff --git a/axios/ScreenSystem/InputState.cs b/axios/ScreenSystem/InputState.cs index 7fa2520..1ca51d7 100644 --- a/axios/ScreenSystem/InputState.cs +++ b/axios/ScreenSystem/InputState.cs @@ -15,6 +15,11 @@ using Microsoft.Xna.Framework.Input.Touch; using FarseerPhysics.SamplesFramework; using Microsoft.Xna.Framework.Graphics; using System; +#if WINDOWS +using XNACC.BaseTypes; +#endif +using System.Linq; + namespace GameStateManagement { @@ -37,8 +42,46 @@ namespace GameStateManagement /// query methods for high level input actions such as "move up through the menu" /// or "pause the game". /// +#if WINDOWS + public class InputState : IConsoleKeyboard +#else public class InputState +#endif { + +#if WINDOWS + #region XNACC + /* + * These are needed for XNACC + * -- Nathan Adams [adamsna@datanethost.net] - 5/26/2012 + */ + + private KeyboardState KeyState; + private List newlyPressedKeys = new List(); + private List heldKeys = new List(); + private Keys[] oldPressedKeys; + private Keys[] newPressedKeys; + + public KeyboardState CurrentKeyboardState + { + get { return KeyState; } + } + + public IList NewlyPressedKeys + { + get { return newlyPressedKeys; } + } + + public IList HeldKeys + { + get { return heldKeys; } + } + + /* + * End XNACC variables + */ + #endregion +#endif public const int MaxInputs = 4; public readonly KeyboardState[] CurrentKeyboardStates; @@ -270,6 +313,27 @@ namespace GameStateManagement /// public void Update(GameTime gameTime) { + +#if WINDOWS + #region XNACC + KeyState = Keyboard.GetState(); + + oldPressedKeys = newPressedKeys; + newPressedKeys = KeyState.GetPressedKeys(); + + newlyPressedKeys.Clear(); + heldKeys.Clear(); + + foreach (Keys key in newPressedKeys) + { + if (oldPressedKeys.Contains(key)) + heldKeys.Add(key); + else + newlyPressedKeys.Add(key); + } + #endregion +#endif + //PlayerIndex p; _lastMouseState = _currentMouseState; if (_handleVirtualStick) diff --git a/axios/XNACC/CommandConsoleBase.cs b/axios/XNACC/CommandConsoleBase.cs index 604b95e..c9930d6 100644 --- a/axios/XNACC/CommandConsoleBase.cs +++ b/axios/XNACC/CommandConsoleBase.cs @@ -11,7 +11,7 @@ using System.Threading; using System.IO; using System.ComponentModel; using System.Reflection; -using JRTS.XNA.Console.BaseTypes; +using XNACC.BaseTypes; using System.Diagnostics; #endif #endregion @@ -71,7 +71,7 @@ using System.Diagnostics; //NA: Seriously Microsoft? #if WINDOWS /// Namespace that contains code related to the XNACC (CommandConsole) component -namespace JRTS.XNA.Console +namespace XNACC.Console { /// Base functionality of the XNACC (CommandConsole) component public class CommandConsoleBase : DrawableGameComponent diff --git a/axios/XNACC/CommandConsoleBaseSharedTypes.cs b/axios/XNACC/CommandConsoleBaseSharedTypes.cs index 4b49338..e417d3d 100644 --- a/axios/XNACC/CommandConsoleBaseSharedTypes.cs +++ b/axios/XNACC/CommandConsoleBaseSharedTypes.cs @@ -6,7 +6,7 @@ using Microsoft.Xna.Framework.Input; #if WINDOWS /// Namespace that contains shared types related to the XNACC (CommandConsole) component -namespace JRTS.XNA.Console.BaseTypes +namespace XNACC.BaseTypes { #region IConsoleKeyboard /// Basic keyboard/input functionality required by the CommandConsole(Base) class From 13857f324d049ac070db858c26d2126d2f473109 Mon Sep 17 00:00:00 2001 From: Nathan Adams Date: Sat, 26 May 2012 18:50:49 -0500 Subject: [PATCH 03/11] Adding AxiosCommandConsole for easy intergration with AxiosGameScreens Adding the ability to get the InputState object from the ScreenManager --HG-- branch : xnacc-integration --- axios/Axios_WP7.csproj | 1 + axios/Axios_Windows.csproj | 1 + axios/Axios_Xbox_360.csproj | 1 + axios/Engine/AxiosCommandConsole.cs | 26 ++++++++++++++++++++++++++ axios/ScreenSystem/ScreenManager.cs | 5 +++++ 5 files changed, 34 insertions(+) create mode 100644 axios/Engine/AxiosCommandConsole.cs diff --git a/axios/Axios_WP7.csproj b/axios/Axios_WP7.csproj index 897dcf9..9df37ff 100644 --- a/axios/Axios_WP7.csproj +++ b/axios/Axios_WP7.csproj @@ -155,6 +155,7 @@ + diff --git a/axios/Axios_Windows.csproj b/axios/Axios_Windows.csproj index 195fc78..8d24a3f 100644 --- a/axios/Axios_Windows.csproj +++ b/axios/Axios_Windows.csproj @@ -98,6 +98,7 @@ + diff --git a/axios/Axios_Xbox_360.csproj b/axios/Axios_Xbox_360.csproj index 9ce7f6f..33ed00a 100644 --- a/axios/Axios_Xbox_360.csproj +++ b/axios/Axios_Xbox_360.csproj @@ -149,6 +149,7 @@ + diff --git a/axios/Engine/AxiosCommandConsole.cs b/axios/Engine/AxiosCommandConsole.cs new file mode 100644 index 0000000..1251e09 --- /dev/null +++ b/axios/Engine/AxiosCommandConsole.cs @@ -0,0 +1,26 @@ +#if WINDOWS +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using XNACC.Console; +using Microsoft.Xna.Framework.Graphics; + +namespace Axios.Engine +{ + class AxiosCommandConsole : CommandConsoleBase + { + public AxiosCommandConsole(AxiosGameScreen gameScreen) + : base(gameScreen.ScreenManager.Game) + { + Keyboard = gameScreen.ScreenManager.InputState; + } + + public AxiosCommandConsole(AxiosGameScreen gameScreen, SpriteFont font) + : base(gameScreen.ScreenManager.Game, font) + { + Keyboard = gameScreen.ScreenManager.InputState; + } + } +} +#endif \ No newline at end of file diff --git a/axios/ScreenSystem/ScreenManager.cs b/axios/ScreenSystem/ScreenManager.cs index dcd2545..eb4f79d 100644 --- a/axios/ScreenSystem/ScreenManager.cs +++ b/axios/ScreenSystem/ScreenManager.cs @@ -57,6 +57,11 @@ namespace GameStateManagement #region Properties + public InputState InputState + { + get { return input; } + private set { input = value; } + } public SpriteFonts Fonts { From 11ab45d9ee41252dc5c7d2ba0f3609b7a2f68f63 Mon Sep 17 00:00:00 2001 From: Nathan Adams Date: Sat, 26 May 2012 18:57:16 -0500 Subject: [PATCH 04/11] Adding code to keep track of the console in AxiosGameScreen --HG-- branch : xnacc-integration --- axios/Engine/AxiosGameScreen.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/axios/Engine/AxiosGameScreen.cs b/axios/Engine/AxiosGameScreen.cs index 211795f..ff1f445 100644 --- a/axios/Engine/AxiosGameScreen.cs +++ b/axios/Engine/AxiosGameScreen.cs @@ -41,6 +41,10 @@ namespace Axios.Engine private Camera camera; +#if WINDOWS + AxiosCommandConsole _console = null; +#endif + public AxiosGameScreen() : base() { @@ -95,6 +99,20 @@ namespace Axios.Engine public void AddGameObject(object obj) { +#if WINDOWS + if (obj is AxiosCommandConsole) + { + if (_console != null) + { + //remove the current one first + ScreenManager.Game.Components.Remove(_console); + _console.Dispose(); + _console = null; + } + _console = (AxiosCommandConsole)obj; + ScreenManager.Game.Components.Add(_console); + } +#endif if (obj is AxiosGameObject || obj is AxiosUIObject || obj is AxiosTimer) { AxiosGameObject tmp = obj as AxiosGameObject; From 56f2b95e72af514cdf9435fcd2b4e822a0ca5028 Mon Sep 17 00:00:00 2001 From: Nathan Adams Date: Sat, 26 May 2012 19:08:33 -0500 Subject: [PATCH 05/11] Adding empty AxiosCommandConsole to not require #if WINDOWS/#endif precompiler statments on WP7/Xbox 360 Adjusting code in AxiosGameScreen to accept it on WP7/Xbox 360 but just store it --HG-- branch : xnacc-integration --- axios/Engine/AxiosCommandConsole.cs | 43 +++++++++++++++++++++++++++++ axios/Engine/AxiosGameScreen.cs | 9 +++--- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/axios/Engine/AxiosCommandConsole.cs b/axios/Engine/AxiosCommandConsole.cs index 1251e09..8447878 100644 --- a/axios/Engine/AxiosCommandConsole.cs +++ b/axios/Engine/AxiosCommandConsole.cs @@ -5,6 +5,18 @@ using System.Linq; using System.Text; using XNACC.Console; using Microsoft.Xna.Framework.Graphics; +using Microsoft.Xna.Framework.Content; +using Microsoft.Xna.Framework; + +/* + * The empty AxiosCommandConsole is so that when you use the comamnd console + * in your game you don't need #if WINDOWS/#endif precompiler - when you attempt + * to use it on WP7/Xbox 360 it just won't do anything. + * + * Perhaps one day we should develop a customized console that doesn't require keyboard input + * to still allow debugging on WP7/Xbox 360 + * -- Nathan Adams [adamsna@datanethost.net] - 5/26/2012 + */ namespace Axios.Engine { @@ -21,6 +33,37 @@ namespace Axios.Engine { Keyboard = gameScreen.ScreenManager.InputState; } + + protected override void LoadContent() + { + FadeColor = Color.White * 0.5f; + Texture2D tmp = new Texture2D(GraphicsDevice, 1, 1); + tmp.SetData(new Color[] { Color.Black }); + FadeImage = tmp; + + base.LoadContent(); + } + } +} +#else +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Microsoft.Xna.Framework.Graphics; +namespace Axios.Engine +{ + class AxiosCommandConsole + { + public AxiosCommandConsole(AxiosGameScreen gameScreen) + { + + } + + public AxiosCommandConsole(AxiosGameScreen gameScreen, SpriteFont font) + { + + } } } #endif \ No newline at end of file diff --git a/axios/Engine/AxiosGameScreen.cs b/axios/Engine/AxiosGameScreen.cs index ff1f445..6c31a84 100644 --- a/axios/Engine/AxiosGameScreen.cs +++ b/axios/Engine/AxiosGameScreen.cs @@ -41,9 +41,7 @@ namespace Axios.Engine private Camera camera; -#if WINDOWS AxiosCommandConsole _console = null; -#endif public AxiosGameScreen() : base() @@ -98,21 +96,22 @@ namespace Axios.Engine public void AddGameObject(object obj) { - -#if WINDOWS if (obj is AxiosCommandConsole) { if (_console != null) { //remove the current one first +#if WINDOWS ScreenManager.Game.Components.Remove(_console); _console.Dispose(); +#endif _console = null; } _console = (AxiosCommandConsole)obj; +#if WINDOWS ScreenManager.Game.Components.Add(_console); - } #endif + } if (obj is AxiosGameObject || obj is AxiosUIObject || obj is AxiosTimer) { AxiosGameObject tmp = obj as AxiosGameObject; From 20e58e8e014ec94bd0d43839cf063ad11311ca72 Mon Sep 17 00:00:00 2001 From: Nathan Adams Date: Sat, 26 May 2012 19:12:50 -0500 Subject: [PATCH 06/11] Updating readme to update authors and License information Adding XNACC license --HG-- branch : xnacc-integration --- README | 8 +++++++- XNACC.License.txt | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 XNACC.License.txt diff --git a/README b/README index a245ee3..abefa79 100644 --- a/README +++ b/README @@ -42,6 +42,9 @@ Authors General questions/comments/concerns can be directed at: Nathan Adams - adamsna[at]datanethost.net + +Contributors: +Bret Deasy Copyright and License Information --------------------------------- @@ -51,4 +54,7 @@ Axios - See Axios License.txt Farseer - See Farseer License.txt -Glee2D - See Glee2D License.txt \ No newline at end of file +Glee2D - See Glee2D.License.txt + +XNACC - See XNACC.License.txt +Portions of this product are (C) 2009-2011 JRTwine Software, LLC \ No newline at end of file diff --git a/XNACC.License.txt b/XNACC.License.txt new file mode 100644 index 0000000..125a926 --- /dev/null +++ b/XNACC.License.txt @@ -0,0 +1,32 @@ +Microsoft Public License (Ms-PL) +Microsoft Public License (Ms-PL) + +This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software. + +1. Definitions + +The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under U.S. copyright law. + +A "contribution" is the original software, or any additions or changes to the software. + +A "contributor" is any person that distributes its contribution under this license. + +"Licensed patents" are a contributor's patent claims that read directly on its contribution. + +2. Grant of Rights + +(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create. + +(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software. + +3. Conditions and Limitations + +(A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks. + +(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically. + +(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software. + +(D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license. + +(E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement. \ No newline at end of file From 1da538dc2521958566f8f4a6f411ee865999f499 Mon Sep 17 00:00:00 2001 From: Nathan Adams Date: Sat, 26 May 2012 19:15:02 -0500 Subject: [PATCH 07/11] Updating README --HG-- branch : xnacc-integration --- README | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README b/README index abefa79..9403681 100644 --- a/README +++ b/README @@ -53,8 +53,12 @@ Axios - See Axios License.txt - Written by Nathan Adams and released under the Apache License Farseer - See Farseer License.txt + http://farseerphysics.codeplex.com/ Glee2D - See Glee2D.License.txt - + http://gleed2d.codeplex.com/ + XNACC - See XNACC.License.txt + http://xnacc.codeplex.com/ + Portions of this product are (C) 2009-2011 JRTwine Software, LLC \ No newline at end of file From 97c57b9dcf01791e1ab48a8e1d89952a8584ad97 Mon Sep 17 00:00:00 2001 From: Nathan Adams Date: Sat, 26 May 2012 19:18:40 -0500 Subject: [PATCH 08/11] Updating formating of README --HG-- branch : xnacc-integration --- README | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/README b/README index 9403681..1c602f1 100644 --- a/README +++ b/README @@ -53,12 +53,15 @@ Axios - See Axios License.txt - Written by Nathan Adams and released under the Apache License Farseer - See Farseer License.txt + http://farseerphysics.codeplex.com/ - + Glee2D - See Glee2D.License.txt - http://gleed2d.codeplex.com/ - -XNACC - See XNACC.License.txt - http://xnacc.codeplex.com/ + http://gleed2d.codeplex.com/ + +XNACC - See XNACC.License.txt + + http://xnacc.codeplex.com/ + Portions of this product are (C) 2009-2011 JRTwine Software, LLC \ No newline at end of file From 98737603af4ab00d78b5d19fcb8e6700a31f2091 Mon Sep 17 00:00:00 2001 From: Nathan Adams Date: Sat, 26 May 2012 19:20:04 -0500 Subject: [PATCH 09/11] Again another format update --HG-- branch : xnacc-integration --- README | 1 + 1 file changed, 1 insertion(+) diff --git a/README b/README index 1c602f1..54a627e 100644 --- a/README +++ b/README @@ -44,6 +44,7 @@ General questions/comments/concerns can be directed at: Nathan Adams - adamsna[at]datanethost.net Contributors: + Bret Deasy Copyright and License Information From 977f4e7f9a46c9430641918ab3b6a9da00ba06a1 Mon Sep 17 00:00:00 2001 From: Nathan Adams Date: Sat, 26 May 2012 22:53:55 -0500 Subject: [PATCH 10/11] Adding default Font if one is not provided Adding a flag to AxiosGameScreen to allow a developer to disable input across everything if the console is visible/active. Changing Deactivate to Unload because Unload is what is gets called when a screen is told to go away --HG-- branch : xnacc-integration --- axios/Axios_settings.cs | 1 + axios/Engine/AxiosCommandConsole.cs | 20 ++++++++++++++--- axios/Engine/AxiosGameScreen.cs | 34 +++++++++++++++++++++++------ 3 files changed, 45 insertions(+), 10 deletions(-) diff --git a/axios/Axios_settings.cs b/axios/Axios_settings.cs index 003fd61..3c0bdce 100644 --- a/axios/Axios_settings.cs +++ b/axios/Axios_settings.cs @@ -92,6 +92,7 @@ * - Changing AxiosTitleFile.GetStream() to return Stream instead of FileStream * - Changing IAxiosFile.GetStream() to return Stream instead of FileStream * - Adding support for XNACC + * - Fixed a bug where cleanup actions were being performed in Deactivate instead of Unload in AxiosGameScreen * */ #endregion diff --git a/axios/Engine/AxiosCommandConsole.cs b/axios/Engine/AxiosCommandConsole.cs index 8447878..193e76b 100644 --- a/axios/Engine/AxiosCommandConsole.cs +++ b/axios/Engine/AxiosCommandConsole.cs @@ -20,27 +20,40 @@ using Microsoft.Xna.Framework; namespace Axios.Engine { - class AxiosCommandConsole : CommandConsoleBase + public class AxiosCommandConsole : CommandConsoleBase { + //private AxiosGameScreen _gameScreen; public AxiosCommandConsole(AxiosGameScreen gameScreen) : base(gameScreen.ScreenManager.Game) { + //_gameScreen = gameScreen; Keyboard = gameScreen.ScreenManager.InputState; } public AxiosCommandConsole(AxiosGameScreen gameScreen, SpriteFont font) : base(gameScreen.ScreenManager.Game, font) { + //_gameScreen = gameScreen; Keyboard = gameScreen.ScreenManager.InputState; } - protected override void LoadContent() + protected void LoadDefault() { FadeColor = Color.White * 0.5f; Texture2D tmp = new Texture2D(GraphicsDevice, 1, 1); tmp.SetData(new Color[] { Color.Black }); FadeImage = tmp; + } + + public override void LoadContent(ContentManager content) + { + base.LoadContent(content); + } + protected override void LoadContent() + { + if (Font == null) + Font = Game.Content.Load("Console"); base.LoadContent(); } } @@ -53,8 +66,9 @@ using System.Text; using Microsoft.Xna.Framework.Graphics; namespace Axios.Engine { - class AxiosCommandConsole + public class AxiosCommandConsole { + public bool Active = false; public AxiosCommandConsole(AxiosGameScreen gameScreen) { diff --git a/axios/Engine/AxiosGameScreen.cs b/axios/Engine/AxiosGameScreen.cs index 6c31a84..71fa375 100644 --- a/axios/Engine/AxiosGameScreen.cs +++ b/axios/Engine/AxiosGameScreen.cs @@ -43,6 +43,14 @@ namespace Axios.Engine AxiosCommandConsole _console = null; + protected bool AllowKeyboardWhileConsoleIsActive = false; + + public AxiosCommandConsole Console + { + get { return _console; } + private set { _console = value; } + } + public AxiosGameScreen() : base() { @@ -110,6 +118,7 @@ namespace Axios.Engine _console = (AxiosCommandConsole)obj; #if WINDOWS ScreenManager.Game.Components.Add(_console); + _console.LoadContent(ScreenManager.Game.Content); #endif } if (obj is AxiosGameObject || obj is AxiosUIObject || obj is AxiosTimer) @@ -230,7 +239,7 @@ namespace Axios.Engine public override void Update(GameTime gameTime, bool otherScreenHasFocus, bool coveredByOtherScreen) { base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen); - + if (this._objectstoremove.Count > 0) { List list = this._objectstoremove.ToList(); @@ -379,17 +388,21 @@ namespace Axios.Engine public override void HandleInput(GameTime gameTime, InputState input) { - base.HandleInput(gameTime, input); + if ((AllowKeyboardWhileConsoleIsActive && _console.Active) || !_console.Active) + { + base.HandleInput(gameTime, input); - foreach (AxiosGameObject g in _gameObjects.ToList()) - g.HandleInput(this, input, gameTime); + foreach (AxiosGameObject g in _gameObjects.ToList()) + g.HandleInput(this, input, gameTime); - foreach (AxiosUIObject g in _uiobjects.ToList()) - g.HandleInput(this, input, gameTime); + foreach (AxiosUIObject g in _uiobjects.ToList()) + g.HandleInput(this, input, gameTime); + } } - public override void Deactivate() + public override void Unload() { + //System.Diagnostics.Debugger.Break(); base.Deactivate(); AxiosLog.Instance.AddLine("Memory usage before cleanup: " + GC.GetTotalMemory(true).ToString(), LoggingFlag.DEBUG); foreach (AxiosGameObject g in _gameObjects) @@ -409,6 +422,13 @@ namespace Axios.Engine //AxiosIsolatedFile f = new AxiosIsolatedFile("log.log"); //f.WriteData(AxiosLog.Instance.GetLog(), FileMode.Append); //CleanUp(); +#if WINDOWS + if (_console != null) + { + ScreenManager.Game.Components.Remove(_console); + _console.Dispose(); + } +#endif }