Improve use of concurrent .NET patterns
This commit is contained in:
parent
bd132b0d6f
commit
b308252b88
@ -99,15 +99,19 @@ namespace TrueCraft.Client
|
||||
Coordinates3D.West
|
||||
};
|
||||
|
||||
private readonly List<VertexPositionNormalTexture> OpaqueVerticies = new List<VertexPositionNormalTexture>();
|
||||
private readonly List<int> OpaqueIndicies = new List<int>();
|
||||
private readonly List<VertexPositionNormalTexture> TransparentVerticies = new List<VertexPositionNormalTexture>();
|
||||
private readonly List<int> TransparentIndicies = new List<int>();
|
||||
private readonly HashSet<Coordinates3D> DrawableCoordinates = new HashSet<Coordinates3D>();
|
||||
|
||||
private Tuple<Mesh, Mesh> ProcessChunk(ReadOnlyChunk chunk)
|
||||
{
|
||||
var opaqueVerticies = new List<VertexPositionNormalTexture>();
|
||||
var opaqueIndicies = new List<int>();
|
||||
|
||||
var transparentVerticies = new List<VertexPositionNormalTexture>();
|
||||
var transparentIndicies = new List<int>();
|
||||
|
||||
var drawableCoordinates = new HashSet<Coordinates3D>();
|
||||
OpaqueVerticies.Clear();
|
||||
OpaqueIndicies.Clear();
|
||||
TransparentVerticies.Clear();
|
||||
TransparentIndicies.Clear();
|
||||
DrawableCoordinates.Clear();
|
||||
|
||||
var boundingBox = new Microsoft.Xna.Framework.BoundingBox(
|
||||
new Vector3(chunk.X * Chunk.Width, 0, chunk.Z * Chunk.Depth),
|
||||
@ -123,7 +127,7 @@ namespace TrueCraft.Client
|
||||
var id = chunk.GetBlockId(coords);
|
||||
var provider = BlockRepository.GetBlockProvider(id);
|
||||
if (id != 0)
|
||||
drawableCoordinates.Add(coords);
|
||||
DrawableCoordinates.Add(coords);
|
||||
if (!provider.Opaque)
|
||||
{
|
||||
// Add adjacent blocks
|
||||
@ -137,14 +141,17 @@ namespace TrueCraft.Client
|
||||
continue;
|
||||
}
|
||||
if (chunk.GetBlockId(next) != 0)
|
||||
drawableCoordinates.Add(next);
|
||||
DrawableCoordinates.Add(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (var coords in drawableCoordinates)
|
||||
var enumerator = DrawableCoordinates.GetEnumerator();
|
||||
for (int j = 0; j < DrawableCoordinates.Count; j++)
|
||||
{
|
||||
var coords = enumerator.Current;
|
||||
enumerator.MoveNext();
|
||||
var descriptor = new BlockDescriptor
|
||||
{
|
||||
ID = chunk.GetBlockId(coords),
|
||||
@ -159,23 +166,23 @@ namespace TrueCraft.Client
|
||||
int[] i;
|
||||
var v = BlockRenderer.RenderBlock(provider, descriptor,
|
||||
new Vector3(chunk.X * Chunk.Width + coords.X, coords.Y, chunk.Z * Chunk.Depth + coords.Z),
|
||||
opaqueVerticies.Count, out i);
|
||||
opaqueVerticies.AddRange(v);
|
||||
opaqueIndicies.AddRange(i);
|
||||
OpaqueVerticies.Count, out i);
|
||||
OpaqueVerticies.AddRange(v);
|
||||
OpaqueIndicies.AddRange(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
int[] i;
|
||||
var v = BlockRenderer.RenderBlock(provider, descriptor,
|
||||
new Vector3(chunk.X * Chunk.Width + coords.X, coords.Y, chunk.Z * Chunk.Depth + coords.Z),
|
||||
transparentVerticies.Count, out i);
|
||||
transparentVerticies.AddRange(v);
|
||||
transparentIndicies.AddRange(i);
|
||||
TransparentVerticies.Count, out i);
|
||||
TransparentVerticies.AddRange(v);
|
||||
TransparentIndicies.AddRange(i);
|
||||
}
|
||||
}
|
||||
var meshes = new Tuple<Mesh, Mesh>(
|
||||
new Mesh(Graphics, opaqueVerticies.ToArray(), opaqueIndicies.ToArray(), false),
|
||||
new Mesh(Graphics, transparentVerticies.ToArray(), transparentIndicies.ToArray(), false));
|
||||
new Mesh(Graphics, OpaqueVerticies.ToArray(), OpaqueIndicies.ToArray(), false),
|
||||
new Mesh(Graphics, TransparentVerticies.ToArray(), TransparentIndicies.ToArray(), false));
|
||||
meshes.Item1.BoundingBox = boundingBox;
|
||||
meshes.Item2.BoundingBox = boundingBox;
|
||||
return meshes;
|
||||
|
@ -4,6 +4,7 @@ using TrueCraft.Core.Networking.Packets;
|
||||
using TrueCraft.Core.Networking;
|
||||
using TrueCraft.Client.Events;
|
||||
using TrueCraft.API;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace TrueCraft.Client.Handlers
|
||||
{
|
||||
@ -29,7 +30,12 @@ namespace TrueCraft.Client.Handlers
|
||||
public static void HandleHandshake(IPacket _packet, MultiplayerClient client)
|
||||
{
|
||||
var packet = (HandshakeResponsePacket)_packet;
|
||||
Console.WriteLine("Got handshake with {0}", packet.ConnectionHash); // TODO: Authenticate?
|
||||
if (packet.ConnectionHash != "-")
|
||||
{
|
||||
Console.WriteLine("Online mode is not supported");
|
||||
Process.GetCurrentProcess().Kill();
|
||||
}
|
||||
// TODO: Authentication
|
||||
client.QueuePacket(new LoginRequestPacket(PacketReader.Version, "TestUser"));
|
||||
}
|
||||
|
||||
@ -44,7 +50,6 @@ namespace TrueCraft.Client.Handlers
|
||||
client._Position = new Vector3(packet.X, packet.Y, packet.Z);
|
||||
client.QueuePacket(packet);
|
||||
client.LoggedIn = true;
|
||||
Console.WriteLine("Got P+L: {0}", client._Position);
|
||||
// TODO: Pitch and yaw
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ namespace TrueCraft.Client.Rendering.Blocks
|
||||
}
|
||||
|
||||
private static Vector2 TextureMap = new Vector2(0, 0);
|
||||
private static Vector2 BottomTexture = new Vector2(2, 0);
|
||||
private static Vector2 EndsTexture = new Vector2(2, 0);
|
||||
private static Vector2 SideTexture = new Vector2(3, 0);
|
||||
private static Vector2[] Texture =
|
||||
{
|
||||
@ -46,10 +46,10 @@ namespace TrueCraft.Client.Rendering.Blocks
|
||||
TextureMap,
|
||||
TextureMap + Vector2.UnitX,
|
||||
// Negative Y
|
||||
BottomTexture + Vector2.UnitX + Vector2.UnitY,
|
||||
BottomTexture + Vector2.UnitY,
|
||||
BottomTexture,
|
||||
BottomTexture + Vector2.UnitX,
|
||||
EndsTexture + Vector2.UnitX + Vector2.UnitY,
|
||||
EndsTexture + Vector2.UnitY,
|
||||
EndsTexture,
|
||||
EndsTexture + Vector2.UnitX,
|
||||
};
|
||||
|
||||
public override VertexPositionNormalTexture[] Render(BlockDescriptor descriptor, Vector3 offset,
|
||||
|
60
TrueCraft.Client/Rendering/Blocks/LogRenderer.cs
Normal file
60
TrueCraft.Client/Rendering/Blocks/LogRenderer.cs
Normal file
@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework;
|
||||
using TrueCraft.Core.Logic.Blocks;
|
||||
using TrueCraft.API.Logic;
|
||||
|
||||
namespace TrueCraft.Client.Rendering.Blocks
|
||||
{
|
||||
public class LogRenderer : BlockRenderer
|
||||
{
|
||||
static LogRenderer()
|
||||
{
|
||||
BlockRenderer.RegisterRenderer(WoodBlock.BlockID, new LogRenderer());
|
||||
for (int i = 0; i < Texture.Length; i++)
|
||||
Texture[i] *= new Vector2(16f / 256f);
|
||||
}
|
||||
|
||||
private static Vector2 EndsTexture = new Vector2(5, 1);
|
||||
private static Vector2 SideTexture = new Vector2(4, 1);
|
||||
private static Vector2[] Texture =
|
||||
{
|
||||
// Positive Z
|
||||
SideTexture + Vector2.UnitX + Vector2.UnitY,
|
||||
SideTexture + Vector2.UnitY,
|
||||
SideTexture,
|
||||
SideTexture + Vector2.UnitX,
|
||||
// Negative Z
|
||||
SideTexture + Vector2.UnitX + Vector2.UnitY,
|
||||
SideTexture + Vector2.UnitY,
|
||||
SideTexture,
|
||||
SideTexture + Vector2.UnitX,
|
||||
// Positive X
|
||||
SideTexture + Vector2.UnitX + Vector2.UnitY,
|
||||
SideTexture + Vector2.UnitY,
|
||||
SideTexture,
|
||||
SideTexture + Vector2.UnitX,
|
||||
// Negative X
|
||||
SideTexture + Vector2.UnitX + Vector2.UnitY,
|
||||
SideTexture + Vector2.UnitY,
|
||||
SideTexture,
|
||||
SideTexture + Vector2.UnitX,
|
||||
// Positive Y
|
||||
EndsTexture + Vector2.UnitX + Vector2.UnitY,
|
||||
EndsTexture + Vector2.UnitY,
|
||||
EndsTexture,
|
||||
EndsTexture + Vector2.UnitX,
|
||||
// Negative Y
|
||||
EndsTexture + Vector2.UnitX + Vector2.UnitY,
|
||||
EndsTexture + Vector2.UnitY,
|
||||
EndsTexture,
|
||||
EndsTexture + Vector2.UnitX,
|
||||
};
|
||||
|
||||
public override VertexPositionNormalTexture[] Render(BlockDescriptor descriptor, Vector3 offset,
|
||||
Tuple<int, int> textureMap, int indiciesOffset, out int[] indicies)
|
||||
{
|
||||
return CreateUniformCube(offset, Texture, indiciesOffset, out indicies);
|
||||
}
|
||||
}
|
||||
}
|
@ -15,7 +15,7 @@ namespace TrueCraft.Client.Rendering
|
||||
|
||||
public Mesh(GraphicsDevice device, VertexPositionNormalTexture[] verticies, int[] indicies, bool calculateBounds = true)
|
||||
{
|
||||
Empty = verticies.Length == 0 || indicies.Length == 0;
|
||||
Empty = verticies.Length == 0 && indicies.Length == 0;
|
||||
if (!Empty)
|
||||
{
|
||||
Verticies = new VertexBuffer(device, VertexPositionNormalTexture.VertexDeclaration,
|
||||
|
@ -87,6 +87,7 @@
|
||||
<Compile Include="Rendering\Blocks\TNTRenderer.cs" />
|
||||
<Compile Include="Rendering\Blocks\SnowRenderer.cs" />
|
||||
<Compile Include="Rendering\Blocks\TorchRenderer.cs" />
|
||||
<Compile Include="Rendering\Blocks\LogRenderer.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<ItemGroup>
|
||||
|
@ -12,6 +12,7 @@ using System.Linq;
|
||||
using System.ComponentModel;
|
||||
using TrueCraft.Core.Networking.Packets;
|
||||
using TrueCraft.API.World;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace TrueCraft.Client
|
||||
{
|
||||
@ -26,8 +27,10 @@ namespace TrueCraft.Client
|
||||
private ChunkConverter ChunkConverter { get; set; }
|
||||
private DateTime NextPhysicsUpdate { get; set; }
|
||||
private List<Mesh> ChunkMeshes { get; set; }
|
||||
private ConcurrentBag<Action> PendingMainThreadActions { get; set; }
|
||||
private ConcurrentBag<Mesh> IncomingChunks { get; set; }
|
||||
private ConcurrentBag<Mesh> IncomingTransparentChunks { get; set; }
|
||||
private List<Mesh> TransparentChunkMeshes { get; set; }
|
||||
private readonly object ChunkMeshesLock = new object();
|
||||
private Matrix Camera;
|
||||
private Matrix Perspective;
|
||||
private BoundingFrustum CameraView;
|
||||
@ -49,6 +52,9 @@ namespace TrueCraft.Client
|
||||
NextPhysicsUpdate = DateTime.MinValue;
|
||||
ChunkMeshes = new List<Mesh>();
|
||||
TransparentChunkMeshes = new List<Mesh>();
|
||||
IncomingChunks = new ConcurrentBag<Mesh>();
|
||||
IncomingTransparentChunks = new ConcurrentBag<Mesh>();
|
||||
PendingMainThreadActions = new ConcurrentBag<Action>();
|
||||
MouseCaptured = true;
|
||||
}
|
||||
|
||||
@ -61,11 +67,8 @@ namespace TrueCraft.Client
|
||||
Client.ChunkLoaded += (sender, e) => ChunkConverter.QueueChunk(e.Chunk);
|
||||
ChunkConverter.Start((opaque, transparent) =>
|
||||
{
|
||||
lock (ChunkMeshesLock)
|
||||
{
|
||||
ChunkMeshes.Add(opaque);
|
||||
TransparentChunkMeshes.Add(transparent);
|
||||
}
|
||||
IncomingChunks.Add(opaque);
|
||||
IncomingTransparentChunks.Add(transparent);
|
||||
});
|
||||
Client.PropertyChanged += HandleClientPropertyChanged;
|
||||
Client.Connect(EndPoint);
|
||||
@ -84,8 +87,7 @@ namespace TrueCraft.Client
|
||||
UpdateMatricies();
|
||||
var sorter = new ChunkConverter.ChunkSorter(new Coordinates3D(
|
||||
(int)Client.Position.X, 0, (int)Client.Position.Z));
|
||||
lock (ChunkMeshesLock)
|
||||
TransparentChunkMeshes.Sort(sorter);
|
||||
PendingMainThreadActions.Add(() => TransparentChunkMeshes.Sort(sorter));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -128,9 +130,12 @@ namespace TrueCraft.Client
|
||||
{
|
||||
if (state.IsKeyDown(Keys.Escape))
|
||||
Exit();
|
||||
|
||||
// TODO: Rebindable keys
|
||||
// TODO: Horizontal terrain collisions
|
||||
|
||||
Microsoft.Xna.Framework.Vector3 delta = Microsoft.Xna.Framework.Vector3.Zero;
|
||||
|
||||
if (state.IsKeyDown(Keys.Left) || state.IsKeyDown(Keys.A))
|
||||
delta += Microsoft.Xna.Framework.Vector3.Left;
|
||||
if (state.IsKeyDown(Keys.Right) || state.IsKeyDown(Keys.D))
|
||||
@ -140,14 +145,16 @@ namespace TrueCraft.Client
|
||||
if (state.IsKeyDown(Keys.Down) || state.IsKeyDown(Keys.S))
|
||||
delta += Microsoft.Xna.Framework.Vector3.Backward;
|
||||
|
||||
if (state.IsKeyUp(Keys.Tab) && oldState.IsKeyDown(Keys.Tab))
|
||||
MouseCaptured = !MouseCaptured;
|
||||
|
||||
if (delta != Microsoft.Xna.Framework.Vector3.Zero)
|
||||
{
|
||||
var lookAt = Microsoft.Xna.Framework.Vector3.Transform(
|
||||
delta, Matrix.CreateRotationY(MathHelper.ToRadians(Client.Yaw)));
|
||||
|
||||
Client.Position += new TrueCraft.API.Vector3(lookAt.X, lookAt.Y, lookAt.Z) * (gameTime.ElapsedGameTime.TotalSeconds * 4.3717);
|
||||
}
|
||||
|
||||
if (state.IsKeyUp(Keys.Tab) && oldState.IsKeyDown(Keys.Tab))
|
||||
MouseCaptured = !MouseCaptured;
|
||||
if (MouseCaptured)
|
||||
{
|
||||
var centerX = GraphicsDevice.Viewport.Width / 2;
|
||||
@ -172,25 +179,31 @@ namespace TrueCraft.Client
|
||||
{
|
||||
i.Update(gameTime);
|
||||
}
|
||||
if (NextPhysicsUpdate < DateTime.Now)
|
||||
|
||||
Mesh mesh;
|
||||
if (IncomingChunks.TryTake(out mesh))
|
||||
ChunkMeshes.Add(mesh);
|
||||
if (IncomingTransparentChunks.TryTake(out mesh))
|
||||
TransparentChunkMeshes.Add(mesh);
|
||||
Action action;
|
||||
if (PendingMainThreadActions.TryTake(out action))
|
||||
action();
|
||||
|
||||
if (NextPhysicsUpdate < DateTime.Now && Client.LoggedIn)
|
||||
{
|
||||
IChunk chunk;
|
||||
var adjusted = Client.World.World.FindBlockPosition(new Coordinates3D((int)Client.Position.X, 0, (int)Client.Position.Z), out chunk);
|
||||
if (Client.LoggedIn && chunk != null)
|
||||
if (chunk != null)
|
||||
{
|
||||
if (chunk.GetHeight((byte)adjusted.X, (byte)adjusted.Z) != 0)
|
||||
Client.Physics.Update();
|
||||
}
|
||||
if (Client.LoggedIn)
|
||||
{
|
||||
// NOTE: This is to make the vanilla server send us chunk packets
|
||||
// We should eventually make some means of detecing that we're on a vanilla server to enable this
|
||||
// It's a waste of bandwidth to do it on a TrueCraft server
|
||||
Console.WriteLine("Sending position packet");
|
||||
Client.QueuePacket(new PlayerGroundedPacket { OnGround = true });
|
||||
Client.QueuePacket(new PlayerPositionAndLookPacket(Client.Position.X, Client.Position.Y,
|
||||
Client.Position.Y + MultiplayerClient.Height, Client.Position.Z, Client.Yaw, Client.Pitch, false));
|
||||
}
|
||||
NextPhysicsUpdate = DateTime.Now.AddMilliseconds(1000 / 20);
|
||||
}
|
||||
var state = Keyboard.GetState();
|
||||
@ -217,6 +230,10 @@ namespace TrueCraft.Client
|
||||
Perspective = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(70f), GraphicsDevice.Viewport.AspectRatio, 0.01f, 1000f);
|
||||
|
||||
CameraView = new BoundingFrustum(Camera * Perspective);
|
||||
|
||||
OpaqueEffect.View = TransparentEffect.View = Camera;
|
||||
OpaqueEffect.Projection = TransparentEffect.Projection = Perspective;
|
||||
OpaqueEffect.World = TransparentEffect.World = Matrix.Identity;
|
||||
}
|
||||
|
||||
protected override void Draw(GameTime gameTime)
|
||||
@ -226,45 +243,40 @@ namespace TrueCraft.Client
|
||||
GraphicsDevice.SamplerStates[1] = SamplerState.PointClamp;
|
||||
GraphicsDevice.BlendState = BlendState.AlphaBlend;
|
||||
|
||||
OpaqueEffect.View = TransparentEffect.View = Camera;
|
||||
OpaqueEffect.Projection = TransparentEffect.Projection = Perspective;
|
||||
OpaqueEffect.World = TransparentEffect.World = Matrix.Identity;
|
||||
int verticies = 0, chunks = 0;
|
||||
lock (ChunkMeshesLock)
|
||||
{
|
||||
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
|
||||
foreach (var chunk in ChunkMeshes)
|
||||
for (int i = 0; i < ChunkMeshes.Count; i++)
|
||||
{
|
||||
if (CameraView.Intersects(chunk.BoundingBox))
|
||||
if (CameraView.Intersects(ChunkMeshes[i].BoundingBox))
|
||||
{
|
||||
verticies += chunk.Verticies.VertexCount;
|
||||
verticies += ChunkMeshes[i].Verticies.VertexCount;
|
||||
chunks++;
|
||||
chunk.Draw(OpaqueEffect);
|
||||
ChunkMeshes[i].Draw(OpaqueEffect);
|
||||
}
|
||||
}
|
||||
GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
|
||||
foreach (var chunk in TransparentChunkMeshes)
|
||||
for (int i = 0; i < TransparentChunkMeshes.Count; i++)
|
||||
{
|
||||
if (CameraView.Intersects(chunk.BoundingBox))
|
||||
if (CameraView.Intersects(TransparentChunkMeshes[i].BoundingBox))
|
||||
{
|
||||
if (chunk.Verticies != null)
|
||||
verticies += chunk.Verticies.VertexCount;
|
||||
chunk.Draw(TransparentEffect);
|
||||
}
|
||||
if (TransparentChunkMeshes[i].Verticies != null)
|
||||
verticies += TransparentChunkMeshes[i].Verticies.VertexCount;
|
||||
TransparentChunkMeshes[i].Draw(TransparentEffect);
|
||||
}
|
||||
}
|
||||
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
|
||||
|
||||
SpriteBatch.Begin();
|
||||
foreach (var i in Interfaces)
|
||||
for (int i = 0; i < Interfaces.Count; i++)
|
||||
{
|
||||
i.DrawSprites(gameTime, SpriteBatch);
|
||||
Interfaces[i].DrawSprites(gameTime, SpriteBatch);
|
||||
}
|
||||
|
||||
int fps = (int)(1 / gameTime.ElapsedGameTime.TotalSeconds);
|
||||
DejaVu.DrawText(SpriteBatch, 0, GraphicsDevice.Viewport.Height - 30,
|
||||
string.Format("{0} FPS, {1} verticies, {2} chunks", fps + 1, verticies, chunks));
|
||||
SpriteBatch.End();
|
||||
|
||||
base.Draw(gameTime);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user