Start moving client towards a more refined design
I'm splitting up core pieces of functionality into several smaller modules. TrueCraftGame will be made smaller and smaller until it's just a small wrapper around the modules doing all of the work. This should allow for modders to easily add new modules or replace builtin modules, and will make the codebase more maintainable in general.
This commit is contained in:
parent
915937dbd4
commit
8fe7329135
@ -8,7 +8,7 @@ namespace TrueCraft.Client.Input
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Encapsulates keyboard input in an event-driven manner.
|
/// Encapsulates keyboard input in an event-driven manner.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class KeyboardComponent : GameComponent
|
public sealed class KeyboardHandler : GameComponent
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Raised when a key for this keyboard component is pressed.
|
/// Raised when a key for this keyboard component is pressed.
|
||||||
@ -29,7 +29,7 @@ namespace TrueCraft.Client.Input
|
|||||||
/// Creates a new keyboard component.
|
/// Creates a new keyboard component.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="game">The parent game for the component.</param>
|
/// <param name="game">The parent game for the component.</param>
|
||||||
public KeyboardComponent(Game game)
|
public KeyboardHandler(Game game)
|
||||||
: base(game)
|
: base(game)
|
||||||
{
|
{
|
||||||
}
|
}
|
@ -7,7 +7,7 @@ namespace TrueCraft.Client.Input
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Encapsulates mouse input in an event-driven manner.
|
/// Encapsulates mouse input in an event-driven manner.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class MouseComponent : GameComponent
|
public sealed class MouseHandler : GameComponent
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Raised when this mouse component is moved.
|
/// Raised when this mouse component is moved.
|
||||||
@ -38,7 +38,7 @@ namespace TrueCraft.Client.Input
|
|||||||
/// Creates a new mouse component.
|
/// Creates a new mouse component.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="game">The parent game for the component.</param>
|
/// <param name="game">The parent game for the component.</param>
|
||||||
public MouseComponent(Game game)
|
public MouseHandler(Game game)
|
||||||
: base(game)
|
: base(game)
|
||||||
{
|
{
|
||||||
}
|
}
|
@ -103,7 +103,7 @@ namespace TrueCraft.Client.Interface
|
|||||||
public bool HasFocus { get; set; }
|
public bool HasFocus { get; set; }
|
||||||
|
|
||||||
public MultiplayerClient Client { get; set; }
|
public MultiplayerClient Client { get; set; }
|
||||||
public KeyboardComponent Keyboard { get; set; }
|
public KeyboardHandler Keyboard { get; set; }
|
||||||
public FontRenderer Font { get; set; }
|
public FontRenderer Font { get; set; }
|
||||||
|
|
||||||
private readonly object Lock = new object();
|
private readonly object Lock = new object();
|
||||||
@ -111,7 +111,7 @@ namespace TrueCraft.Client.Interface
|
|||||||
private List<ChatMessage> Messages { get; set; }
|
private List<ChatMessage> Messages { get; set; }
|
||||||
private Texture2D DummyTexture { get; set; }
|
private Texture2D DummyTexture { get; set; }
|
||||||
|
|
||||||
public ChatInterface(MultiplayerClient client, KeyboardComponent keyboard, FontRenderer font)
|
public ChatInterface(MultiplayerClient client, KeyboardHandler keyboard, FontRenderer font)
|
||||||
{
|
{
|
||||||
Client = client;
|
Client = client;
|
||||||
Keyboard = keyboard;
|
Keyboard = keyboard;
|
||||||
|
@ -14,7 +14,6 @@ namespace TrueCraft.Client.Interface
|
|||||||
|
|
||||||
public int Vertices { private get; set; }
|
public int Vertices { private get; set; }
|
||||||
public int Chunks { private get; set; }
|
public int Chunks { private get; set; }
|
||||||
public Coordinates3D HighlightedBlock { private get; set; }
|
|
||||||
|
|
||||||
public DebugInterface(MultiplayerClient client, FontRenderer font)
|
public DebugInterface(MultiplayerClient client, FontRenderer font)
|
||||||
{
|
{
|
||||||
@ -41,7 +40,6 @@ namespace TrueCraft.Client.Interface
|
|||||||
Font.DrawText(spriteBatch, xOrigin, yOrigin + (yOffset * 1), string.Format("§o{0} vertices", Vertices), scale);
|
Font.DrawText(spriteBatch, xOrigin, yOrigin + (yOffset * 1), string.Format("§o{0} vertices", Vertices), scale);
|
||||||
Font.DrawText(spriteBatch, xOrigin, yOrigin + (yOffset * 2), string.Format("§o{0} chunks", Chunks), scale);
|
Font.DrawText(spriteBatch, xOrigin, yOrigin + (yOffset * 2), string.Format("§o{0} chunks", Chunks), scale);
|
||||||
Font.DrawText(spriteBatch, xOrigin, yOrigin + (yOffset * 3), string.Format("§o<{0:N2}, {1:N2}, {2:N2}>", Client.Position.X, Client.Position.Y, Client.Position.Z), scale);
|
Font.DrawText(spriteBatch, xOrigin, yOrigin + (yOffset * 3), string.Format("§o<{0:N2}, {1:N2}, {2:N2}>", Client.Position.X, Client.Position.Y, Client.Position.Z), scale);
|
||||||
Font.DrawText(spriteBatch, xOrigin, yOrigin + (yOffset * 4), string.Format("§o<{0:N2}, {1:N2}, {2:N2}>", HighlightedBlock.X, HighlightedBlock.Y, HighlightedBlock.Z), scale);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnHide() { }
|
protected override void OnHide() { }
|
||||||
|
127
TrueCraft.Client/Modules/ChunkModule.cs
Normal file
127
TrueCraft.Client/Modules/ChunkModule.cs
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
using System;
|
||||||
|
using TrueCraft.Client.Rendering;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using TrueCraft.API;
|
||||||
|
|
||||||
|
namespace TrueCraft.Client.Modules
|
||||||
|
{
|
||||||
|
public class ChunkModule : IGraphicalModule
|
||||||
|
{
|
||||||
|
public TrueCraftGame Game { get; set; }
|
||||||
|
public ChunkRenderer ChunkRenderer { get; set; }
|
||||||
|
|
||||||
|
private List<Mesh> ChunkMeshes { get; set; }
|
||||||
|
private ConcurrentBag<Mesh> IncomingChunks { get; set; }
|
||||||
|
|
||||||
|
private BasicEffect OpaqueEffect { get; set; }
|
||||||
|
private AlphaTestEffect TransparentEffect { get; set; }
|
||||||
|
|
||||||
|
public ChunkModule(TrueCraftGame game)
|
||||||
|
{
|
||||||
|
Game = game;
|
||||||
|
|
||||||
|
ChunkRenderer = new ChunkRenderer(Game.Client.World, Game, Game.BlockRepository);
|
||||||
|
Game.Client.ChunkLoaded += (sender, e) => ChunkRenderer.Enqueue(e.Chunk);
|
||||||
|
//Client.ChunkModified += (sender, e) => ChunkRenderer.Enqueue(e.Chunk, true);
|
||||||
|
ChunkRenderer.MeshCompleted += MeshCompleted;
|
||||||
|
ChunkRenderer.Start();
|
||||||
|
|
||||||
|
OpaqueEffect = new BasicEffect(Game.GraphicsDevice);
|
||||||
|
OpaqueEffect.EnableDefaultLighting();
|
||||||
|
OpaqueEffect.DirectionalLight0.SpecularColor = Color.Black.ToVector3();
|
||||||
|
OpaqueEffect.DirectionalLight1.SpecularColor = Color.Black.ToVector3();
|
||||||
|
OpaqueEffect.DirectionalLight2.SpecularColor = Color.Black.ToVector3();
|
||||||
|
OpaqueEffect.TextureEnabled = true;
|
||||||
|
OpaqueEffect.Texture = Game.TextureMapper.GetTexture("terrain.png");
|
||||||
|
OpaqueEffect.FogEnabled = true;
|
||||||
|
OpaqueEffect.FogStart = 512f;
|
||||||
|
OpaqueEffect.FogEnd = 1000f;
|
||||||
|
OpaqueEffect.FogColor = Color.CornflowerBlue.ToVector3();
|
||||||
|
OpaqueEffect.VertexColorEnabled = true;
|
||||||
|
|
||||||
|
TransparentEffect = new AlphaTestEffect(Game.GraphicsDevice);
|
||||||
|
TransparentEffect.AlphaFunction = CompareFunction.Greater;
|
||||||
|
TransparentEffect.ReferenceAlpha = 127;
|
||||||
|
TransparentEffect.Texture = Game.TextureMapper.GetTexture("terrain.png");
|
||||||
|
TransparentEffect.VertexColorEnabled = true;
|
||||||
|
|
||||||
|
ChunkMeshes = new List<Mesh>();
|
||||||
|
IncomingChunks = new ConcurrentBag<Mesh>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MeshCompleted(object sender, RendererEventArgs<ReadOnlyChunk> e)
|
||||||
|
{
|
||||||
|
IncomingChunks.Add(e.Result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleClientPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
switch (e.PropertyName)
|
||||||
|
{
|
||||||
|
case "Position":
|
||||||
|
var sorter = new ChunkRenderer.ChunkSorter(new Coordinates3D(
|
||||||
|
(int)Game.Client.Position.X, 0, (int)Game.Client.Position.Z));
|
||||||
|
Game.PendingMainThreadActions.Add(() => ChunkMeshes.Sort(sorter));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(GameTime gameTime)
|
||||||
|
{
|
||||||
|
Mesh mesh;
|
||||||
|
while (IncomingChunks.TryTake(out mesh))
|
||||||
|
{
|
||||||
|
ChunkMeshes.Add(mesh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly BlendState ColorWriteDisable = new BlendState()
|
||||||
|
{
|
||||||
|
ColorWriteChannels = ColorWriteChannels.None
|
||||||
|
};
|
||||||
|
|
||||||
|
public void Draw(GameTime gameTime)
|
||||||
|
{
|
||||||
|
Game.Camera.ApplyTo(OpaqueEffect);
|
||||||
|
Game.Camera.ApplyTo(TransparentEffect);
|
||||||
|
|
||||||
|
int verticies = 0, chunks = 0;
|
||||||
|
Game.GraphicsDevice.DepthStencilState = DepthStencilState.Default;
|
||||||
|
for (int i = 0; i < ChunkMeshes.Count; i++)
|
||||||
|
{
|
||||||
|
if (Game.Camera.Frustum.Intersects(ChunkMeshes[i].BoundingBox))
|
||||||
|
{
|
||||||
|
verticies += ChunkMeshes[i].GetTotalVertices();
|
||||||
|
chunks++;
|
||||||
|
ChunkMeshes[i].Draw(OpaqueEffect, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Game.GraphicsDevice.BlendState = ColorWriteDisable;
|
||||||
|
for (int i = 0; i < ChunkMeshes.Count; i++)
|
||||||
|
{
|
||||||
|
if (Game.Camera.Frustum.Intersects(ChunkMeshes[i].BoundingBox))
|
||||||
|
{
|
||||||
|
if (!ChunkMeshes[i].IsDisposed)
|
||||||
|
verticies += ChunkMeshes[i].GetTotalVertices();
|
||||||
|
ChunkMeshes[i].Draw(TransparentEffect, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Game.GraphicsDevice.BlendState = BlendState.NonPremultiplied;
|
||||||
|
for (int i = 0; i < ChunkMeshes.Count; i++)
|
||||||
|
{
|
||||||
|
if (Game.Camera.Frustum.Intersects(ChunkMeshes[i].BoundingBox))
|
||||||
|
{
|
||||||
|
if (!ChunkMeshes[i].IsDisposed)
|
||||||
|
verticies += ChunkMeshes[i].GetTotalVertices();
|
||||||
|
ChunkMeshes[i].Draw(TransparentEffect, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
95
TrueCraft.Client/Modules/HighlightModule.cs
Normal file
95
TrueCraft.Client/Modules/HighlightModule.cs
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using TrueCraft.API;
|
||||||
|
using TrueCraft.Client.Rendering;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
|
||||||
|
namespace TrueCraft.Client.Modules
|
||||||
|
{
|
||||||
|
public class HighlightModule : IGraphicalModule
|
||||||
|
{
|
||||||
|
public TrueCraftGame Game { get; set; }
|
||||||
|
|
||||||
|
private Texture2D HighlightTexture { get; set; }
|
||||||
|
private Coordinates3D HighlightedBlock { get; set; }
|
||||||
|
private Mesh HighlightMesh { get; set; }
|
||||||
|
private BasicEffect HighlightEffect { get; set; }
|
||||||
|
|
||||||
|
public HighlightModule(TrueCraftGame game)
|
||||||
|
{
|
||||||
|
Game = game;
|
||||||
|
|
||||||
|
const int size = 64;
|
||||||
|
HighlightedBlock = -Coordinates3D.One;
|
||||||
|
HighlightTexture = new Texture2D(Game.GraphicsDevice, size, size);
|
||||||
|
|
||||||
|
var colors = new Color[size * size];
|
||||||
|
for (int i = 0; i < colors.Length; i++)
|
||||||
|
colors[i] = Color.Transparent;
|
||||||
|
for (int x = 0; x < size; x++)
|
||||||
|
colors[x] = Color.Black; // Top
|
||||||
|
for (int x = 0; x < size; x++)
|
||||||
|
colors[x + (size - 1) * size] = Color.Black; // Bottom
|
||||||
|
for (int y = 0; y < size; y++)
|
||||||
|
colors[y * size] = Color.Black; // Left
|
||||||
|
for (int y = 0; y < size; y++)
|
||||||
|
colors[y * size + (size - 1)] = Color.Black; // Right
|
||||||
|
|
||||||
|
HighlightTexture.SetData<Color>(colors);
|
||||||
|
var texcoords = new[]
|
||||||
|
{
|
||||||
|
Vector2.UnitX + Vector2.UnitY,
|
||||||
|
Vector2.UnitY,
|
||||||
|
Vector2.Zero,
|
||||||
|
Vector2.UnitX
|
||||||
|
};
|
||||||
|
int[] indicies;
|
||||||
|
var verticies = BlockRenderer.CreateUniformCube(Microsoft.Xna.Framework.Vector3.Zero,
|
||||||
|
texcoords, VisibleFaces.All, 0, out indicies, Color.White);
|
||||||
|
HighlightMesh = new Mesh(Game, verticies, indicies);
|
||||||
|
|
||||||
|
HighlightEffect = new BasicEffect(Game.GraphicsDevice);
|
||||||
|
HighlightEffect.EnableDefaultLighting();
|
||||||
|
HighlightEffect.DirectionalLight0.SpecularColor = Color.Black.ToVector3();
|
||||||
|
HighlightEffect.DirectionalLight1.SpecularColor = Color.Black.ToVector3();
|
||||||
|
HighlightEffect.DirectionalLight2.SpecularColor = Color.Black.ToVector3();
|
||||||
|
HighlightEffect.TextureEnabled = true;
|
||||||
|
HighlightEffect.Texture = HighlightTexture;
|
||||||
|
HighlightEffect.VertexColorEnabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(GameTime gameTime)
|
||||||
|
{
|
||||||
|
var direction = Microsoft.Xna.Framework.Vector3.Transform(
|
||||||
|
-Microsoft.Xna.Framework.Vector3.UnitZ,
|
||||||
|
Matrix.CreateRotationX(MathHelper.ToRadians(Game.Client.Pitch)) *
|
||||||
|
Matrix.CreateRotationY(MathHelper.ToRadians(Game.Client.Yaw)));
|
||||||
|
|
||||||
|
var cast = VoxelCast.Cast(Game.Client.World,
|
||||||
|
new TrueCraft.API.Ray(Game.Camera.Position,
|
||||||
|
new TrueCraft.API.Vector3(direction.X, direction.Y, direction.Z)),
|
||||||
|
Game.BlockRepository, TrueCraftGame.Reach);
|
||||||
|
|
||||||
|
if (cast == null)
|
||||||
|
HighlightedBlock = -Coordinates3D.One;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HighlightedBlock = cast.Item1;
|
||||||
|
HighlightEffect.World = Matrix.CreateScale(1.02f) *
|
||||||
|
Matrix.CreateTranslation(new Microsoft.Xna.Framework.Vector3(
|
||||||
|
cast.Item1.X, cast.Item1.Y, cast.Item1.Z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Draw(GameTime gameTime)
|
||||||
|
{
|
||||||
|
Game.Camera.ApplyTo(HighlightEffect);
|
||||||
|
|
||||||
|
if (HighlightedBlock != -Coordinates3D.One)
|
||||||
|
{
|
||||||
|
Game.GraphicsDevice.DepthStencilState = DepthStencilState.None;
|
||||||
|
HighlightMesh.Draw(HighlightEffect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
TrueCraft.Client/Modules/IGameplayModule.cs
Normal file
10
TrueCraft.Client/Modules/IGameplayModule.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
|
||||||
|
namespace TrueCraft.Client.Modules
|
||||||
|
{
|
||||||
|
public interface IGameplayModule
|
||||||
|
{
|
||||||
|
void Update(GameTime gameTime);
|
||||||
|
}
|
||||||
|
}
|
10
TrueCraft.Client/Modules/IGraphicalModule.cs
Normal file
10
TrueCraft.Client/Modules/IGraphicalModule.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
|
||||||
|
namespace TrueCraft.Client.Modules
|
||||||
|
{
|
||||||
|
public interface IGraphicalModule : IGameplayModule
|
||||||
|
{
|
||||||
|
void Draw(GameTime gameTime);
|
||||||
|
}
|
||||||
|
}
|
12
TrueCraft.Client/Modules/IInputModule.cs
Normal file
12
TrueCraft.Client/Modules/IInputModule.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using TrueCraft.Client.Input;
|
||||||
|
|
||||||
|
namespace TrueCraft.Client.Modules
|
||||||
|
{
|
||||||
|
public interface IInputModule : IGameplayModule
|
||||||
|
{
|
||||||
|
bool KeyDown(GameTime gameTime, KeyboardKeyEventArgs e);
|
||||||
|
bool KeyUp(GameTime gameTime, KeyboardKeyEventArgs e);
|
||||||
|
void MouseMove(GameTime gameTime, MouseMoveEventArgs e);
|
||||||
|
}
|
||||||
|
}
|
129
TrueCraft.Client/Modules/PlayerControlModule.cs
Normal file
129
TrueCraft.Client/Modules/PlayerControlModule.cs
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Input;
|
||||||
|
using TrueCraft.Client.Input;
|
||||||
|
using TCVector3 = TrueCraft.API.Vector3;
|
||||||
|
|
||||||
|
namespace TrueCraft.Client.Modules
|
||||||
|
{
|
||||||
|
public class PlayerControlModule : IInputModule
|
||||||
|
{
|
||||||
|
private TrueCraftGame Game { get; set; }
|
||||||
|
private Vector3 Delta { get; set; }
|
||||||
|
|
||||||
|
public PlayerControlModule(TrueCraftGame game)
|
||||||
|
{
|
||||||
|
Game = game;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool KeyDown(GameTime gameTime, KeyboardKeyEventArgs e)
|
||||||
|
{
|
||||||
|
switch (e.Key)
|
||||||
|
{
|
||||||
|
// Exit game
|
||||||
|
case Keys.Escape:
|
||||||
|
Process.GetCurrentProcess().Kill();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Take a screenshot.
|
||||||
|
case Keys.F2:
|
||||||
|
Game.TakeScreenshot();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Move to the left.
|
||||||
|
case Keys.A:
|
||||||
|
case Keys.Left:
|
||||||
|
Delta += Vector3.Left;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Move to the right.
|
||||||
|
case Keys.D:
|
||||||
|
case Keys.Right:
|
||||||
|
Delta += Vector3.Right;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Move forwards.
|
||||||
|
case Keys.W:
|
||||||
|
case Keys.Up:
|
||||||
|
Delta += Vector3.Forward;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Move backwards.
|
||||||
|
case Keys.S:
|
||||||
|
case Keys.Down:
|
||||||
|
Delta += Vector3.Backward;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case Keys.Space:
|
||||||
|
if (Math.Floor(Game.Client.Position.Y) == Game.Client.Position.Y)
|
||||||
|
Game.Client.Velocity += TrueCraft.API.Vector3.Up * 0.3;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool KeyUp(GameTime gameTime, KeyboardKeyEventArgs e)
|
||||||
|
{
|
||||||
|
switch (e.Key)
|
||||||
|
{
|
||||||
|
// Stop moving to the left.
|
||||||
|
case Keys.A:
|
||||||
|
case Keys.Left:
|
||||||
|
Delta -= Vector3.Left;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Stop moving to the right.
|
||||||
|
case Keys.D:
|
||||||
|
case Keys.Right:
|
||||||
|
Delta -= Vector3.Right;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Stop moving forwards.
|
||||||
|
case Keys.W:
|
||||||
|
case Keys.Up:
|
||||||
|
Delta -= Vector3.Forward;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Stop moving backwards.
|
||||||
|
case Keys.S:
|
||||||
|
case Keys.Down:
|
||||||
|
Delta -= Vector3.Backward;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void MouseMove(GameTime gameTime, MouseMoveEventArgs e)
|
||||||
|
{
|
||||||
|
var centerX = Game.GraphicsDevice.Viewport.Width / 2;
|
||||||
|
var centerY = Game.GraphicsDevice.Viewport.Height / 2;
|
||||||
|
Mouse.SetPosition(centerX, centerY);
|
||||||
|
|
||||||
|
var look = new Vector2((centerX - e.X), (centerY - e.Y))
|
||||||
|
* (float)(gameTime.ElapsedGameTime.TotalSeconds * 30);
|
||||||
|
|
||||||
|
Game.Client.Yaw += look.X;
|
||||||
|
Game.Client.Pitch += look.Y;
|
||||||
|
Game.Client.Yaw %= 360;
|
||||||
|
Game.Client.Pitch = MathHelper.Clamp(Game.Client.Pitch, -89.9f, 89.9f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(GameTime gameTime)
|
||||||
|
{
|
||||||
|
if (Delta != Vector3.Zero)
|
||||||
|
{
|
||||||
|
var lookAt = Vector3.Transform(Delta, Matrix.CreateRotationY(MathHelper.ToRadians(Game.Client.Yaw)));
|
||||||
|
|
||||||
|
lookAt.X *= (float)(gameTime.ElapsedGameTime.TotalSeconds * 4.3717);
|
||||||
|
lookAt.Z *= (float)(gameTime.ElapsedGameTime.TotalSeconds * 4.3717);
|
||||||
|
|
||||||
|
Game.Bobbing += Math.Max(Math.Abs(lookAt.X), Math.Abs(lookAt.Z));
|
||||||
|
|
||||||
|
Game.Client.Velocity = new TCVector3(lookAt.X, Game.Client.Velocity.Y, lookAt.Z);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Game.Client.Velocity *= new TCVector3(0, 1, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -133,19 +133,21 @@ namespace TrueCraft.Client.Rendering
|
|||||||
|
|
||||||
effectMatrices.View = _view;
|
effectMatrices.View = _view;
|
||||||
effectMatrices.Projection = _projection;
|
effectMatrices.Projection = _projection;
|
||||||
effectMatrices.World = Matrix.Identity;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the bounding frustum calculated for this camera.
|
/// Returns the bounding frustum calculated for this camera.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public BoundingFrustum GetFrustum()
|
public BoundingFrustum Frustum
|
||||||
|
{
|
||||||
|
get
|
||||||
{
|
{
|
||||||
if (_isDirty)
|
if (_isDirty)
|
||||||
Recalculate();
|
Recalculate();
|
||||||
return _frustum;
|
return _frustum;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the view matrix calculated for this camera.
|
/// Returns the view matrix calculated for this camera.
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<Import Project="..\targets\Client.targets" />
|
<Import Project="..\targets\Client.targets" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
@ -72,14 +71,15 @@
|
|||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
|
<Reference Include="MonoGame.Framework">
|
||||||
|
<HintPath>..\packages\MonoGame.Framework.Linux.3.4.0.459\lib\net40\MonoGame.Framework.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Input\KeyboardComponent.cs" />
|
|
||||||
<Compile Include="Input\KeyboardEventArgs.cs" />
|
<Compile Include="Input\KeyboardEventArgs.cs" />
|
||||||
<Compile Include="Input\KeyboardKeyEventArgs.cs" />
|
<Compile Include="Input\KeyboardKeyEventArgs.cs" />
|
||||||
<Compile Include="Input\MouseButton.cs" />
|
<Compile Include="Input\MouseButton.cs" />
|
||||||
<Compile Include="Input\MouseButtonEventArgs.cs" />
|
<Compile Include="Input\MouseButtonEventArgs.cs" />
|
||||||
<Compile Include="Input\MouseComponent.cs" />
|
|
||||||
<Compile Include="Input\MouseEventArgs.cs" />
|
<Compile Include="Input\MouseEventArgs.cs" />
|
||||||
<Compile Include="Input\MouseMoveEventArgs.cs" />
|
<Compile Include="Input\MouseMoveEventArgs.cs" />
|
||||||
<Compile Include="Input\MouseScrollEventArgs.cs" />
|
<Compile Include="Input\MouseScrollEventArgs.cs" />
|
||||||
@ -127,6 +127,14 @@
|
|||||||
<Compile Include="Rendering\Blocks\WaterRenderer.cs" />
|
<Compile Include="Rendering\Blocks\WaterRenderer.cs" />
|
||||||
<Compile Include="Rendering\Blocks\FarmlandRenderer.cs" />
|
<Compile Include="Rendering\Blocks\FarmlandRenderer.cs" />
|
||||||
<Compile Include="VoxelCast.cs" />
|
<Compile Include="VoxelCast.cs" />
|
||||||
|
<Compile Include="Input\KeyboardHandler.cs" />
|
||||||
|
<Compile Include="Input\MouseHandler.cs" />
|
||||||
|
<Compile Include="Modules\IGameplayModule.cs" />
|
||||||
|
<Compile Include="Modules\IInputModule.cs" />
|
||||||
|
<Compile Include="Modules\IGraphicalModule.cs" />
|
||||||
|
<Compile Include="Modules\ChunkModule.cs" />
|
||||||
|
<Compile Include="Modules\HighlightModule.cs" />
|
||||||
|
<Compile Include="Modules\PlayerControlModule.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@ -223,4 +231,7 @@
|
|||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Modules\" />
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@ -1,60 +1,58 @@
|
|||||||
using System;
|
using System;
|
||||||
using Microsoft.Xna.Framework;
|
using System.Collections.Concurrent;
|
||||||
using Microsoft.Xna.Framework.Input;
|
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using TrueCraft.Client.Interface;
|
using System.ComponentModel;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using TrueCraft.API;
|
using Microsoft.Xna.Framework;
|
||||||
using TrueCraft.Client.Rendering;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using System.Linq;
|
using Microsoft.Xna.Framework.Input;
|
||||||
using System.ComponentModel;
|
|
||||||
using TrueCraft.Core.Networking.Packets;
|
|
||||||
using TrueCraft.API.World;
|
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using TrueCraft.Client.Input;
|
|
||||||
using TrueCraft.Core;
|
|
||||||
using MonoGame.Utilities.Png;
|
using MonoGame.Utilities.Png;
|
||||||
using System.Diagnostics;
|
using TrueCraft.API;
|
||||||
using TrueCraft.Core.Logic.Blocks;
|
using TrueCraft.API.Logic;
|
||||||
|
using TrueCraft.API.World;
|
||||||
|
using TrueCraft.Core;
|
||||||
|
using TrueCraft.Core.Networking.Packets;
|
||||||
|
using TrueCraft.Client.Input;
|
||||||
|
using TrueCraft.Client.Interface;
|
||||||
|
using TrueCraft.Client.Modules;
|
||||||
|
using TrueCraft.Client.Rendering;
|
||||||
|
|
||||||
namespace TrueCraft.Client
|
namespace TrueCraft.Client
|
||||||
{
|
{
|
||||||
public class TrueCraftGame : Game
|
public class TrueCraftGame : Game
|
||||||
{
|
{
|
||||||
private MultiplayerClient Client { get; set; }
|
public MultiplayerClient Client { get; private set; }
|
||||||
private GraphicsDeviceManager Graphics { get; set; }
|
public GraphicsDeviceManager Graphics { get; private set; }
|
||||||
private List<IGameInterface> Interfaces { get; set; }
|
public TextureMapper TextureMapper { get; private set; }
|
||||||
private FontRenderer Pixel { get; set; }
|
public Camera Camera { get; private set; }
|
||||||
|
public ConcurrentBag<Action> PendingMainThreadActions { get; set; }
|
||||||
|
public double Bobbing { get; set; }
|
||||||
|
|
||||||
|
private List<IGameplayModule> Modules { get; set; }
|
||||||
private SpriteBatch SpriteBatch { get; set; }
|
private SpriteBatch SpriteBatch { get; set; }
|
||||||
|
private KeyboardHandler KeyboardComponent { get; set; }
|
||||||
|
private MouseHandler MouseComponent { get; set; }
|
||||||
|
private RenderTarget2D RenderTarget { get; set; }
|
||||||
|
|
||||||
|
private FontRenderer Pixel { get; set; }
|
||||||
private IPEndPoint EndPoint { get; set; }
|
private IPEndPoint EndPoint { get; set; }
|
||||||
private ChunkRenderer ChunkConverter { get; set; }
|
|
||||||
private DateTime LastPhysicsUpdate { get; set; }
|
private DateTime LastPhysicsUpdate { get; set; }
|
||||||
private DateTime NextPhysicsUpdate { get; set; }
|
private DateTime NextPhysicsUpdate { get; set; }
|
||||||
private List<Mesh> ChunkMeshes { get; set; }
|
private bool MouseCaptured { get; set; }
|
||||||
public ConcurrentBag<Action> PendingMainThreadActions { get; set; }
|
|
||||||
private ConcurrentBag<Mesh> IncomingChunks { get; set; }
|
|
||||||
public ChatInterface ChatInterface { get; set; }
|
|
||||||
public DebugInterface DebugInterface { get; set; }
|
|
||||||
private RenderTarget2D RenderTarget;
|
|
||||||
private BoundingFrustum CameraView;
|
|
||||||
private Camera Camera;
|
|
||||||
private bool MouseCaptured;
|
|
||||||
private KeyboardComponent KeyboardComponent { get; set; }
|
|
||||||
private MouseComponent MouseComponent { get; set; }
|
|
||||||
private GameTime GameTime { get; set; }
|
private GameTime GameTime { get; set; }
|
||||||
private Microsoft.Xna.Framework.Vector3 Delta { get; set; }
|
private Microsoft.Xna.Framework.Vector3 Delta { get; set; }
|
||||||
private TextureMapper TextureMapper { get; set; }
|
|
||||||
private double Bobbing { get; set; }
|
|
||||||
private Coordinates3D HighlightedBlock { get; set; }
|
|
||||||
private Mesh HighlightMesh { get; set; }
|
|
||||||
private Texture2D HighlightTexture { get; set; }
|
|
||||||
private BasicEffect OpaqueEffect, HighlightEffect;
|
|
||||||
private AlphaTestEffect TransparentEffect;
|
|
||||||
|
|
||||||
public static readonly int Reach = 5;
|
public static readonly int Reach = 5;
|
||||||
|
|
||||||
|
public IBlockRepository BlockRepository
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Client.World.World.BlockRepository;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public TrueCraftGame(MultiplayerClient client, IPEndPoint endPoint)
|
public TrueCraftGame(MultiplayerClient client, IPEndPoint endPoint)
|
||||||
{
|
{
|
||||||
Window.Title = "TrueCraft";
|
Window.Title = "TrueCraft";
|
||||||
@ -68,75 +66,46 @@ namespace TrueCraft.Client
|
|||||||
EndPoint = endPoint;
|
EndPoint = endPoint;
|
||||||
LastPhysicsUpdate = DateTime.MinValue;
|
LastPhysicsUpdate = DateTime.MinValue;
|
||||||
NextPhysicsUpdate = DateTime.MinValue;
|
NextPhysicsUpdate = DateTime.MinValue;
|
||||||
ChunkMeshes = new List<Mesh>();
|
|
||||||
IncomingChunks = new ConcurrentBag<Mesh>();
|
|
||||||
PendingMainThreadActions = new ConcurrentBag<Action>();
|
PendingMainThreadActions = new ConcurrentBag<Action>();
|
||||||
MouseCaptured = true;
|
MouseCaptured = true;
|
||||||
Bobbing = 0;
|
Bobbing = 0;
|
||||||
|
|
||||||
var keyboardComponent = new KeyboardComponent(this);
|
var keyboardComponent = new KeyboardHandler(this);
|
||||||
KeyboardComponent = keyboardComponent;
|
KeyboardComponent = keyboardComponent;
|
||||||
Components.Add(keyboardComponent);
|
Components.Add(keyboardComponent);
|
||||||
|
|
||||||
var mouseComponent = new MouseComponent(this);
|
var mouseComponent = new MouseHandler(this);
|
||||||
MouseComponent = mouseComponent;
|
MouseComponent = mouseComponent;
|
||||||
Components.Add(mouseComponent);
|
Components.Add(mouseComponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Initialize()
|
protected override void Initialize()
|
||||||
{
|
{
|
||||||
Interfaces = new List<IGameInterface>();
|
Modules = new List<IGameplayModule>();
|
||||||
SpriteBatch = new SpriteBatch(GraphicsDevice);
|
|
||||||
base.Initialize(); // (calls LoadContent)
|
base.Initialize(); // (calls LoadContent)
|
||||||
ChunkConverter = new ChunkRenderer(Client.World, this, Client.World.World.BlockRepository);
|
|
||||||
Client.ChunkLoaded += (sender, e) => ChunkConverter.Enqueue(e.Chunk);
|
Modules.Add(new ChunkModule(this));
|
||||||
//Client.ChunkModified += (sender, e) => ChunkConverter.Enqueue(e.Chunk, true);
|
Modules.Add(new HighlightModule(this));
|
||||||
ChunkConverter.MeshCompleted += ChunkConverter_MeshGenerated;
|
Modules.Add(new PlayerControlModule(this));
|
||||||
ChunkConverter.Start();
|
|
||||||
Client.PropertyChanged += HandleClientPropertyChanged;
|
Client.PropertyChanged += HandleClientPropertyChanged;
|
||||||
Client.Connect(EndPoint);
|
Client.Connect(EndPoint);
|
||||||
|
|
||||||
var centerX = GraphicsDevice.Viewport.Width / 2;
|
var centerX = GraphicsDevice.Viewport.Width / 2;
|
||||||
var centerY = GraphicsDevice.Viewport.Height / 2;
|
var centerY = GraphicsDevice.Viewport.Height / 2;
|
||||||
Mouse.SetPosition(centerX, centerY);
|
Mouse.SetPosition(centerX, centerY);
|
||||||
|
|
||||||
Camera = new Camera(GraphicsDevice.Viewport.AspectRatio, 70.0f, 0.1f, 1000.0f);
|
Camera = new Camera(GraphicsDevice.Viewport.AspectRatio, 70.0f, 0.1f, 1000.0f);
|
||||||
UpdateCamera();
|
UpdateCamera();
|
||||||
Window.ClientSizeChanged += (sender, e) => CreateRenderTarget();
|
|
||||||
MouseComponent.Move += OnMouseComponentMove;
|
MouseComponent.Move += OnMouseComponentMove;
|
||||||
KeyboardComponent.KeyDown += OnKeyboardKeyDown;
|
KeyboardComponent.KeyDown += OnKeyboardKeyDown;
|
||||||
KeyboardComponent.KeyUp += OnKeyboardKeyUp;
|
KeyboardComponent.KeyUp += OnKeyboardKeyUp;
|
||||||
|
|
||||||
|
Window.ClientSizeChanged += (sender, e) => CreateRenderTarget();
|
||||||
CreateRenderTarget();
|
CreateRenderTarget();
|
||||||
}
|
SpriteBatch = new SpriteBatch(GraphicsDevice);
|
||||||
|
|
||||||
private void InitializeHighlightedBlock()
|
|
||||||
{
|
|
||||||
const int size = 64;
|
|
||||||
HighlightedBlock = -Coordinates3D.One;
|
|
||||||
HighlightTexture = new Texture2D(GraphicsDevice, size, size);
|
|
||||||
|
|
||||||
var colors = new Color[size * size];
|
|
||||||
for (int i = 0; i < colors.Length; i++)
|
|
||||||
colors[i] = Color.Transparent;
|
|
||||||
for (int x = 0; x < size; x++)
|
|
||||||
colors[x] = Color.Black; // Top
|
|
||||||
for (int x = 0; x < size; x++)
|
|
||||||
colors[x + (size - 1) * size] = Color.Black; // Bottom
|
|
||||||
for (int y = 0; y < size; y++)
|
|
||||||
colors[y * size] = Color.Black; // Left
|
|
||||||
for (int y = 0; y < size; y++)
|
|
||||||
colors[y * size + (size - 1)] = Color.Black; // Right
|
|
||||||
|
|
||||||
HighlightTexture.SetData<Color>(colors);
|
|
||||||
var texcoords = new[]
|
|
||||||
{
|
|
||||||
Vector2.UnitX + Vector2.UnitY,
|
|
||||||
Vector2.UnitY,
|
|
||||||
Vector2.Zero,
|
|
||||||
Vector2.UnitX
|
|
||||||
};
|
|
||||||
int[] indicies;
|
|
||||||
var verticies = BlockRenderer.CreateUniformCube(Microsoft.Xna.Framework.Vector3.Zero,
|
|
||||||
texcoords, VisibleFaces.All, 0, out indicies, Color.White);
|
|
||||||
HighlightMesh = new Mesh(this, verticies, indicies);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateRenderTarget()
|
private void CreateRenderTarget()
|
||||||
@ -145,20 +114,12 @@ namespace TrueCraft.Client
|
|||||||
false, GraphicsDevice.PresentationParameters.BackBufferFormat, DepthFormat.Depth24);
|
false, GraphicsDevice.PresentationParameters.BackBufferFormat, DepthFormat.Depth24);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChunkConverter_MeshGenerated(object sender, RendererEventArgs<ReadOnlyChunk> e)
|
|
||||||
{
|
|
||||||
IncomingChunks.Add(e.Result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HandleClientPropertyChanged(object sender, PropertyChangedEventArgs e)
|
void HandleClientPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||||
{
|
{
|
||||||
switch (e.PropertyName)
|
switch (e.PropertyName)
|
||||||
{
|
{
|
||||||
case "Position":
|
case "Position":
|
||||||
UpdateCamera();
|
UpdateCamera();
|
||||||
var sorter = new ChunkRenderer.ChunkSorter(new Coordinates3D(
|
|
||||||
(int)Client.Position.X, 0, (int)Client.Position.Z));
|
|
||||||
PendingMainThreadActions.Add(() => ChunkMeshes.Sort(sorter));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -174,212 +135,52 @@ namespace TrueCraft.Client
|
|||||||
TextureMapper.AddTexturePack(TexturePack.FromArchive(Path.Combine(TexturePack.TexturePackPath, UserSettings.Local.SelectedTexturePack)));
|
TextureMapper.AddTexturePack(TexturePack.FromArchive(Path.Combine(TexturePack.TexturePackPath, UserSettings.Local.SelectedTexturePack)));
|
||||||
|
|
||||||
Pixel = new FontRenderer(
|
Pixel = new FontRenderer(
|
||||||
new Font(Content, "Fonts/Pixel", FontStyle.Regular),
|
new Font(Content, "Fonts/Pixel"),
|
||||||
new Font(Content, "Fonts/Pixel", FontStyle.Bold),
|
new Font(Content, "Fonts/Pixel", FontStyle.Bold),
|
||||||
null, // No support for underlined or strikethrough yet. The FontRenderer will revert to using the regular font style.
|
null, // No support for underlined or strikethrough yet. The FontRenderer will revert to using the regular font style.
|
||||||
null, // (I don't think BMFont has those options?)
|
null, // (I don't think BMFont has those options?)
|
||||||
new Font(Content, "Fonts/Pixel", FontStyle.Italic));
|
new Font(Content, "Fonts/Pixel", FontStyle.Italic));
|
||||||
Interfaces.Add(ChatInterface = new ChatInterface(Client, KeyboardComponent, Pixel));
|
|
||||||
Interfaces.Add(DebugInterface = new DebugInterface(Client, Pixel));
|
|
||||||
|
|
||||||
ChatInterface.IsVisible = true;
|
|
||||||
DebugInterface.IsVisible = true;
|
|
||||||
|
|
||||||
OpaqueEffect = new BasicEffect(GraphicsDevice);
|
|
||||||
OpaqueEffect.EnableDefaultLighting();
|
|
||||||
OpaqueEffect.DirectionalLight0.SpecularColor = Color.Black.ToVector3();
|
|
||||||
OpaqueEffect.DirectionalLight1.SpecularColor = Color.Black.ToVector3();
|
|
||||||
OpaqueEffect.DirectionalLight2.SpecularColor = Color.Black.ToVector3();
|
|
||||||
OpaqueEffect.TextureEnabled = true;
|
|
||||||
OpaqueEffect.Texture = TextureMapper.GetTexture("terrain.png");
|
|
||||||
OpaqueEffect.FogEnabled = true;
|
|
||||||
OpaqueEffect.FogStart = 512f;
|
|
||||||
OpaqueEffect.FogEnd = 1000f;
|
|
||||||
OpaqueEffect.FogColor = Color.CornflowerBlue.ToVector3();
|
|
||||||
OpaqueEffect.VertexColorEnabled = true;
|
|
||||||
|
|
||||||
TransparentEffect = new AlphaTestEffect(GraphicsDevice);
|
|
||||||
TransparentEffect.AlphaFunction = CompareFunction.Greater;
|
|
||||||
TransparentEffect.ReferenceAlpha = 127;
|
|
||||||
TransparentEffect.Texture = TextureMapper.GetTexture("terrain.png");
|
|
||||||
TransparentEffect.VertexColorEnabled = true;
|
|
||||||
|
|
||||||
InitializeHighlightedBlock();
|
|
||||||
|
|
||||||
HighlightEffect = new BasicEffect(GraphicsDevice);
|
|
||||||
HighlightEffect.EnableDefaultLighting();
|
|
||||||
HighlightEffect.DirectionalLight0.SpecularColor = Color.Black.ToVector3();
|
|
||||||
HighlightEffect.DirectionalLight1.SpecularColor = Color.Black.ToVector3();
|
|
||||||
HighlightEffect.DirectionalLight2.SpecularColor = Color.Black.ToVector3();
|
|
||||||
HighlightEffect.TextureEnabled = true;
|
|
||||||
HighlightEffect.Texture = HighlightTexture;
|
|
||||||
HighlightEffect.VertexColorEnabled = true;
|
|
||||||
|
|
||||||
base.LoadContent();
|
base.LoadContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnExiting(object sender, EventArgs args)
|
|
||||||
{
|
|
||||||
ChunkConverter.Stop();
|
|
||||||
base.OnExiting(sender, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnKeyboardKeyDown(object sender, KeyboardKeyEventArgs e)
|
private void OnKeyboardKeyDown(object sender, KeyboardKeyEventArgs e)
|
||||||
{
|
{
|
||||||
// TODO: Rebindable keys
|
foreach (var module in Modules)
|
||||||
// TODO: Horizontal terrain collisions
|
|
||||||
|
|
||||||
switch (e.Key)
|
|
||||||
{
|
{
|
||||||
// Close game (or chat).
|
var input = module as IInputModule;
|
||||||
case Keys.Escape:
|
if (input != null)
|
||||||
if (ChatInterface.HasFocus)
|
|
||||||
ChatInterface.HasFocus = false;
|
|
||||||
else
|
|
||||||
Process.GetCurrentProcess().Kill();
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Open chat window.
|
|
||||||
case Keys.T:
|
|
||||||
if (!ChatInterface.HasFocus && ChatInterface.IsVisible)
|
|
||||||
ChatInterface.HasFocus = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Open chat window.
|
|
||||||
case Keys.OemQuestion:
|
|
||||||
if (!ChatInterface.HasFocus && ChatInterface.IsVisible)
|
|
||||||
ChatInterface.HasFocus = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Close chat window.
|
|
||||||
case Keys.Enter:
|
|
||||||
if (ChatInterface.HasFocus)
|
|
||||||
ChatInterface.HasFocus = false;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Take a screenshot.
|
|
||||||
case Keys.F2:
|
|
||||||
TakeScreenshot();
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Toggle debug view.
|
|
||||||
case Keys.F3:
|
|
||||||
DebugInterface.IsVisible = !DebugInterface.IsVisible;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Change interface scale.
|
|
||||||
case Keys.F4:
|
|
||||||
foreach (var item in Interfaces)
|
|
||||||
{
|
{
|
||||||
item.Scale = (InterfaceScale)(item.Scale + 1);
|
if (input.KeyDown(GameTime, e))
|
||||||
if ((int)item.Scale > 2)
|
|
||||||
item.Scale = InterfaceScale.Small;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Move to the left.
|
|
||||||
case Keys.A:
|
|
||||||
case Keys.Left:
|
|
||||||
if (ChatInterface.HasFocus)
|
|
||||||
break;
|
|
||||||
Delta += Microsoft.Xna.Framework.Vector3.Left;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Move to the right.
|
|
||||||
case Keys.D:
|
|
||||||
case Keys.Right:
|
|
||||||
if (ChatInterface.HasFocus)
|
|
||||||
break;
|
|
||||||
Delta += Microsoft.Xna.Framework.Vector3.Right;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Move forwards.
|
|
||||||
case Keys.W:
|
|
||||||
case Keys.Up:
|
|
||||||
if (ChatInterface.HasFocus)
|
|
||||||
break;
|
|
||||||
Delta += Microsoft.Xna.Framework.Vector3.Forward;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Move backwards.
|
|
||||||
case Keys.S:
|
|
||||||
case Keys.Down:
|
|
||||||
if (ChatInterface.HasFocus)
|
|
||||||
break;
|
|
||||||
Delta += Microsoft.Xna.Framework.Vector3.Backward;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Keys.Space:
|
|
||||||
if (ChatInterface.HasFocus)
|
|
||||||
break;
|
|
||||||
if (Math.Floor(Client.Position.Y) == Client.Position.Y) // Crappy onground substitute
|
|
||||||
Client.Velocity += TrueCraft.API.Vector3.Up * 0.3;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Toggle mouse capture.
|
|
||||||
case Keys.Tab:
|
|
||||||
MouseCaptured = !MouseCaptured;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnKeyboardKeyUp(object sender, KeyboardKeyEventArgs e)
|
private void OnKeyboardKeyUp(object sender, KeyboardKeyEventArgs e)
|
||||||
{
|
{
|
||||||
switch (e.Key)
|
foreach (var module in Modules)
|
||||||
{
|
{
|
||||||
// Stop moving to the left.
|
var input = module as IInputModule;
|
||||||
case Keys.A:
|
if (input != null)
|
||||||
case Keys.Left:
|
{
|
||||||
if (ChatInterface.HasFocus) break;
|
if (input.KeyUp(GameTime, e))
|
||||||
Delta -= Microsoft.Xna.Framework.Vector3.Left;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Stop moving to the right.
|
|
||||||
case Keys.D:
|
|
||||||
case Keys.Right:
|
|
||||||
if (ChatInterface.HasFocus) break;
|
|
||||||
Delta -= Microsoft.Xna.Framework.Vector3.Right;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Stop moving forwards.
|
|
||||||
case Keys.W:
|
|
||||||
case Keys.Up:
|
|
||||||
if (ChatInterface.HasFocus) break;
|
|
||||||
Delta -= Microsoft.Xna.Framework.Vector3.Forward;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Stop moving backwards.
|
|
||||||
case Keys.S:
|
|
||||||
case Keys.Down:
|
|
||||||
if (ChatInterface.HasFocus) break;
|
|
||||||
Delta -= Microsoft.Xna.Framework.Vector3.Backward;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void OnMouseComponentMove(object sender, MouseMoveEventArgs e)
|
private void OnMouseComponentMove(object sender, MouseMoveEventArgs e)
|
||||||
{
|
{
|
||||||
if (MouseCaptured && IsActive)
|
foreach (var module in Modules)
|
||||||
{
|
{
|
||||||
var centerX = GraphicsDevice.Viewport.Width / 2;
|
var input = module as IInputModule;
|
||||||
var centerY = GraphicsDevice.Viewport.Height / 2;
|
if (input != null)
|
||||||
Mouse.SetPosition(centerX, centerY);
|
input.MouseMove(GameTime, e);
|
||||||
|
|
||||||
var look = new Vector2((centerX - e.X), (centerY - e.Y))
|
|
||||||
* (float)(GameTime.ElapsedGameTime.TotalSeconds * 30);
|
|
||||||
|
|
||||||
Client.Yaw += look.X;
|
|
||||||
Client.Pitch += look.Y;
|
|
||||||
Client.Yaw %= 360;
|
|
||||||
Client.Pitch = Microsoft.Xna.Framework.MathHelper.Clamp(Client.Pitch, -89.9f, 89.9f);
|
|
||||||
|
|
||||||
if (look != Vector2.Zero)
|
|
||||||
UpdateCamera();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TakeScreenshot()
|
public void TakeScreenshot()
|
||||||
{
|
{
|
||||||
var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
|
var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
|
||||||
".truecraft", "screenshots", DateTime.Now.ToString("yyyy-MM-dd_H.mm.ss") + ".png");
|
".truecraft", "screenshots", DateTime.Now.ToString("yyyy-MM-dd_H.mm.ss") + ".png");
|
||||||
@ -387,29 +188,19 @@ namespace TrueCraft.Client
|
|||||||
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
||||||
using (var stream = File.OpenWrite(path))
|
using (var stream = File.OpenWrite(path))
|
||||||
new PngWriter().Write(RenderTarget, stream);
|
new PngWriter().Write(RenderTarget, stream);
|
||||||
ChatInterface.AddMessage(string.Format("Screenshot saved as {0}", Path.GetFileName(path)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update(GameTime gameTime)
|
protected override void Update(GameTime gameTime)
|
||||||
{
|
{
|
||||||
GameTime = gameTime;
|
GameTime = gameTime;
|
||||||
|
|
||||||
foreach (var i in Interfaces)
|
|
||||||
{
|
|
||||||
i.Update(gameTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
Mesh mesh;
|
|
||||||
while (IncomingChunks.TryTake(out mesh))
|
|
||||||
{
|
|
||||||
ChunkMeshes.Add(mesh);
|
|
||||||
}
|
|
||||||
Action action;
|
Action action;
|
||||||
if (PendingMainThreadActions.TryTake(out action))
|
if (PendingMainThreadActions.TryTake(out action))
|
||||||
action();
|
action();
|
||||||
|
|
||||||
IChunk chunk;
|
IChunk chunk;
|
||||||
var adjusted = Client.World.World.FindBlockPosition(new Coordinates3D((int)Client.Position.X, 0, (int)Client.Position.Z), out chunk);
|
var adjusted = Client.World.World.FindBlockPosition(
|
||||||
|
new Coordinates3D((int)Client.Position.X, 0, (int)Client.Position.Z), out chunk);
|
||||||
if (chunk != null && Client.LoggedIn)
|
if (chunk != null && Client.LoggedIn)
|
||||||
{
|
{
|
||||||
if (chunk.GetHeight((byte)adjusted.X, (byte)adjusted.Z) != 0)
|
if (chunk.GetHeight((byte)adjusted.X, (byte)adjusted.Z) != 0)
|
||||||
@ -426,69 +217,29 @@ namespace TrueCraft.Client
|
|||||||
NextPhysicsUpdate = DateTime.UtcNow.AddMilliseconds(1000 / 20);
|
NextPhysicsUpdate = DateTime.UtcNow.AddMilliseconds(1000 / 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Delta != Microsoft.Xna.Framework.Vector3.Zero)
|
foreach (var module in Modules)
|
||||||
{
|
module.Update(gameTime);
|
||||||
var lookAt = Microsoft.Xna.Framework.Vector3.Transform(
|
|
||||||
Delta, Matrix.CreateRotationY(Microsoft.Xna.Framework.MathHelper.ToRadians(Client.Yaw)));
|
|
||||||
|
|
||||||
lookAt.X *= (float)(gameTime.ElapsedGameTime.TotalSeconds * 4.3717);
|
|
||||||
lookAt.Z *= (float)(gameTime.ElapsedGameTime.TotalSeconds * 4.3717);
|
|
||||||
|
|
||||||
Bobbing += Math.Max(Math.Abs(lookAt.X), Math.Abs(lookAt.Z));
|
|
||||||
|
|
||||||
Client.Velocity = new TrueCraft.API.Vector3(lookAt.X, Client.Velocity.Y, lookAt.Z);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
Client.Velocity *= new TrueCraft.API.Vector3(0, 1, 0);
|
|
||||||
|
|
||||||
UpdateCamera();
|
UpdateCamera();
|
||||||
|
|
||||||
base.Update(gameTime);
|
base.Update(gameTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateCamera()
|
private void UpdateCamera()
|
||||||
{
|
{
|
||||||
const double bobbingMultiplier = 0.015;
|
const double bobbingMultiplier = 0.015;
|
||||||
|
|
||||||
var bobbing = Bobbing * 1.5;
|
var bobbing = Bobbing * 1.5;
|
||||||
|
var xbob = Math.Cos(bobbing + Math.PI / 2) * bobbingMultiplier;
|
||||||
|
var ybob = Math.Sin(Math.PI / 2 - (2 * bobbing)) * bobbingMultiplier;
|
||||||
Camera.Position = new TrueCraft.API.Vector3(
|
Camera.Position = new TrueCraft.API.Vector3(
|
||||||
Client.Position.X + Math.Cos(bobbing + Math.PI / 2) * bobbingMultiplier
|
Client.Position.X + xbob - (Client.Size.Width / 2),
|
||||||
- (Client.Size.Width / 2),
|
Client.Position.Y + (Client.Size.Height - 0.5) + ybob,
|
||||||
Client.Position.Y + (Client.Size.Height - 0.5)
|
|
||||||
+ Math.Sin(Math.PI / 2 - (2 * bobbing)) * bobbingMultiplier,
|
|
||||||
Client.Position.Z - (Client.Size.Depth / 2));
|
Client.Position.Z - (Client.Size.Depth / 2));
|
||||||
|
|
||||||
Camera.Pitch = Client.Pitch;
|
Camera.Pitch = Client.Pitch;
|
||||||
Camera.Yaw = Client.Yaw;
|
Camera.Yaw = Client.Yaw;
|
||||||
|
|
||||||
CameraView = Camera.GetFrustum();
|
|
||||||
|
|
||||||
Camera.ApplyTo(HighlightEffect);
|
|
||||||
Camera.ApplyTo(OpaqueEffect);
|
|
||||||
Camera.ApplyTo(TransparentEffect);
|
|
||||||
|
|
||||||
var direction = Microsoft.Xna.Framework.Vector3.Transform(
|
|
||||||
-Microsoft.Xna.Framework.Vector3.UnitZ,
|
|
||||||
Matrix.CreateRotationX(Microsoft.Xna.Framework.MathHelper.ToRadians(Client.Pitch)) *
|
|
||||||
Matrix.CreateRotationY(Microsoft.Xna.Framework.MathHelper.ToRadians(Client.Yaw)));
|
|
||||||
|
|
||||||
var cast = VoxelCast.Cast(Client.World,
|
|
||||||
new TrueCraft.API.Ray(Camera.Position, new TrueCraft.API.Vector3(
|
|
||||||
direction.X, direction.Y, direction.Z)),
|
|
||||||
Client.World.World.BlockRepository, Reach);
|
|
||||||
|
|
||||||
if (cast == null)
|
|
||||||
HighlightedBlock = -Coordinates3D.One;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
HighlightEffect.World = Matrix.CreateScale(1.02f) *
|
|
||||||
Matrix.CreateTranslation(new Microsoft.Xna.Framework.Vector3(
|
|
||||||
cast.Item1.X, cast.Item1.Y, cast.Item1.Z));
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private static readonly BlendState ColorWriteDisable = new BlendState()
|
|
||||||
{
|
|
||||||
ColorWriteChannels = ColorWriteChannels.None
|
|
||||||
};
|
|
||||||
|
|
||||||
protected override void Draw(GameTime gameTime)
|
protected override void Draw(GameTime gameTime)
|
||||||
{
|
{
|
||||||
@ -499,55 +250,15 @@ namespace TrueCraft.Client
|
|||||||
GraphicsDevice.SamplerStates[0] = SamplerState.PointClamp;
|
GraphicsDevice.SamplerStates[0] = SamplerState.PointClamp;
|
||||||
GraphicsDevice.SamplerStates[1] = SamplerState.PointClamp;
|
GraphicsDevice.SamplerStates[1] = SamplerState.PointClamp;
|
||||||
|
|
||||||
int verticies = 0, chunks = 0;
|
foreach (var module in Modules)
|
||||||
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
|
|
||||||
for (int i = 0; i < ChunkMeshes.Count; i++)
|
|
||||||
{
|
{
|
||||||
if (CameraView.Intersects(ChunkMeshes[i].BoundingBox))
|
var drawable = module as IGraphicalModule;
|
||||||
{
|
if (drawable != null)
|
||||||
verticies += ChunkMeshes[i].GetTotalVertices();
|
drawable.Draw(gameTime);
|
||||||
chunks++;
|
|
||||||
ChunkMeshes[i].Draw(OpaqueEffect, 0);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
HighlightMesh.Draw(HighlightEffect);
|
|
||||||
|
|
||||||
GraphicsDevice.BlendState = ColorWriteDisable;
|
|
||||||
for (int i = 0; i < ChunkMeshes.Count; i++)
|
|
||||||
{
|
|
||||||
if (CameraView.Intersects(ChunkMeshes[i].BoundingBox))
|
|
||||||
{
|
|
||||||
if (!ChunkMeshes[i].IsDisposed)
|
|
||||||
verticies += ChunkMeshes[i].GetTotalVertices();
|
|
||||||
ChunkMeshes[i].Draw(TransparentEffect, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GraphicsDevice.BlendState = BlendState.NonPremultiplied;
|
|
||||||
for (int i = 0; i < ChunkMeshes.Count; i++)
|
|
||||||
{
|
|
||||||
if (CameraView.Intersects(ChunkMeshes[i].BoundingBox))
|
|
||||||
{
|
|
||||||
if (!ChunkMeshes[i].IsDisposed)
|
|
||||||
verticies += ChunkMeshes[i].GetTotalVertices();
|
|
||||||
ChunkMeshes[i].Draw(TransparentEffect, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DebugInterface.Vertices = verticies;
|
|
||||||
DebugInterface.Chunks = chunks;
|
|
||||||
DebugInterface.HighlightedBlock = HighlightedBlock;
|
|
||||||
|
|
||||||
HighlightMesh.Draw(HighlightEffect);
|
|
||||||
|
|
||||||
SpriteBatch.Begin(SpriteSortMode.Deferred, null, SamplerState.PointClamp, null, null, null, null);
|
|
||||||
for (int i = 0; i < Interfaces.Count; i++)
|
|
||||||
Interfaces[i].DrawSprites(gameTime, SpriteBatch);
|
|
||||||
SpriteBatch.End();
|
|
||||||
|
|
||||||
GraphicsDevice.SetRenderTarget(null);
|
GraphicsDevice.SetRenderTarget(null);
|
||||||
|
|
||||||
GraphicsDevice.Clear(Color.CornflowerBlue);
|
|
||||||
SpriteBatch.Begin();
|
SpriteBatch.Begin();
|
||||||
SpriteBatch.Draw(RenderTarget, new Vector2(0));
|
SpriteBatch.Draw(RenderTarget, new Vector2(0));
|
||||||
SpriteBatch.End();
|
SpriteBatch.End();
|
||||||
@ -559,8 +270,6 @@ namespace TrueCraft.Client
|
|||||||
{
|
{
|
||||||
if (disposing)
|
if (disposing)
|
||||||
{
|
{
|
||||||
ChunkConverter.Dispose();
|
|
||||||
|
|
||||||
KeyboardComponent.Dispose();
|
KeyboardComponent.Dispose();
|
||||||
MouseComponent.Dispose();
|
MouseComponent.Dispose();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user