Rewrite chat interface
This commit is contained in:
parent
42f682ac1c
commit
3da7d25a3d
216
TrueCraft.Client/Modules/ChatModule.cs
Normal file
216
TrueCraft.Client/Modules/ChatModule.cs
Normal file
@ -0,0 +1,216 @@
|
||||
using System;
|
||||
using TrueCraft.Client.Input;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using TrueCraft.Client.Rendering;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
|
||||
namespace TrueCraft.Client.Modules
|
||||
{
|
||||
public class ChatModule : InputModule, IGraphicalModule
|
||||
{
|
||||
private static readonly int TimeToFade = 9 * 1000;
|
||||
private static readonly int TimeToExpire = 10 * 1000;
|
||||
private static readonly int MaxLines = 10;
|
||||
|
||||
private struct Message
|
||||
{
|
||||
public string Text { get; set; }
|
||||
public long Arrived { get; set; }
|
||||
}
|
||||
|
||||
private TrueCraftGame Game { get; set; }
|
||||
private Texture2D Background { get; set; }
|
||||
private FontRenderer Font { get; set; }
|
||||
private SpriteBatch SpriteBatch { get; set; }
|
||||
private List<Message> Messages { get; set; }
|
||||
private Stopwatch Watch { get; set; }
|
||||
private bool Editing { get; set; }
|
||||
private string Text { get; set; }
|
||||
|
||||
public ChatModule(TrueCraftGame game, FontRenderer font)
|
||||
{
|
||||
Game = game;
|
||||
Font = font;
|
||||
Messages = new List<Message>();
|
||||
Background = new Texture2D(Game.GraphicsDevice, 1, 1);
|
||||
Background.SetData<Color>(new[] { new Color(Color.Black, 160) });
|
||||
SpriteBatch = new SpriteBatch(Game.GraphicsDevice);
|
||||
Watch = new Stopwatch();
|
||||
Watch.Start();
|
||||
Text = string.Empty;
|
||||
Game.Client.ChatMessage += (sender, e) => AddMessage(e.Message);
|
||||
}
|
||||
|
||||
public override bool KeyDown(GameTime gameTime, KeyboardKeyEventArgs e)
|
||||
{
|
||||
if (!Editing)
|
||||
{
|
||||
if (e.Key == Keys.T)
|
||||
{
|
||||
Editing = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (e.Key == Keys.Back)
|
||||
Text = Text.Length > 0 ? Text.Substring(0, Text.Length - 1) : Text;
|
||||
else if (e.Key == Keys.Escape)
|
||||
{
|
||||
Editing = false;
|
||||
Text = string.Empty;
|
||||
}
|
||||
else if (e.Key == Keys.Enter)
|
||||
{
|
||||
Game.Client.SendMessage(Text);
|
||||
Editing = false;
|
||||
Text = string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
var shift = (Keyboard.GetState().IsKeyDown(Keys.LeftShift) || Keyboard.GetState().IsKeyDown(Keys.RightShift));
|
||||
var value = default(char);
|
||||
|
||||
if (TryParseKey(e.Key, shift, out value))
|
||||
Text += value;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool KeyUp(GameTime gameTime, KeyboardKeyEventArgs e)
|
||||
{
|
||||
return Editing;
|
||||
}
|
||||
|
||||
public void AddMessage(string text)
|
||||
{
|
||||
Console.WriteLine(text);
|
||||
Messages.Insert(0, new Message { Text = text, Arrived = Watch.ElapsedMilliseconds });
|
||||
}
|
||||
|
||||
public void Draw(GameTime gameTime)
|
||||
{
|
||||
SpriteBatch.Begin();
|
||||
const int height = 25;
|
||||
int x = 5, y = (int)(Game.GraphicsDevice.Viewport.Height - Scale(22) * 2);
|
||||
int width = Game.GraphicsDevice.Viewport.Width / 2;
|
||||
int max = MaxLines;
|
||||
if (Editing)
|
||||
max = Game.GraphicsDevice.Viewport.Height / height;
|
||||
for (int i = 0; i < Messages.Count && i < max; i++)
|
||||
{
|
||||
var time = Watch.ElapsedMilliseconds - Messages[i].Arrived;
|
||||
if (time >= TimeToExpire && !Editing)
|
||||
continue;
|
||||
byte alpha = 255;
|
||||
if (time > TimeToFade && !Editing)
|
||||
{
|
||||
var t = TimeToExpire - time / (double)(TimeToExpire - TimeToFade);
|
||||
alpha = (byte)(t * 256);
|
||||
}
|
||||
SpriteBatch.Draw(Background, new Rectangle(
|
||||
x, y - (i * height), width, height), new Color(Color.White, alpha));
|
||||
Font.DrawText(SpriteBatch, x, y - (i * height) - 5, Messages[i].Text, alpha: alpha);
|
||||
}
|
||||
if (Editing)
|
||||
{
|
||||
SpriteBatch.Draw(Background,
|
||||
new Rectangle(0, Game.GraphicsDevice.Viewport.Height - height,
|
||||
Game.GraphicsDevice.Viewport.Width, height), Color.White);
|
||||
if (Watch.Elapsed.Seconds % 2 == 0)
|
||||
Font.DrawText(SpriteBatch, 3, Game.GraphicsDevice.Viewport.Height - height - 5, Text);
|
||||
else
|
||||
Font.DrawText(SpriteBatch, 3, Game.GraphicsDevice.Viewport.Height - height - 5, Text + "_");
|
||||
}
|
||||
SpriteBatch.End();
|
||||
}
|
||||
|
||||
public override void Update(GameTime gameTime)
|
||||
{
|
||||
}
|
||||
|
||||
private float Scale(float value)
|
||||
{
|
||||
return value * Game.ScaleFactor * 2;
|
||||
}
|
||||
|
||||
private static bool TryParseKey(Keys key, bool shift, out char value)
|
||||
{
|
||||
// Credit to Roy Triesscheijn for thinking of this.
|
||||
// His implementation of this solution can be found at:
|
||||
// http://roy-t.nl/index.php/2010/02/11/code-snippet-converting-keyboard-input-to-text-in-xna/
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case Keys.NumPad1: value = '1'; break;
|
||||
case Keys.NumPad2: value = '2'; break;
|
||||
case Keys.NumPad3: value = '3'; break;
|
||||
case Keys.NumPad4: value = '4'; break;
|
||||
case Keys.NumPad5: value = '5'; break;
|
||||
case Keys.NumPad6: value = '6'; break;
|
||||
case Keys.NumPad7: value = '7'; break;
|
||||
case Keys.NumPad8: value = '8'; break;
|
||||
case Keys.NumPad9: value = '9'; break;
|
||||
case Keys.NumPad0: value = '0'; break;
|
||||
|
||||
case Keys.D1: value = (shift) ? '!' : '1'; break;
|
||||
case Keys.D2: value = (shift) ? '@' : '2'; break;
|
||||
case Keys.D3: value = (shift) ? '#' : '3'; break;
|
||||
case Keys.D4: value = (shift) ? '$' : '4'; break;
|
||||
case Keys.D5: value = (shift) ? '%' : '5'; break;
|
||||
case Keys.D6: value = (shift) ? '^' : '6'; break;
|
||||
case Keys.D7: value = (shift) ? '&' : '7'; break;
|
||||
case Keys.D8: value = (shift) ? '*' : '8'; break;
|
||||
case Keys.D9: value = (shift) ? '(' : '9'; break;
|
||||
case Keys.D0: value = (shift) ? ')' : '0'; break;
|
||||
|
||||
case Keys.A: value = (shift) ? 'A' : 'a'; break;
|
||||
case Keys.B: value = (shift) ? 'B' : 'b'; break;
|
||||
case Keys.C: value = (shift) ? 'C' : 'c'; break;
|
||||
case Keys.D: value = (shift) ? 'D' : 'd'; break;
|
||||
case Keys.E: value = (shift) ? 'E' : 'e'; break;
|
||||
case Keys.F: value = (shift) ? 'F' : 'f'; break;
|
||||
case Keys.G: value = (shift) ? 'G' : 'g'; break;
|
||||
case Keys.H: value = (shift) ? 'H' : 'h'; break;
|
||||
case Keys.I: value = (shift) ? 'I' : 'i'; break;
|
||||
case Keys.J: value = (shift) ? 'J' : 'j'; break;
|
||||
case Keys.K: value = (shift) ? 'K' : 'k'; break;
|
||||
case Keys.L: value = (shift) ? 'L' : 'l'; break;
|
||||
case Keys.M: value = (shift) ? 'M' : 'm'; break;
|
||||
case Keys.N: value = (shift) ? 'N' : 'n'; break;
|
||||
case Keys.O: value = (shift) ? 'O' : 'o'; break;
|
||||
case Keys.P: value = (shift) ? 'P' : 'p'; break;
|
||||
case Keys.Q: value = (shift) ? 'Q' : 'q'; break;
|
||||
case Keys.R: value = (shift) ? 'R' : 'r'; break;
|
||||
case Keys.S: value = (shift) ? 'S' : 's'; break;
|
||||
case Keys.T: value = (shift) ? 'T' : 't'; break;
|
||||
case Keys.U: value = (shift) ? 'U' : 'u'; break;
|
||||
case Keys.V: value = (shift) ? 'V' : 'v'; break;
|
||||
case Keys.W: value = (shift) ? 'W' : 'w'; break;
|
||||
case Keys.X: value = (shift) ? 'X' : 'x'; break;
|
||||
case Keys.Y: value = (shift) ? 'Y' : 'y'; break;
|
||||
case Keys.Z: value = (shift) ? 'Z' : 'z'; break;
|
||||
|
||||
case Keys.OemTilde: value = (shift) ? '~' : '`'; break;
|
||||
case Keys.OemSemicolon: value = (shift) ? ':' : ';'; break;
|
||||
case Keys.OemQuotes: value = (shift) ? '"' : '\''; break;
|
||||
case Keys.OemQuestion: value = (shift) ? '?' : '/'; break;
|
||||
case Keys.OemPlus: value = (shift) ? '+' : '='; break;
|
||||
case Keys.OemPipe: value = (shift) ? '|' : '\\'; break;
|
||||
case Keys.OemPeriod: value = (shift) ? '>' : '.'; break;
|
||||
case Keys.OemOpenBrackets: value = (shift) ? '{' : '['; break;
|
||||
case Keys.OemCloseBrackets: value = (shift) ? '}' : ']'; break;
|
||||
case Keys.OemMinus: value = (shift) ? '_' : '-'; break;
|
||||
case Keys.OemComma: value = (shift) ? '<' : ','; break;
|
||||
|
||||
case Keys.Space: value = ' '; break;
|
||||
|
||||
default: value = default(char); return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -61,7 +61,7 @@ namespace TrueCraft.Client.Rendering
|
||||
/// <param name="y"></param>
|
||||
/// <param name="text"></param>
|
||||
/// <param name="scale"></param>
|
||||
public void DrawText(SpriteBatch spriteBatch, int x, int y, string text, float scale = 1.0f)
|
||||
public void DrawText(SpriteBatch spriteBatch, int x, int y, string text, float scale = 1.0f, byte alpha = 255)
|
||||
{
|
||||
var dx = x;
|
||||
var dy = y;
|
||||
@ -96,8 +96,8 @@ namespace TrueCraft.Client.Rendering
|
||||
(int)(glyph.Width * scale),
|
||||
(int)(glyph.Height * scale));
|
||||
|
||||
spriteBatch.Draw(font.GetTexture(glyph.Page), shadowRectangle, sourceRectangle, new Color(63, 63, 21));
|
||||
spriteBatch.Draw(font.GetTexture(glyph.Page), destRectangle, sourceRectangle, color);
|
||||
spriteBatch.Draw(font.GetTexture(glyph.Page), shadowRectangle, sourceRectangle, new Color(63, 63, 21, alpha));
|
||||
spriteBatch.Draw(font.GetTexture(glyph.Page), destRectangle, sourceRectangle, new Color(color, alpha));
|
||||
dx += (int)(glyph.XAdvance * scale);
|
||||
}
|
||||
}
|
||||
|
@ -145,6 +145,7 @@
|
||||
<Compile Include="Input\GamePadEventArgs.cs" />
|
||||
<Compile Include="Input\GamePadButtonEventArgs.cs" />
|
||||
<Compile Include="AudioManager.cs" />
|
||||
<Compile Include="Modules\ChatModule.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<ItemGroup>
|
||||
|
@ -32,6 +32,7 @@ namespace TrueCraft.Client
|
||||
public ConcurrentBag<Action> PendingMainThreadActions { get; set; }
|
||||
public double Bobbing { get; set; }
|
||||
public ChunkModule ChunkModule { get; set; }
|
||||
public ChatModule ChatModule { get; set; }
|
||||
public float ScaleFactor { get; set; }
|
||||
public Coordinates3D HighlightedBlock { get; set; }
|
||||
public BlockFace HighlightedBlockFace { get; set; }
|
||||
@ -121,9 +122,11 @@ namespace TrueCraft.Client
|
||||
|
||||
ChunkModule = new ChunkModule(this);
|
||||
DebugInfoModule = new DebugInfoModule(this, Pixel);
|
||||
ChatModule = new ChatModule(this, Pixel);
|
||||
|
||||
Modules.Add(ChunkModule);
|
||||
Modules.Add(new HighlightModule(this));
|
||||
Modules.Add(ChatModule);
|
||||
Modules.Add(new PlayerControlModule(this));
|
||||
Modules.Add(new HUDModule(this, Pixel));
|
||||
Modules.Add(DebugInfoModule);
|
||||
|
@ -32,6 +32,7 @@ namespace TrueCraft.Core.World
|
||||
public World World { get; set; }
|
||||
|
||||
private Stream regionFile { get; set; }
|
||||
private object streamLock = new object();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new Region for server-side use at the given position using
|
||||
@ -163,7 +164,7 @@ namespace TrueCraft.Core.World
|
||||
{
|
||||
lock (Chunks)
|
||||
{
|
||||
lock (regionFile)
|
||||
lock (streamLock)
|
||||
{
|
||||
var toRemove = new List<Coordinates2D>();
|
||||
foreach (var kvp in Chunks)
|
||||
@ -262,7 +263,7 @@ namespace TrueCraft.Core.World
|
||||
{
|
||||
if (regionFile == null)
|
||||
return;
|
||||
lock (regionFile)
|
||||
lock (streamLock)
|
||||
{
|
||||
regionFile.Flush();
|
||||
regionFile.Close();
|
||||
|
Loading…
x
Reference in New Issue
Block a user