372 lines
8.4 KiB
C#
372 lines
8.4 KiB
C#
|
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 Microsoft.Xna.Framework.Storage;
|
||
|
using SpacePew.Models;
|
||
|
|
||
|
|
||
|
namespace SpacePew.Networking
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// 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)
|
||
|
/// </summary>
|
||
|
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<NetworkMessage> _messages;
|
||
|
|
||
|
private const int DefaultMessageLifeTime = 10;
|
||
|
|
||
|
public NetworkMessenger(MainGame game, UdpClient client)
|
||
|
: base(game)
|
||
|
{
|
||
|
_game = game;
|
||
|
_client = client;
|
||
|
_messages = new List<NetworkMessage>();
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// 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.
|
||
|
/// </summary>
|
||
|
public override void Initialize()
|
||
|
{
|
||
|
_spriteBatch = new SpriteBatch(_game.GraphicsDevice);
|
||
|
_netFont = _game.Content.Load<SpriteFont>("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;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Allows the game component to update itself.
|
||
|
/// </summary>
|
||
|
/// <param name="gameTime">Provides a snapshot of timing values.</param>
|
||
|
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<EventArgs> IDrawable.DrawOrderChanged
|
||
|
{
|
||
|
add { }
|
||
|
remove { }
|
||
|
}
|
||
|
|
||
|
event EventHandler<EventArgs> IDrawable.VisibleChanged
|
||
|
{
|
||
|
add { }
|
||
|
remove { }
|
||
|
}
|
||
|
}
|
||
|
}
|