diff --git a/InputSystems/ANX.InputSystem.Recording/Creator.cs b/InputSystems/ANX.InputSystem.Recording/Creator.cs index 6c3908af..ba6b671f 100644 --- a/InputSystems/ANX.InputSystem.Recording/Creator.cs +++ b/InputSystems/ANX.InputSystem.Recording/Creator.cs @@ -65,13 +65,13 @@ namespace ANX.InputSystem.Recording #if XNAEXT RecordingMotionSensingDevice msd; #endif - + public IGamePad GamePad { get - { - AddInSystemFactory.Instance.PreventSystemChange( - AddInType.InputSystem); + { + AddInSystemFactory.Instance.PreventSystemChange( + AddInType.InputSystem); if (gamePad == null) gamePad = new RecordingGamePad(); return gamePad; @@ -81,9 +81,9 @@ namespace ANX.InputSystem.Recording public IMouse Mouse { get - { - AddInSystemFactory.Instance.PreventSystemChange( - AddInType.InputSystem); + { + AddInSystemFactory.Instance.PreventSystemChange( + AddInType.InputSystem); if (mouse == null) mouse = new RecordingMouse(); return mouse; @@ -93,9 +93,9 @@ namespace ANX.InputSystem.Recording public IKeyboard Keyboard { get - { - AddInSystemFactory.Instance.PreventSystemChange( - AddInType.InputSystem); + { + AddInSystemFactory.Instance.PreventSystemChange( + AddInType.InputSystem); if (keyboard == null) keyboard = new RecordingKeyboard(); return keyboard; @@ -106,9 +106,9 @@ namespace ANX.InputSystem.Recording public IMotionSensingDevice MotionSensingDevice { get - { - AddInSystemFactory.Instance.PreventSystemChange( - AddInType.InputSystem); + { + AddInSystemFactory.Instance.PreventSystemChange( + AddInType.InputSystem); if (msd == null) msd = new RecordingMotionSensingDevice(); return msd; diff --git a/InputSystems/ANX.InputSystem.Recording/RecordableDevice.cs b/InputSystems/ANX.InputSystem.Recording/RecordableDevice.cs index 69336fa9..bb6ffa1f 100644 --- a/InputSystems/ANX.InputSystem.Recording/RecordableDevice.cs +++ b/InputSystems/ANX.InputSystem.Recording/RecordableDevice.cs @@ -70,7 +70,7 @@ namespace ANX.InputSystem.Recording public event EventHandler EndOfPlaybackReached; /// - /// How many bytes this Instance requires per Paket. Must never change! + /// How many bytes this Instance requires per Packet. Must never change! /// public int PacketLenght { get; protected set; } @@ -150,17 +150,35 @@ namespace ANX.InputSystem.Recording } if (state.Length != PacketLenght) - throw new InvalidOperationException("The passed state's lenght does not match the speficed FramePaketLenght."); + throw new InvalidOperationException("The passed state's lenght does not match the speficed FramePacketLenght."); + TryWriteNullStates(); + + recordStream.WriteByte((byte)PacketType.InputData); + recordStream.Write(state, 0, state.Length); + } + + /// + /// Writes a custom packet to the stream. When this packet is found during ReadState() + /// HandleUserPacket is called to handle the packet. Please note that the packetTypes 0 and + /// 1 are reseved. + /// + protected virtual void WriteUserState(byte packetType, byte[] packetData) + { + TryWriteNullStates(); + + recordStream.WriteByte(packetType); + recordStream.WriteByte(packetData.Length); + } + + private void TryWriteNullStates() + { if (nullStateCounter > 0) //Note how many packets we had nothing { recordStream.WriteByte((byte)PacketType.NullFrameCounter); recordStream.Write(BitConverter.GetBytes(nullStateCounter), 0, 4); nullStateCounter = 0; } - - recordStream.WriteByte((byte)PacketType.InputData); - recordStream.Write(state, 0, state.Length); } /// @@ -178,7 +196,7 @@ namespace ANX.InputSystem.Recording if (recordStream.Position == recordStream.Length) { OnEndOfPlaybackReached(); - return null; //TODO: Better switch to RecordingState.None here? + return null; } PacketType type = (PacketType)recordStream.ReadByte(); @@ -193,8 +211,12 @@ namespace ANX.InputSystem.Recording byte[] buffer2 = new byte[PacketLenght]; recordStream.Read(buffer2, 0, PacketLenght); return buffer2; - default: - throw new NotImplementedException("The PaketType " + Enum.GetName(typeof(PacketType), type) + "is not supported."); + default: //Custom Packet Type + byte packetLenght = (byte)recordStream.ReadByte(); + byte[] buffer3 = new byte[packetLenght]; + recordStream.Read(buffer3, 0, packetLenght); + HandleUserPacket((byte)type, buffer3); + return ReadState(); //We read another packet until we find a "valid" one. } } @@ -210,5 +232,13 @@ namespace ANX.InputSystem.Recording if (EndOfPlaybackReached != null) EndOfPlaybackReached(this, EventArgs.Empty); } + + /// + /// Overwrite this method to handle custom packet types written by WriteUserState(). When + /// ReadState() encounters an unknown packet type this method is called. + /// + protected virtual void HandleUserPacket(byte packetType, byte[] packetData) + { + } } } diff --git a/InputSystems/ANX.InputSystem.Recording/RecordingGamePad.cs b/InputSystems/ANX.InputSystem.Recording/RecordingGamePad.cs index a81c864e..159e6452 100644 --- a/InputSystems/ANX.InputSystem.Recording/RecordingGamePad.cs +++ b/InputSystems/ANX.InputSystem.Recording/RecordingGamePad.cs @@ -6,6 +6,7 @@ using System.Text; using ANX.Framework.NonXNA; using ANX.Framework.Input; using ANX.Framework; +using System.IO; #endregion @@ -58,14 +59,50 @@ using ANX.Framework; namespace ANX.InputSystem.Recording { + [Flags] + enum GamePadRecordInfo : int + { + LeftStick = 1, + RightStick = 2, + LeftTrigger = 4, + RightTrigger = 8, + AButton = 16, + BButton = 32, + XButton = 64, + YButton = 128, + StartButton = 256, + BackButton = 512, + LeftShoulderButton = 1024, + RightShoulderButton = 2048, + LeftStickButton = 4096, + RightStickButton = 8192, + DPadUp = 16384, + DPadDown = 32768, + DPadLeft = 65536, + DPadRight = 131072, + + BothSticks = LeftStick | RightStick, + BothTriggers = LeftTrigger | RightTrigger, + AllAnalog = BothSticks | BothTriggers, + ABXYButton = AButton | BButton | XButton | YButton, + BothStickButtons = LeftStickButton | RightStickButton, + BothSoulderButtons = LeftShoulderButton | RightShoulderButton, + AllDPad = DPadUp | DPadDown | DPadLeft | DPadRight, + AllButtons = ABXYButton | BothStickButtons | StartButton | BackButton | BothSoulderButtons, + All = AllAnalog | AllButtons | AllDPad + } + /// /// Wrapper arround another IGamePad, will record all inputs and allows playback. /// public class RecordingGamePad : RecordableDevice, IGamePad { - public GamePadCapabilities GetCapabilities(PlayerIndex playerIndex) + private IGamePad realGamePad; + private GamePadRecordInfo recordInfo; + + public GamePadCapabilities GetCapabilities(PlayerIndex playerIndex) //no recording here... { - throw new NotImplementedException(); + return realGamePad.GetCapabilities(playerIndex); } public GamePadState GetState(PlayerIndex playerIndex, out bool isConnected, out int packetNumber) @@ -73,7 +110,7 @@ namespace ANX.InputSystem.Recording throw new NotImplementedException(); } - public GamePadState GetState(PlayerIndex playerIndex, Framework.Input.GamePadDeadZone deadZoneMode, out bool isConnected, out int packetNumber) + public GamePadState GetState(PlayerIndex playerIndex, GamePadDeadZone deadZoneMode, out bool isConnected, out int packetNumber) { throw new NotImplementedException(); } @@ -82,5 +119,51 @@ namespace ANX.InputSystem.Recording { throw new NotImplementedException(); } + + /// + /// Intializes this instance using a new MemoryStream as the Buffer, the + /// default's InputSystems GamePad and the passed GamePadRecordInfo. + /// + public void Initialize(GamePadRecordInfo info) + { + this.Initialize(info, new MemoryStream(), InputDeviceFactory.Instance.GetDefaultGamePad()); + } + + /// + /// Intializes this instance using a new MemoryStream as the Buffer, recording + /// the passed IGamePad, using the passed GamePadRecordInfo. + /// + public void Initialize(GamePadRecordInfo info, IGamePad gamePad) + { + this.Initialize(info, new MemoryStream(), gamePad); + } + + /// + /// Intializes this instance using the passed Stream as the Buffer, the + /// default's InputSystems GamePad and the passed GamePadRecordInfo. + /// + public void Initialize(GamePadRecordInfo info, Stream bufferStream) + { + this.Initialize(info, bufferStream, InputDeviceFactory.Instance.GetDefaultGamePad()); + } + + /// + /// Intializes this instance using the passed Stream as the Buffer, recording + /// the passed IGamePad, using the passed GamePadRecordInfo. + /// + public void Initialize(GamePadRecordInfo info, Stream bufferStream, IGamePad gamePad) + { + realGamePad = gamePad; + + recordInfo = info; + PacketLenght = GetPaketSize(info); + + base.Initialize(bufferStream); + } + + private int GetPaketSize(GamePadRecordInfo info) + { + throw new NotImplementedException(); + } } } diff --git a/InputSystems/ANX.InputSystem.Recording/RecordingHelper.cs b/InputSystems/ANX.InputSystem.Recording/RecordingHelper.cs index 9b2c60f8..97be78f7 100644 --- a/InputSystems/ANX.InputSystem.Recording/RecordingHelper.cs +++ b/InputSystems/ANX.InputSystem.Recording/RecordingHelper.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text; +using ANX.Framework.NonXNA; #endregion @@ -71,6 +72,7 @@ namespace ANX.InputSystem.Recording None } + //0-1 are reserved for the recording Engine, 2-255 can be used using WriteUserState(). enum PacketType : byte { NullFrameCounter = 0, @@ -78,10 +80,32 @@ namespace ANX.InputSystem.Recording } /// - /// Static Helper-class containing some recording related stuff. + /// Static Helper-class containing some recording-related stuff. /// - static class RecordingHelper + public static class RecordingHelper { - + /// + /// Returns the RecordingMouse of the RecordingInput-System. + /// + public static RecordingMouse GetMouse() + { + return ((RecordingMouse)AddInSystemFactory.Instance.GetCreator("Recording").Mouse); + } + + /// + /// Returns the RecordingKeyboard of the RecordingInput-System. + /// + public static RecordingKeyboard GetKeyboard() + { + return ((RecordingKeyboard)AddInSystemFactory.Instance.GetCreator("Recording").Keyboard); + } + + /// + /// Returns the RecordingGamePad of the RecordingInput-System. + /// + public static RecordingGamePad GetGamepad() + { + return ((RecordingGamePad)AddInSystemFactory.Instance.GetCreator("Recording").GamePad); + } } } diff --git a/RecordingSample/RecordingSample/Game1.cs b/RecordingSample/RecordingSample/Game1.cs index c53b58c7..fa25d82b 100644 --- a/RecordingSample/RecordingSample/Game1.cs +++ b/RecordingSample/RecordingSample/Game1.cs @@ -60,7 +60,7 @@ using ANX.InputSystem.Recording; namespace RecordingSample { /// - /// Sample, showing the use of the RecordingSystem (currently only the Mouse). + /// Sample, showing the use of the RecordingSystem. /// public class Game1 : Game { @@ -81,12 +81,11 @@ namespace RecordingSample protected override void Initialize() { - Window.Title = "Use Mouse to move arround, press r to record, p for playback and n for none"; - - //this is quite ugly... could this be improved? - recMouse = ((RecordingMouse)AddInSystemFactory.Instance.GetDefaultCreator().Mouse); + Window.Title = "Move the Mouse or press Enter. press R to record, P for playback and N for none"; + + recMouse = RecordingHelper.GetMouse(); //((RecordingMouse)AddInSystemFactory.Instance.GetDefaultCreator().Mouse); recMouse.Initialize(MouseRecordInfo.Position); - recKeyboard = ((RecordingKeyboard)AddInSystemFactory.Instance.GetDefaultCreator().Keyboard); + recKeyboard = RecordingHelper.GetKeyboard(); recKeyboard.Initialize(Keys.Enter); base.Initialize(); @@ -142,13 +141,10 @@ namespace RecordingSample GraphicsDevice.Clear(Color.CornflowerBlue); spriteBatch.Begin(); - if (Keyboard.GetState().IsKeyDown(Keys.Enter)) - { + if (Keyboard.GetState().IsKeyDown(Keys.Enter)) //Keyboard spriteBatch.Draw(logo, Vector2.Zero, Color.White); - } - //spriteBatch.End(); - //spriteBatch.Begin(); - spriteBatch.Draw(logo, new Rectangle(Mouse.GetState().X, Mouse.GetState().Y, 115, 30), Color.White); + + spriteBatch.Draw(logo, new Rectangle(Mouse.GetState().X, Mouse.GetState().Y, 115, 30), Color.White); //Mouse spriteBatch.End(); base.Draw(gameTime); diff --git a/RecordingSample/RecordingSample/Program.cs b/RecordingSample/RecordingSample/Program.cs index bb02131e..1d3e27aa 100644 --- a/RecordingSample/RecordingSample/Program.cs +++ b/RecordingSample/RecordingSample/Program.cs @@ -9,8 +9,7 @@ namespace RecordingSample static void Main(string[] args) { //This is technically unessasary, because there is only a reference to the RecordingSystem... - AddInSystemFactory.Instance.SetPreferredSystem( - AddInType.InputSystem, "Recording"); + AddInSystemFactory.Instance.SetPreferredSystem(AddInType.InputSystem, "Recording"); using (Game1 game = new Game1()) {