From fa358f9ad20fcc458404d78ee0de0e545d45e2f4 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Thu, 17 Dec 2015 18:35:05 +1100 Subject: [PATCH] Add rain particles, use particle pooling. --- ClassicalSharp/ClassicalSharp.csproj | 2 +- ClassicalSharp/Map/Map.cs | 2 +- ClassicalSharp/Network/NetworkProcessor.cs | 8 +- ClassicalSharp/Network/Utils/NetWriter.cs | 4 +- .../Particles/CollidableParticle.cs | 31 ++++--- ClassicalSharp/Particles/Particle.cs | 7 +- ClassicalSharp/Particles/ParticleManager.cs | 80 +++++++++++++------ ClassicalSharp/Particles/RainParticle.cs | 17 +++- ClassicalSharp/Particles/TerrainParticle.cs | 10 ++- ClassicalSharp/Rendering/WeatherRenderer.cs | 15 ++-- ClassicalSharp/Singleplayer/Server.cs | 2 +- ClassicalSharp/Utils/Vector3I.cs | 8 +- 12 files changed, 115 insertions(+), 71 deletions(-) diff --git a/ClassicalSharp/ClassicalSharp.csproj b/ClassicalSharp/ClassicalSharp.csproj index 124d08550..52c5cb0ce 100644 --- a/ClassicalSharp/ClassicalSharp.csproj +++ b/ClassicalSharp/ClassicalSharp.csproj @@ -35,7 +35,7 @@ DEBUG;TRACE; Project obj\ - wwwf mppass 127.0.0.1 25565 + wwwf sdf 127.0.0.1 25565 ..\output\release\ diff --git a/ClassicalSharp/Map/Map.cs b/ClassicalSharp/Map/Map.cs index fe523c911..30c97b18d 100644 --- a/ClassicalSharp/Map/Map.cs +++ b/ClassicalSharp/Map/Map.cs @@ -279,7 +279,7 @@ namespace ClassicalSharp { /// Unpacks the given index into the map's block array into its original world coordinates. public Vector3I GetCoords( int index ) { if( index < 0 || index >= mapData.Length ) - return new Vector3I( -1, -1, -1 ); + return new Vector3I( -1 ); int x = index % Width; int y = index / oneY; // index / (width * length) int z = (index / Width) % Length; diff --git a/ClassicalSharp/Network/NetworkProcessor.cs b/ClassicalSharp/Network/NetworkProcessor.cs index 6ded88d4f..de6613754 100644 --- a/ClassicalSharp/Network/NetworkProcessor.cs +++ b/ClassicalSharp/Network/NetworkProcessor.cs @@ -148,6 +148,10 @@ namespace ClassicalSharp { NetWriter writer; void SendPacket() { + if( Disconnected ) { + writer.index = 0; + return; + } try { writer.Send( Disconnected ); } catch( IOException ex ) { @@ -163,9 +167,9 @@ namespace ClassicalSharp { void ReadPacket( byte opcode ) { reader.Remove( 1 ); // remove opcode lastOpcode = (PacketId)opcode; - Action handler; + Action handler = handlers[opcode]; - if( opcode >= maxHandledPacket || (handler = handlers[opcode]) == null) + if( handler == null ) throw new NotImplementedException( "Unsupported packet:" + (PacketId)opcode ); handler(); } diff --git a/ClassicalSharp/Network/Utils/NetWriter.cs b/ClassicalSharp/Network/Utils/NetWriter.cs index 4639bbbcf..8b33d00fb 100644 --- a/ClassicalSharp/Network/Utils/NetWriter.cs +++ b/ClassicalSharp/Network/Utils/NetWriter.cs @@ -53,10 +53,8 @@ namespace ClassicalSharp { } public void Send( bool disconnected ) { - int packetLength = index; + Stream.Write( buffer, 0, index ); index = 0; - if( !disconnected ) - Stream.Write( buffer, 0, packetLength ); } } } \ No newline at end of file diff --git a/ClassicalSharp/Particles/CollidableParticle.cs b/ClassicalSharp/Particles/CollidableParticle.cs index de9d4c143..49aa0e3fa 100644 --- a/ClassicalSharp/Particles/CollidableParticle.cs +++ b/ClassicalSharp/Particles/CollidableParticle.cs @@ -5,17 +5,22 @@ namespace ClassicalSharp.Particles { public abstract class CollidableParticle : Particle { - const float gravity = 3.4f; - //const float gravity = 0.7f; // TODO: temp debug + protected bool hitTerrain = false; + public CollidableParticle( Game game ) : base( game) { } - public CollidableParticle( Game game, Vector3 pos, Vector3 velocity, double lifetime ) - : base( game, pos, velocity, lifetime ) { + public void ResetState( Vector3 pos, Vector3 velocity, double lifetime ) { + Position = lastPos = nextPos = pos; + Velocity = velocity; + Lifetime = (float)lifetime; + hitTerrain = false; } - public override bool Tick( double delta ) { + protected bool Tick( float gravity, double delta ) { + hitTerrain = false; lastPos = Position = nextPos; byte curBlock = game.Map.SafeGetBlock( (int)Position.X, (int)Position.Y, (int)Position.Z ); - if( !CanPassThrough( curBlock ) ) return true; + float blockY = (int)Position.Y + game.BlockInfo.Height[curBlock]; + if( !CanPassThrough( curBlock ) && Position.Y < blockY ) return true; Velocity.Y -= gravity * (float)delta; int startY = (int)Math.Floor( Position.Y ); @@ -25,34 +30,34 @@ namespace ClassicalSharp.Particles { Utils.Clamp( ref Position.Z, 0, game.Map.Length - 0.01f ); if( Velocity.Y > 0 ) { - for( int y = startY; y <= endY && TestY( y, false ); y++ ); + // don't test block we are already in + for( int y = startY + 1; y <= endY && TestY( y, false ); y++ ); } else { for( int y = startY; y >= endY && TestY( y, true ); y-- ); } nextPos = Position; Position = lastPos; return base.Tick( delta ); - } + } bool TestY( int y, bool topFace ) { if( y < 0 ) { Position.Y = nextPos.Y = lastPos.Y = 0 + Entity.Adjustment; Velocity = Vector3.Zero; + hitTerrain = true; return false; } byte block = game.Map.SafeGetBlock( (int)Position.X, y, (int)Position.Z ); if( CanPassThrough( block ) ) return true; - float collideY = y; - if( topFace ) - collideY += game.BlockInfo.Height[block]; - - bool collide = topFace ? (Position.Y < collideY) : (Position.Y > collideY ); + float collideY = y + (topFace ? game.BlockInfo.Height[block] : 0); + bool collide = topFace ? (Position.Y < collideY) : (Position.Y > collideY); if( collide ) { float adjust = topFace ? Entity.Adjustment : -Entity.Adjustment; Position.Y = nextPos.Y = lastPos.Y = collideY + adjust; Velocity = Vector3.Zero; + hitTerrain = true; return false; } return true; diff --git a/ClassicalSharp/Particles/Particle.cs b/ClassicalSharp/Particles/Particle.cs index 6ff57d9f9..d47021963 100644 --- a/ClassicalSharp/Particles/Particle.cs +++ b/ClassicalSharp/Particles/Particle.cs @@ -13,12 +13,7 @@ namespace ClassicalSharp.Particles { public abstract void Render( double delta, float t, VertexPos3fTex2fCol4b[] vertices, ref int index ); - public Particle( Game game, Vector3 pos, Vector3 velocity, double lifetime ) { - this.game = game; - Position = lastPos = nextPos = pos; - Velocity = velocity; - Lifetime = (float)lifetime; - } + public Particle( Game game ) { this.game = game; } public virtual bool Tick( double delta ) { Lifetime -= (float)delta; diff --git a/ClassicalSharp/Particles/ParticleManager.cs b/ClassicalSharp/Particles/ParticleManager.cs index 115206830..326c3c1a0 100644 --- a/ClassicalSharp/Particles/ParticleManager.cs +++ b/ClassicalSharp/Particles/ParticleManager.cs @@ -8,32 +8,35 @@ namespace ClassicalSharp.Particles { public class ParticleManager : IDisposable { public int ParticlesTexId; - List terrainParticles = new List(); - List rainParticles = new List(); + TerrainParticle[] terrainParticles = new TerrainParticle[maxParticles]; + RainParticle[] rainParticles = new RainParticle[maxParticles]; + int terrainCount, rainCount; + Game game; Random rnd; int vb; + const int maxParticles = 600; public ParticleManager( Game game ) { this.game = game; rnd = new Random(); - vb = game.Graphics.CreateDynamicVb( VertexFormat.Pos3fTex2fCol4b, 1000 ); + vb = game.Graphics.CreateDynamicVb( VertexFormat.Pos3fTex2fCol4b, maxParticles * 4 ); } VertexPos3fTex2fCol4b[] vertices = new VertexPos3fTex2fCol4b[0]; public void Render( double delta, float t ) { - if( terrainParticles.Count == 0 && rainParticles.Count == 0 ) return; + if( terrainCount == 0 && rainCount == 0 ) return; IGraphicsApi graphics = game.Graphics; graphics.Texturing = true; graphics.AlphaTest = true; graphics.SetBatchFormat( VertexFormat.Pos3fTex2fCol4b ); - int count = RenderParticles( terrainParticles, delta, t ); + int count = RenderParticles( terrainParticles, terrainCount, delta, t ); if( count > 0 ) { graphics.BindTexture( game.TerrainAtlas.TexId ); graphics.UpdateDynamicIndexedVb( DrawMode.Triangles, vb, vertices, count, count * 6 / 4 ); } - count = RenderParticles( rainParticles, delta, t ); + count = RenderParticles( rainParticles, rainCount, delta, t ); if( count > 0 ) { graphics.BindTexture( ParticlesTexId ); graphics.UpdateDynamicIndexedVb( DrawMode.Triangles, vb, vertices, count, count * 6 / 4 ); @@ -43,27 +46,27 @@ namespace ClassicalSharp.Particles { graphics.Texturing = false; } - int RenderParticles( List particles, double delta, float t ) { - int count = particles.Count * 4; + int RenderParticles( Particle[] particles, int elems, double delta, float t ) { + int count = elems * 4; if( count > vertices.Length ) vertices = new VertexPos3fTex2fCol4b[count]; int index = 0; - for( int i = 0; i < particles.Count; i++ ) - particles[i].Render( delta, t, vertices, ref index ); - return Math.Min( count, 1000 ); + for( int i = 0; i < elems; i++ ) + particles[i].Render( delta, t, vertices, ref index ); + return Math.Min( count, maxParticles * 4 ); } public void Tick( double delta ) { - TickParticles( terrainParticles, delta ); - TickParticles( rainParticles, delta ); + TickParticles( terrainParticles, ref terrainCount, delta ); + TickParticles( rainParticles, ref rainCount, delta ); } - void TickParticles( List particles, double delta ) { - for( int i = 0; i < particles.Count; i++ ) { + void TickParticles( Particle[] particles, ref int count, double delta ) { + for( int i = 0; i < count; i++ ) { Particle particle = particles[i]; if( particle.Tick( delta ) ) { - particles.RemoveAt( i ); + RemoveAt( i, particles, ref count ); i--; } } @@ -103,27 +106,56 @@ namespace ClassicalSharp.Particles { particleRec.V2 = particleRec.V1 + elemSize; double life = 1.5 - rnd.NextDouble(); - terrainParticles.Add( new TerrainParticle( game, pos, velocity, life, particleRec ) ); + TerrainParticle p = AddParticle( terrainParticles, ref terrainCount, false ); + p.ResetState( pos, velocity, life ); + p.rec = particleRec; } } public void AddRainParticle( Vector3 pos ) { - Vector3 startPos = pos; - - for( int i = 0; i < 5; i++ ) { + Vector3 startPos = pos; + for( int i = 0; i < 2; i++ ) { double velX = rnd.NextDouble() * 0.8 - 0.4; // [-0.4, 0.4] double velZ = rnd.NextDouble() * 0.8 - 0.4; - double velY = rnd.NextDouble() + 0.5; + double velY = rnd.NextDouble() + 0.4; Vector3 velocity = new Vector3( (float)velX, (float)velY, (float)velZ ); double xOffset = rnd.NextDouble() - 0.5; // [-0.5, 0.5] - double yOffset = 0.01; + double yOffset = rnd.NextDouble() * 0.1 + 0.01; double zOffset = rnd.NextDouble() - 0.5; pos = startPos + new Vector3( 0.5f + (float)xOffset, (float)yOffset, 0.5f + (float)zOffset ); - double life = 3.5 - rnd.NextDouble(); - rainParticles.Add( new RainParticle( game, pos, velocity, life ) ); + double life = 40; + RainParticle p = AddParticle( rainParticles, ref rainCount, true ); + p.ResetState( pos, velocity, life ); + p.Big = rnd.Next( 0, 20 ) >= 18; + p.Tiny = rnd.Next( 0, 30 ) >= 28; } } + + T AddParticle( T[] particles, ref int count, bool rain ) where T : Particle { + if( count == maxParticles ) + RemoveAt( 0, particles, ref count ); + count++; + + T old = particles[count - 1]; + if( old != null ) return old; + + T newT = rain ? (T)(object)new RainParticle( game ) + : (T)(object)new TerrainParticle( game ); + particles[count - 1] = newT; + return newT; + } + + void RemoveAt( int index, T[] particles, ref int count ) where T : Particle { + T removed = particles[index]; + for( int i = index; i < count - 1; i++ ) { + particles[i] = particles[i + 1]; + } + + particles[count - 1] = removed; + count--; + } + } } diff --git a/ClassicalSharp/Particles/RainParticle.cs b/ClassicalSharp/Particles/RainParticle.cs index 32bc11e9e..cb5940bdc 100644 --- a/ClassicalSharp/Particles/RainParticle.cs +++ b/ClassicalSharp/Particles/RainParticle.cs @@ -5,16 +5,25 @@ namespace ClassicalSharp.Particles { public sealed class RainParticle : CollidableParticle { - static Vector2 rainSize = new Vector2( 1/8f, 1/8f ); + static Vector2 bigSize = new Vector2( 1/16f, 1/16f ); + static Vector2 smallSize = new Vector2( 0.75f/16f, 0.75f/16f ); + static Vector2 tinySize = new Vector2( 0.5f/16f, 0.5f/16f ); static TextureRec rec = new TextureRec( 2/128f, 14/128f, 3/128f, 2/128f ); - public RainParticle( Game game, Vector3 pos, Vector3 velocity, double lifetime ) - : base( game, pos, velocity, lifetime ) { + + public RainParticle( Game game ) : base( game ) { } + + public bool Big, Tiny; + + public override bool Tick( double delta ) { + bool dies = Tick( 3.5f, delta ); + return hitTerrain ? true : dies; } public override void Render( double delta, float t, VertexPos3fTex2fCol4b[] vertices, ref int index ) { Position = Vector3.Lerp( lastPos, nextPos, t ); Vector3 p111, p121, p212, p222; - Utils.CalcBillboardPoints( rainSize, Position, ref game.View, + Vector2 size = Big ? bigSize : (Tiny ? tinySize : smallSize ); + Utils.CalcBillboardPoints( size, Position, ref game.View, out p111, out p121, out p212, out p222 ); Map map = game.Map; FastColour col = map.IsLit( Vector3I.Floor( Position ) ) ? map.Sunlight : map.Shadowlight; diff --git a/ClassicalSharp/Particles/TerrainParticle.cs b/ClassicalSharp/Particles/TerrainParticle.cs index eabe5020b..08269995c 100644 --- a/ClassicalSharp/Particles/TerrainParticle.cs +++ b/ClassicalSharp/Particles/TerrainParticle.cs @@ -6,10 +6,12 @@ namespace ClassicalSharp.Particles { public sealed class TerrainParticle : CollidableParticle { static Vector2 terrainSize = new Vector2( 1/8f, 1/8f ); - TextureRec rec; - public TerrainParticle( Game game, Vector3 pos, Vector3 velocity, double lifetime, TextureRec rec ) - : base( game, pos, velocity, lifetime ) { - this.rec = rec; + internal TextureRec rec; + + public TerrainParticle( Game game ) : base( game ) { } + + public override bool Tick( double delta ) { + return Tick( 5.4f, delta ); } public override void Render( double delta, float t, VertexPos3fTex2fCol4b[] vertices, ref int index ) { diff --git a/ClassicalSharp/Rendering/WeatherRenderer.cs b/ClassicalSharp/Rendering/WeatherRenderer.cs index 7e0ca2916..d59803af8 100644 --- a/ClassicalSharp/Rendering/WeatherRenderer.cs +++ b/ClassicalSharp/Rendering/WeatherRenderer.cs @@ -24,6 +24,7 @@ namespace ClassicalSharp { const int extent = 4; VertexPos3fTex2fCol4b[] vertices = new VertexPos3fTex2fCol4b[8 * (extent * 2 + 1) * (extent * 2 + 1)]; double rainAcc; + Vector3I lastPos = new Vector3I( Int32.MinValue ); public void Render( double deltaTime ) { Weather weather = map.Weather; @@ -33,12 +34,14 @@ namespace ClassicalSharp { graphics.BindTexture( weather == Weather.Rainy ? game.RainTexId : game.SnowTexId ); Vector3 eyePos = game.LocalPlayer.EyePosition; Vector3 camPos = game.Camera.GetCameraPos( eyePos ); - Vector3I pos = Vector3I.Floor( eyePos ); // TODO: cam pos + Vector3I pos = Vector3I.Floor( camPos ); + bool moved = pos != lastPos; + lastPos = pos; float speed = weather == Weather.Rainy ? 1f : 0.25f; vOffset = -(float)game.accumulator * speed; rainAcc += deltaTime; - + int index = 0; graphics.AlphaBlending = true; graphics.DepthWrite = false; @@ -49,16 +52,15 @@ namespace ClassicalSharp { float height = Math.Max( game.Map.Height, pos.Y + 64 ) - rainY; if( height <= 0 ) continue; - //if( rainAcc >= 2 ) - // game.ParticleManager.AddRainParticle( new Vector3( pos.X + dx, rainY, pos.Z + dz ) ); + if( rainAcc >= 0.25 || moved ) + game.ParticleManager.AddRainParticle( new Vector3( pos.X + dx, rainY, pos.Z + dz ) ); col.A = (byte)Math.Max( 0, AlphaAt( dx * dx + dz * dz ) ); MakeRainForSquare( pos.X + dx, rainY, height, pos.Z + dz, col, ref index ); } } - if( rainAcc >= 2 ) + if( rainAcc >= 0.25 || moved ) rainAcc = 0; - // fixes crashing on nVidia cards in OpenGL builds. if( index > 0 ) { graphics.SetBatchFormat( VertexFormat.Pos3fTex2fCol4b ); graphics.UpdateDynamicIndexedVb( DrawMode.Triangles, weatherVb, vertices, index, index * 6 / 4 ); @@ -92,6 +94,7 @@ namespace ClassicalSharp { int length, width, maxY, oneY; void OnNewMap( object sender, EventArgs e ) { heightmap = null; + lastPos = new Vector3I( Int32.MaxValue ); } void OnNewMapLoaded( object sender, EventArgs e ) { diff --git a/ClassicalSharp/Singleplayer/Server.cs b/ClassicalSharp/Singleplayer/Server.cs index 859e87460..b5d39196e 100644 --- a/ClassicalSharp/Singleplayer/Server.cs +++ b/ClassicalSharp/Singleplayer/Server.cs @@ -104,7 +104,7 @@ namespace ClassicalSharp.Singleplayer { this.generator = generator; game.SetNewScreen( new LoadingMapScreen( game, "Single player", "Generating.." ) ); - generator.GenerateAsync( game, width, height, length, 0 ); + generator.GenerateAsync( game, width, height, length, seed ); } unsafe void MapSet( int width, int length, byte* ptr, int yStart, int yEnd, byte block ) { diff --git a/ClassicalSharp/Utils/Vector3I.cs b/ClassicalSharp/Utils/Vector3I.cs index 3b0300134..604c86ca2 100644 --- a/ClassicalSharp/Utils/Vector3I.cs +++ b/ClassicalSharp/Utils/Vector3I.cs @@ -28,15 +28,11 @@ namespace ClassicalSharp { } public Vector3I( int x, int y, int z ) { - X = x; - Y = y; - Z = z; + X = x; Y = y; Z = z; } public Vector3I( int value ) { - X = value; - Y = value; - Z = value; + X = value; Y = value; Z = value; } public static Vector3I operator + ( Vector3I left, Vector3I right ) {