using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Media; using SpacePew.Models; namespace SpacePew.Networking { /// /// TODO: This is not really a network messenger yet, so we need to change the functionality a little (send all message over network in the loop down there) /// public class NetworkMessenger : Microsoft.Xna.Framework.GameComponent, IDrawable { private readonly MainGame _game; private SpriteBatch _spriteBatch; private SpriteFont _netFont; private Rectangle _chatRectangle; private Rectangle _textBounds; private static UdpClient _client; private static List _messages; private const int DefaultMessageLifeTime = 10; public NetworkMessenger(MainGame game, UdpClient client) : base(game) { _game = game; _client = client; _messages = new List(); } /// /// Allows the game component to perform any initialization it needs to before starting /// to run. This is where it can query for any required services and load content. /// public override void Initialize() { _spriteBatch = new SpriteBatch(_game.GraphicsDevice); _netFont = _game.Content.Load("Fonts\\Default"); _chatRectangle = new Rectangle(300, 20, 300, _game.GraphicsDevice.Viewport.Height - 40); _textBounds = new Rectangle(); base.Initialize(); } public static void AddDeath(IEntity entity) { _client.SendDeath(entity); } public static void DisplayMessage(NetworkMessage message) { _messages.Add(message); } public static void SendMessage(NetworkMessage message) { _messages.Add(message); _client.SendMessage(message); if (message.IsChatMessage) { SoundManager.Play("Audio/Waves/message", _client.LocalPlayer.Position); } } private string _chatMessage = string.Empty; private KeyboardState _oldKeyboardState; private KeyboardState _currentKeyboardState; bool chatting = false; /// /// Allows the game component to update itself. /// /// Provides a snapshot of timing values. public override void Update(GameTime gameTime) { MainGame.IsKeyboardInUse = chatting; _oldKeyboardState = _currentKeyboardState; _currentKeyboardState = Keyboard.GetState(); Keys[] pressedKeys = _currentKeyboardState.GetPressedKeys(); bool isShiftDown = pressedKeys.Any(KeyboardHelper.IsShift); foreach (Keys key in pressedKeys) { if (!_oldKeyboardState.IsKeyUp(key)) continue; if (key == Keys.T && !chatting) { chatting = true; continue; } if (!chatting) continue; switch (key) { case Keys.Back: _chatMessage = _chatMessage.Remove(_chatMessage.Length - 1, 1); break; case Keys.Space: _chatMessage = _chatMessage + " "; break; default: if (key == Keys.Enter && chatting) { chatting = false; SendMessage(new NetworkMessage() { Color = _client.LocalPlayer.Color, Message = string.Format("{0}: {1}", _client.LocalPlayer.Owner, _chatMessage), Sent = DateTime.Now, IsChatMessage = true }); _chatMessage = string.Empty; } else { if (isShiftDown) { _chatMessage += KeyboardHelper.ToPrintableString(key, KbModifiers.None).ToUpper(); } else { _chatMessage += KeyboardHelper.ToPrintableString(key, KbModifiers.None); } } break; } } for (int i = _messages.Count - 1; i >= 0; i--) { if (_messages[i].Sent.AddSeconds(DefaultMessageLifeTime) <= DateTime.Now) { _messages.RemoveAt(i); } } base.Update(gameTime); } public void Draw(GameTime gameTime) { _spriteBatch.Begin(); int yOffset = 0; if (chatting) { _spriteBatch.DrawString(_netFont, "Chat: " + _chatMessage, new Vector2(300, _game.GraphicsDevice.Viewport.Height - 140), Color.White); } foreach (var message in _messages) { DrawString(_spriteBatch, _netFont, message.Message, _chatRectangle, message.Color, TextAlignment.TopLeft, true, new Vector2(0, (_messages.IndexOf(message) * 15) + yOffset), out _textBounds); yOffset += _textBounds.Height; } _spriteBatch.End(); } public int DrawOrder { get { return 5; } } public bool Visible { get { return true; } } private enum TextAlignment { Top, Left, Middle, Right, Bottom, TopLeft, TopRight, BottomLeft, BottomRight } private static void DrawString(SpriteBatch sb, SpriteFont fnt, string text, Rectangle r, Color col, TextAlignment align, bool performWordWrap, Vector2 offsett, out Rectangle textBounds) { textBounds = r; if (text == null) return; if (text == string.Empty) return; var lines = new StringCollection(); lines.AddRange(text.Split(new string[] { "\\n" }, StringSplitOptions.RemoveEmptyEntries)); Rectangle tmprect = ProcessLines(fnt, r, performWordWrap, lines); var pos = new Vector2(r.X, r.Y); int aStyle = 0; switch (align) { case TextAlignment.Bottom: pos.Y = r.Bottom - tmprect.Height; aStyle = 1; break; case TextAlignment.BottomLeft: pos.Y = r.Bottom - tmprect.Height; aStyle = 0; break; case TextAlignment.BottomRight: pos.Y = r.Bottom - tmprect.Height; aStyle = 2; break; case TextAlignment.Left: pos.Y = r.Y + ((r.Height / 2) - (tmprect.Height / 2)); aStyle = 0; break; case TextAlignment.Middle: pos.Y = r.Y + ((r.Height / 2) - (tmprect.Height / 2)); aStyle = 1; break; case TextAlignment.Right: pos.Y = r.Y + ((r.Height / 2) - (tmprect.Height / 2)); aStyle = 2; break; case TextAlignment.Top: aStyle = 1; break; case TextAlignment.TopLeft: aStyle = 0; break; case TextAlignment.TopRight: aStyle = 2; break; } foreach (string txt in lines) { Vector2 size = fnt.MeasureString(txt); switch (aStyle) { case 0: pos.X = r.X; break; case 1: pos.X = r.X + ((r.Width / 2) - (size.X / 2)); break; case 2: pos.X = r.Right - size.X; break; } sb.DrawString(fnt, txt, pos + offsett, col); pos.Y += fnt.LineSpacing; } textBounds = tmprect; } private static Rectangle ProcessLines(SpriteFont fnt, Rectangle r, bool performWordWrap, StringCollection lines) { Rectangle bounds = r; bounds.Width = 0; bounds.Height = 0; int index = 0; float Width; bool lineInserted = false; while (index < lines.Count) { string linetext = lines[index]; Vector2 size = fnt.MeasureString(linetext); if (performWordWrap && size.X > r.Width) { string endspace = string.Empty; if (linetext.EndsWith(" ")) { endspace = " "; linetext = linetext.TrimEnd(); } int i = linetext.LastIndexOf(" ", StringComparison.InvariantCulture); if (i != -1) { string lastword = linetext.Substring(i + 1); if (index == lines.Count - 1) { lines.Add(lastword); lineInserted = true; } else { if (lineInserted) { lines[index + 1] = lastword + endspace + lines[index + 1]; } else { lines.Insert(index + 1, lastword); lineInserted = true; } } lines[index] = linetext.Substring(0, i + 1); } else { lineInserted = false; size = fnt.MeasureString(lines[index]); if (size.X > bounds.Width) Width = size.X; bounds.Height += fnt.LineSpacing; index++; } } else { lineInserted = false; size = fnt.MeasureString(lines[index]); if (size.X > bounds.Width) bounds.Width = (int)size.X; bounds.Height += fnt.LineSpacing; index++; } } return bounds; } event EventHandler IDrawable.DrawOrderChanged { add { } remove { } } event EventHandler IDrawable.VisibleChanged { add { } remove { } } } }