diff --git a/TrueCraft.Client/Modules/ChunkModule.cs b/TrueCraft.Client/Modules/ChunkModule.cs index dc45869..05a9110 100644 --- a/TrueCraft.Client/Modules/ChunkModule.cs +++ b/TrueCraft.Client/Modules/ChunkModule.cs @@ -66,7 +66,7 @@ namespace TrueCraft.Client.Modules void UnloadChunk(ReadOnlyChunk chunk) { - Game.PendingMainThreadActions.Add(() => + Game.Invoke(() => { ActiveMeshes.Remove(chunk.Coordinates); ChunkMeshes.RemoveAll(m => m.Chunk.Coordinates == chunk.Coordinates); @@ -80,7 +80,7 @@ namespace TrueCraft.Client.Modules 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)); + Game.Invoke(() => ChunkMeshes.Sort(sorter)); break; } } diff --git a/TrueCraft.Client/Modules/HighlightModule.cs b/TrueCraft.Client/Modules/HighlightModule.cs index 248b10d..5934d85 100644 --- a/TrueCraft.Client/Modules/HighlightModule.cs +++ b/TrueCraft.Client/Modules/HighlightModule.cs @@ -6,6 +6,7 @@ using Microsoft.Xna.Framework; using XVector3 = Microsoft.Xna.Framework.Vector3; using TVector3 = TrueCraft.API.Vector3; using TRay = TrueCraft.API.Ray; +using TrueCraft.Core.Logic.Blocks; namespace TrueCraft.Client.Modules { @@ -14,8 +15,13 @@ namespace TrueCraft.Client.Modules public TrueCraftGame Game { get; set; } private BasicEffect HighlightEffect { get; set; } + private AlphaTestEffect DestructionEffect { get; set; } + private Mesh ProgressMesh { get; set; } + private int Progress { get; set; } + private static readonly RasterizerState RasterizerState; private static readonly VertexPositionColor[] CubeVerticies; private static readonly short[] CubeIndicies; + private static readonly BlendState DestructionBlendState; static HighlightModule() { @@ -37,6 +43,18 @@ namespace TrueCraft.Client.Modules 0, 4, 4, 7, 7, 6, 6, 2, 1, 5, 5, 4, 3, 7, 6, 5 }; + DestructionBlendState = new BlendState + { + ColorSourceBlend = Blend.DestinationColor, + ColorDestinationBlend = Blend.SourceColor, + AlphaSourceBlend = Blend.DestinationAlpha, + AlphaDestinationBlend = Blend.SourceAlpha + }; + RasterizerState = new RasterizerState + { + DepthBias = -3, + SlopeScaleDepthBias = -3 + }; } public HighlightModule(TrueCraftGame game) @@ -44,6 +62,29 @@ namespace TrueCraft.Client.Modules Game = game; HighlightEffect = new BasicEffect(Game.GraphicsDevice); HighlightEffect.VertexColorEnabled = true; + DestructionEffect = new AlphaTestEffect(Game.GraphicsDevice); + DestructionEffect.Texture = game.TextureMapper.GetTexture("terrain.png"); + DestructionEffect.ReferenceAlpha = 1; + + GenerateProgressMesh(); + } + + private void GenerateProgressMesh() + { + int[] indicies; + var texCoords = new Vector2(Progress, 15); + var texture = new[] + { + texCoords + Vector2.UnitX + Vector2.UnitY, + texCoords + Vector2.UnitY, + texCoords, + texCoords + Vector2.UnitX + }; + for (int i = 0; i < texture.Length; i++) + texture[i] *= new Vector2(16f / 256f); + var verticies = BlockRenderer.CreateUniformCube(XVector3.Zero, + texture, VisibleFaces.All, 0, out indicies, Color.White); + ProgressMesh = new Mesh(Game, verticies, indicies); } public void Update(GameTime gameTime) @@ -62,10 +103,7 @@ namespace TrueCraft.Client.Modules { Game.HighlightedBlock = cast.Item1; Game.HighlightedBlockFace = cast.Item2; - HighlightEffect.World = - Matrix.CreateTranslation(new XVector3(-0.5f)) * - Matrix.CreateScale(1.01f) * - Matrix.CreateTranslation(new XVector3(0.5f)) * + HighlightEffect.World = DestructionEffect.World = Matrix.CreateTranslation(new XVector3(cast.Item1.X, cast.Item1.Y, cast.Item1.Z)); } } @@ -73,9 +111,11 @@ namespace TrueCraft.Client.Modules public void Draw(GameTime gameTime) { Game.Camera.ApplyTo(HighlightEffect); + Game.Camera.ApplyTo(DestructionEffect); if (Game.HighlightedBlock != -Coordinates3D.One) { + Game.GraphicsDevice.RasterizerState = RasterizerState; foreach (var pass in HighlightEffect.CurrentTechnique.Passes) { pass.Apply(); @@ -84,6 +124,26 @@ namespace TrueCraft.Client.Modules CubeVerticies.Length, CubeIndicies, 0, CubeIndicies.Length / 2); } } + if (Game.EndDigging != DateTime.MaxValue) + { + var diff = Game.EndDigging - DateTime.UtcNow; + var total = Game.EndDigging - Game.StartDigging; + var progress = (int)(diff.TotalMilliseconds / total.TotalMilliseconds * 10); + progress = -(progress - 5) + 5; + if (progress > 9) + progress = 9; + + if (progress != Progress) + { + Progress = progress; + GenerateProgressMesh(); + } + + Game.GraphicsDevice.BlendState = DestructionBlendState; + ProgressMesh.Draw(DestructionEffect); + Game.GraphicsDevice.BlendState = BlendState.AlphaBlend; + Game.GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise; + } } } } diff --git a/TrueCraft.Client/Modules/PlayerControlModule.cs b/TrueCraft.Client/Modules/PlayerControlModule.cs index 9d6f783..5588bae 100644 --- a/TrueCraft.Client/Modules/PlayerControlModule.cs +++ b/TrueCraft.Client/Modules/PlayerControlModule.cs @@ -14,10 +14,7 @@ namespace TrueCraft.Client.Modules public class PlayerControlModule : IInputModule { private TrueCraftGame Game { get; set; } - private DateTime StartDigging { get; set; } private DateTime NextAnimation { get; set; } - private DateTime EndDigging { get; set; } - private Coordinates3D TargetBlock { get; set; } private XVector3 Delta { get; set; } private bool Capture { get; set; } @@ -25,9 +22,9 @@ namespace TrueCraft.Client.Modules { Game = game; Capture = true; - StartDigging = DateTime.MinValue; - EndDigging = DateTime.MaxValue; - TargetBlock = -Coordinates3D.One; + Game.StartDigging = DateTime.MinValue; + Game.EndDigging = DateTime.MaxValue; + Game.TargetBlock = -Coordinates3D.One; NextAnimation = DateTime.MaxValue; } @@ -138,7 +135,7 @@ namespace TrueCraft.Client.Modules switch (e.Button) { case MouseButton.Left: - if (StartDigging == DateTime.MinValue) // Would like to start digging a block + if (Game.StartDigging == DateTime.MinValue) // Would like to start digging a block { var target = Game.HighlightedBlock; if (target != -Coordinates3D.One) @@ -149,11 +146,11 @@ namespace TrueCraft.Client.Modules var target = Game.HighlightedBlock; if (target == -Coordinates3D.One) // Cancel { - StartDigging = DateTime.MinValue; - EndDigging = DateTime.MaxValue; - TargetBlock = -Coordinates3D.One; + Game.StartDigging = DateTime.MinValue; + Game.EndDigging = DateTime.MaxValue; + Game.TargetBlock = -Coordinates3D.One; } - else if (target != TargetBlock) // Change target + else if (target != Game.TargetBlock) // Change target BeginDigging(target); } return true; @@ -163,15 +160,16 @@ namespace TrueCraft.Client.Modules private void BeginDigging(Coordinates3D target) { + // TODO: Adjust digging time to compensate for latency var block = Game.Client.World.GetBlockID(target); - TargetBlock = target; - StartDigging = DateTime.UtcNow; + Game.TargetBlock = target; + Game.StartDigging = DateTime.UtcNow; short damage; - EndDigging = StartDigging.AddMilliseconds( + Game.EndDigging = Game.StartDigging.AddMilliseconds( BlockProvider.GetHarvestTime(block, 0, out damage)); Game.Client.QueuePacket(new PlayerDiggingPacket( PlayerDiggingPacket.Action.StartDigging, - TargetBlock.X, (sbyte)TargetBlock.Y, TargetBlock.Z, + Game.TargetBlock.X, (sbyte)Game.TargetBlock.Y, Game.TargetBlock.Z, Game.HighlightedBlockFace)); NextAnimation = DateTime.UtcNow.AddSeconds(0.25); } @@ -181,9 +179,9 @@ namespace TrueCraft.Client.Modules switch (e.Button) { case MouseButton.Left: - StartDigging = DateTime.MinValue; - EndDigging = DateTime.MaxValue; - TargetBlock = -Coordinates3D.One; + Game.StartDigging = DateTime.MinValue; + Game.EndDigging = DateTime.MaxValue; + Game.TargetBlock = -Coordinates3D.One; return true; } return false; @@ -205,7 +203,7 @@ namespace TrueCraft.Client.Modules } else Game.Client.Velocity *= new TVector3(0, 1, 0); - if (EndDigging != DateTime.MaxValue) + if (Game.EndDigging != DateTime.MaxValue) { if (NextAnimation < DateTime.UtcNow) { @@ -213,12 +211,13 @@ namespace TrueCraft.Client.Modules Game.Client.QueuePacket(new AnimationPacket(Game.Client.EntityID, AnimationPacket.PlayerAnimation.SwingArm)); } - if (DateTime.UtcNow > EndDigging && Game.HighlightedBlock == TargetBlock) + if (DateTime.UtcNow > Game.EndDigging && Game.HighlightedBlock == Game.TargetBlock) { Game.Client.QueuePacket(new PlayerDiggingPacket( PlayerDiggingPacket.Action.StopDigging, - TargetBlock.X, (sbyte)TargetBlock.Y, TargetBlock.Z, + Game.TargetBlock.X, (sbyte)Game.TargetBlock.Y, Game.TargetBlock.Z, Game.HighlightedBlockFace)); + Game.EndDigging = DateTime.MaxValue; } } } diff --git a/TrueCraft.Client/Rendering/Mesh.cs b/TrueCraft.Client/Rendering/Mesh.cs index 89a7546..da276fb 100644 --- a/TrueCraft.Client/Rendering/Mesh.cs +++ b/TrueCraft.Client/Rendering/Mesh.cs @@ -47,7 +47,7 @@ namespace TrueCraft.Client.Rendering if (_vertices != null) _vertices.Dispose(); - _game.PendingMainThreadActions.Add(() => + _game.Invoke(() => { _vertices = new VertexBuffer(_graphicsDevice, VertexPositionNormalColorTexture.VertexDeclaration, (value.Length + 1), BufferUsage.WriteOnly); @@ -132,7 +132,7 @@ namespace TrueCraft.Client.Rendering if (_indices[index] != null) _indices[index].Dispose(); - _game.PendingMainThreadActions.Add(() => + _game.Invoke(() => { _indices[index] = new IndexBuffer(_graphicsDevice, typeof(int), (indices.Length + 1), BufferUsage.WriteOnly); diff --git a/TrueCraft.Client/TrueCraftGame.cs b/TrueCraft.Client/TrueCraftGame.cs index 98d7097..df874b7 100644 --- a/TrueCraft.Client/TrueCraftGame.cs +++ b/TrueCraft.Client/TrueCraftGame.cs @@ -19,6 +19,7 @@ using TrueCraft.Client.Rendering; using TVector3 = TrueCraft.API.Vector3; using XVector3 = Microsoft.Xna.Framework.Vector3; using TrueCraft.Core.Logic; +using System.Threading; namespace TrueCraft.Client { @@ -34,12 +35,16 @@ namespace TrueCraft.Client public float ScaleFactor { get; set; } public Coordinates3D HighlightedBlock { get; set; } public BlockFace HighlightedBlockFace { get; set; } + public DateTime StartDigging { get; set; } + public DateTime EndDigging { get; set; } + public Coordinates3D TargetBlock { get; set; } private List Modules { get; set; } private SpriteBatch SpriteBatch { get; set; } private KeyboardHandler KeyboardComponent { get; set; } private MouseHandler MouseComponent { get; set; } private RenderTarget2D RenderTarget { get; set; } + private int ThreadID { get; set; } private FontRenderer Pixel { get; set; } private IPEndPoint EndPoint { get; set; } @@ -139,6 +144,15 @@ namespace TrueCraft.Client SpriteBatch = new SpriteBatch(GraphicsDevice); Window_ClientSizeChanged(null, null); + ThreadID = Thread.CurrentThread.ManagedThreadId; + } + + public void Invoke(Action action) + { + if (ThreadID == Thread.CurrentThread.ManagedThreadId) + action(); + else + PendingMainThreadActions.Add(action); } private void CreateRenderTarget()