diff --git a/2D/Widgets/PlayerListWidget.cs b/2D/Widgets/PlayerListWidget.cs index 888fe95ba..d75c9e5c0 100644 --- a/2D/Widgets/PlayerListWidget.cs +++ b/2D/Widgets/PlayerListWidget.cs @@ -43,7 +43,6 @@ namespace ClassicalSharp { SortPlayerInfo(); Window.EntityAdded += PlayerSpawned; Window.EntityRemoved += PlayerDespawned; - Window.EntityInfoChanged += PlayerInfoChanged; } public override void Render( double delta ) { @@ -62,7 +61,6 @@ namespace ClassicalSharp { } Window.EntityAdded -= PlayerSpawned; Window.EntityRemoved -= PlayerDespawned; - Window.EntityInfoChanged -= PlayerInfoChanged; } void PlayerSpawned( object sender, IdEventArgs e ) { @@ -84,18 +82,6 @@ namespace ClassicalSharp { } } } - - void PlayerInfoChanged( object sender, IdEventArgs e ) { - for( int i = 0; i < info.Count; i++ ) { - PlayerInfo pInfo = info[i]; - if( pInfo.PlayerId == e.Id ) { - GraphicsApi.DeleteTexture( ref pInfo.Texture ); - info[i] = new PlayerInfo( GraphicsApi, Window.NetPlayers[e.Id], font ); - SortPlayerInfo(); - break; - } - } - } void CreateInitialPlayerInfo() { for( int i = 0; i < Window.NetPlayers.Length; i++ ) { diff --git a/Entities/Player.cs b/Entities/Player.cs index 1a3ea8bd9..a49ae72fa 100644 --- a/Entities/Player.cs +++ b/Entities/Player.cs @@ -1,6 +1,7 @@ using System; using System.Drawing; using OpenTK; +using ClassicalSharp.Network; using ClassicalSharp.Model; using ClassicalSharp.Renderers; @@ -105,9 +106,10 @@ namespace ClassicalSharp { } protected void CheckSkin() { - Bitmap bmp; - Window.AsyncDownloader.TryGetImage( "skin_" + SkinName, out bmp ); - if( bmp != null ) { + DownloadedItem item; + Window.AsyncDownloader.TryGetItem( "skin_" + SkinName, out item ); + if( item != null && item.Bmp != null ) { + Bitmap bmp = item.Bmp; Window.Graphics.DeleteTexture( renderer.TextureId ); renderer.TextureId = Window.Graphics.LoadTexture( bmp ); SkinType = Utils.GetSkinType( bmp ); diff --git a/Game/Game.Events.cs b/Game/Game.Events.cs index 9688a9fe5..865304ad0 100644 --- a/Game/Game.Events.cs +++ b/Game/Game.Events.cs @@ -9,10 +9,6 @@ namespace ClassicalSharp { /// Raised when a player is spawned in the current world. public event EventHandler EntityAdded; - /// Raised when information(display name and/or skin name) is changed about a player. - /// Note this event is only raised when using the CPE player list extension. - public event EventHandler EntityInfoChanged; - /// Raised when a player is despawned from the current world. public event EventHandler EntityRemoved; @@ -55,11 +51,6 @@ namespace ClassicalSharp { RaiseEvent( EntityAdded, e ); } - internal void RaiseEntityInfoChange( byte id ) { - IdEventArgs e = new IdEventArgs( id ); - RaiseEvent( EntityInfoChanged, e ); - } - internal void RaiseEntityRemoved( byte id ) { IdEventArgs e = new IdEventArgs( id ); RaiseEvent( EntityRemoved, e ); diff --git a/Network/AsyncDownloader.cs b/Network/AsyncDownloader.cs index 383187631..e55da11fe 100644 --- a/Network/AsyncDownloader.cs +++ b/Network/AsyncDownloader.cs @@ -15,76 +15,38 @@ namespace ClassicalSharp.Network { readonly object requestLocker = new object(); List requests = new List(); readonly object downloadedLocker = new object(); - Dictionary downloaded = new Dictionary(); + Dictionary downloaded = new Dictionary(); string skinServer = null; public AsyncDownloader( string skinServer ) { this.skinServer = skinServer; client = new WebClient(); client.Proxy = null; + worker = new Thread( DownloadThreadWorker ); worker.Name = "ClassicalSharp.ImageDownloader"; worker.IsBackground = true; worker.Start(); } - class DownloadedRequest { - - public Bitmap Bmp; - public string Page; - public DateTime Timestamp; - - public DownloadedRequest( Bitmap bmp, string page ) { - Bmp = bmp; - Page = page; - Timestamp = DateTime.UtcNow; - } - } - - class DownloadRequest { - - public string Url; - public string Identifier; - public bool IsImage; - - public DownloadRequest( string url, string identifier, bool isImage ) { - Url = url; - Identifier = identifier; - IsImage = isImage; - } - } - public void DownloadSkin( string skinName ) { string strippedSkinName = Utils.StripColours( skinName ); - string url = skinServer + strippedSkinName + ".png"; - DownloadImage( url, false, "skin_" + strippedSkinName ); + string url = Utils.IsUrl( skinName ) ? skinName : + skinServer + strippedSkinName + ".png"; + AddRequestToQueue( url, true, "skin_" + strippedSkinName, true ); } - /// Downloads an image, asynchronously, from the specified url. - /// URL the image is located at. - /// If this is true, the request is added straight to the - /// start of the requests queue. (otherwise added to the end) - /// Unique identifier for the image. (e.g. skin_test) public void DownloadImage( string url, bool priority, string identifier ) { - lock( requestLocker ) { - DownloadRequest request = new DownloadRequest( url, identifier, true ); - if( priority ) { - requests.Insert( 0, request ); - } else { - requests.Add( request ); - } - } - handle.Set(); + AddRequestToQueue( url, priority, identifier, true ); } - /// Downloads a page, asynchronously, from the specified url. - /// URL the image is located at. - /// If this is true, the request is added straight to the - /// start of the requests queue. (otherwise added to the end) - /// Unique identifier for the image. (e.g. skin_test) public void DownloadPage( string url, bool priority, string identifier ) { + AddRequestToQueue( url, priority, identifier, false ); + } + + void AddRequestToQueue( string url, bool priority, string identifier, bool image ) { lock( requestLocker ) { - DownloadRequest request = new DownloadRequest( url, identifier, false ); + DownloadRequest request = new DownloadRequest( url, identifier, image ); if( priority ) { requests.Insert( 0, request ); } else { @@ -105,54 +67,35 @@ namespace ClassicalSharp.Network { client.Dispose(); } - /// Removes all entries from the downloaded images queue that are - /// older (relative to the current time) than the given number of seconds. public void PurgeOldEntries( int seconds ) { lock( downloadedLocker ) { DateTime now = DateTime.UtcNow; - List requestsToRemove = new List( downloaded.Count ); + List itemsToRemove = new List( downloaded.Count ); foreach( var item in downloaded ) { - DateTime timestamp = item.Value.Timestamp; + DateTime timestamp = item.Value.TimeDownloaded; if( ( now - timestamp ).TotalSeconds > seconds ) { - requestsToRemove.Add( item.Key ); + itemsToRemove.Add( item.Key ); } } - for( int i = 0; i < requestsToRemove.Count; i++ ) { - string key = requestsToRemove[i]; - DownloadedRequest req; - downloaded.TryGetValue( key, out req ); + for( int i = 0; i < itemsToRemove.Count; i++ ) { + string key = itemsToRemove[i]; + DownloadedItem item; + downloaded.TryGetValue( key, out item ); downloaded.Remove( key ); - if( req.Bmp != null ) { - req.Bmp.Dispose(); + if( item.Bmp != null ) { + item.Bmp.Dispose(); } } } } - public bool TryGetImage( string identifier, out Bitmap bmp ) { + public bool TryGetItem( string identifier, out DownloadedItem item ) { bool success = false; - bmp = null; - DownloadedRequest req; lock( downloadedLocker ) { - success = downloaded.TryGetValue( identifier, out req ); + success = downloaded.TryGetValue( identifier, out item ); if( success ) { - bmp = req.Bmp; - downloaded.Remove( identifier ); - } - } - return success; - } - - public bool TryGetPage( string identifier, out string page ) { - bool success = false; - page = null; - DownloadedRequest req; - lock( downloadedLocker ) { - success = downloaded.TryGetValue( identifier, out req ); - if( success ) { - page = req.Page; downloaded.Remove( identifier ); } } @@ -167,53 +110,85 @@ namespace ClassicalSharp.Network { if( requests.Count > 0 ) { request = requests[0]; requests.RemoveAt( 0 ); - if( request == null ) return; + if( request == null ) + return; } } if( request != null ) { - string url = request.Url; - bool isImage = request.IsImage; - Utils.LogDebug( "Downloading " + ( isImage ? "image" : "page" ) + " from: " + url ); - Bitmap bmp = null; - string page = null; - - try { - if( isImage ) { - bmp = DownloadImage( request.Url, client ); - } else { - page = DownloadPage( request.Url, client ); - } - Utils.LogDebug( "Downloaded from: " + request.Url ); - } catch( Exception ex ) { - if( !( ex is WebException || ex is ArgumentException ) ) throw; - bmp = null; - page = null; - Utils.LogDebug( "Failed to download from: " + request.Url ); - } - - lock( downloadedLocker ) { - DownloadedRequest old; - if( downloaded.TryGetValue( request.Identifier, out old ) ) { - Utils.LogDebug( "{0} is already in the queue, replacing it..", request.Identifier ); - if( old.Bmp != null ) old.Bmp.Dispose(); - } - downloaded[request.Identifier] = new DownloadedRequest( bmp, page ); - } + DownloadItem( request ); } else { handle.WaitOne(); } } } - static Bitmap DownloadImage( string uri, WebClient client ) { - byte[] data = client.DownloadData( uri ); - using( MemoryStream stream = new MemoryStream( data ) ) { - return new Bitmap( stream ); + void DownloadItem( DownloadRequest request ) { + string url = request.Url; + bool isImage = request.IsImage; + Utils.LogDebug( "Downloading " + ( isImage ? "image" : "page" ) + " from: " + url ); + Bitmap bmp = null; + string page = null; + + try { + if( isImage ) { + byte[] data = client.DownloadData( url ); + using( MemoryStream stream = new MemoryStream( data ) ) { + bmp = new Bitmap( stream ); + } + } else { + page = client.DownloadString( url ); + } + Utils.LogDebug( "Downloaded from: " + request.Url ); + } catch( Exception ex ) { + if( !( ex is WebException || ex is ArgumentException ) ) throw; + Utils.LogDebug( "Failed to download from: " + request.Url ); + } + + lock( downloadedLocker ) { + DownloadedItem oldItem; + DownloadedItem newItem = new DownloadedItem( bmp, page, request.TimeAdded ); + + if( downloaded.TryGetValue( request.Identifier, out oldItem ) ) { + if( oldItem.TimeAdded > newItem.TimeAdded ) { + DownloadedItem old = oldItem; + oldItem = newItem; + newItem = old; + } + + if( oldItem.Bmp != null ) + oldItem.Bmp.Dispose(); + } + downloaded[request.Identifier] = newItem; } } - static string DownloadPage( string uri, WebClient client ) { - return client.DownloadString( uri ); + class DownloadRequest { + + public string Url; + public string Identifier; + public bool IsImage; + public DateTime TimeAdded; + + public DownloadRequest( string url, string identifier, bool isImage ) { + Url = url; + Identifier = identifier; + IsImage = isImage; + TimeAdded = DateTime.UtcNow; + } + } + } + + public class DownloadedItem { + + public Bitmap Bmp; + public string Page; + public DateTime TimeAdded, TimeDownloaded; + + public DownloadedItem( Bitmap bmp, string page, DateTime timeAdded ) { + Bmp = bmp; + Page = page; + TimeAdded = timeAdded; + TimeDownloaded = DateTime.UtcNow; } } } \ No newline at end of file diff --git a/Network/NetworkProcessor.cs b/Network/NetworkProcessor.cs index ec674a2a7..e693df71d 100644 --- a/Network/NetworkProcessor.cs +++ b/Network/NetworkProcessor.cs @@ -6,6 +6,7 @@ using System.IO.Compression; using System.Net; using System.Net.Sockets; using System.Text; +using ClassicalSharp.Network; using OpenTK; namespace ClassicalSharp { @@ -65,10 +66,10 @@ namespace ClassicalSharp { } void CheckForNewTerrainAtlas() { - Bitmap bmp; - Window.AsyncDownloader.TryGetImage( "terrain", out bmp ); - if( bmp != null ) { - Window.ChangeTerrainAtlas( bmp ); + DownloadedItem item; + Window.AsyncDownloader.TryGetItem( "terrain", out item ); + if( item != null && item.Bmp != null ) { + Window.ChangeTerrainAtlas( item.Bmp ); } } @@ -353,7 +354,7 @@ namespace ClassicalSharp { { byte entityId = reader.ReadUInt8(); string name = reader.ReadString(); - AddEntity( entityId, name, name ); + AddEntity( entityId, name, name, true ); } break; case PacketId.EntityTeleport: @@ -494,18 +495,7 @@ namespace ClassicalSharp { byte entityId = reader.ReadUInt8(); string displayName = reader.ReadString(); string skinName = reader.ReadString(); - if( entityId != 0xFF ) { - Window.AsyncDownloader.DownloadSkin( skinName ); - Player oldPlayer = Window.NetPlayers[entityId]; - if( oldPlayer != null ) { - oldPlayer.DisplayName = displayName; - oldPlayer.SkinName = skinName; - Window.RaiseEntityInfoChange( entityId ); - } else { - Window.NetPlayers[entityId] = new NetPlayer( entityId, displayName, skinName, Window ); - Window.RaiseEntityAdded( entityId ); - } - } + AddEntity( entityId, displayName, skinName, false ); } break; case PacketId.CpeExtRemovePlayerName: @@ -631,7 +621,7 @@ namespace ClassicalSharp { byte entityId = reader.ReadUInt8(); string displayName = reader.ReadString(); string skinName = reader.ReadString(); - AddEntity( entityId, displayName, skinName ); + AddEntity( entityId, displayName, skinName, true ); } break; default: @@ -639,7 +629,7 @@ namespace ClassicalSharp { } } - void AddEntity( byte entityId, string displayName, string skinName ) { + void AddEntity( byte entityId, string displayName, string skinName, bool readPosition ) { if( entityId != 0xFF ) { Window.AsyncDownloader.DownloadSkin( skinName ); // This shouldn't usually happen, but just in case.. @@ -651,9 +641,11 @@ namespace ClassicalSharp { Window.NetPlayers[entityId] = new NetPlayer( entityId, displayName, skinName, Window ); Window.RaiseEntityAdded( entityId ); } - ReadAbsoluteLocation( entityId, false ); - if( entityId == 0xFF ) { - Window.LocalPlayer.SpawnPoint = Window.LocalPlayer.Position; + if( readPosition ) { + ReadAbsoluteLocation( entityId, false ); + if( entityId == 0xFF ) { + Window.LocalPlayer.SpawnPoint = Window.LocalPlayer.Position; + } } } diff --git a/Network/WomConfigHandler.cs b/Network/WomConfigHandler.cs index ee35eabdf..4e825b28b 100644 --- a/Network/WomConfigHandler.cs +++ b/Network/WomConfigHandler.cs @@ -2,6 +2,7 @@ using System; using System.Drawing; using System.IO; +using ClassicalSharp.Network; namespace ClassicalSharp { @@ -9,19 +10,15 @@ namespace ClassicalSharp { string womEnvIdentifier = "womenv_0", womTerrainIdentifier = "womterrain_0"; void CheckForWomEnvironment() { - string page; - Window.AsyncDownloader.TryGetPage( womEnvIdentifier, out page ); - if( page != null ) { - ParseWomConfig( page ); + DownloadedItem item; + Window.AsyncDownloader.TryGetItem( womEnvIdentifier, out item ); + if( item != null && item.Page != null ) { + ParseWomConfig( item.Page ); } - CheckWomBitmaps(); - } - - void CheckWomBitmaps() { - Bitmap terrainBmp; - Window.AsyncDownloader.TryGetImage( womTerrainIdentifier, out terrainBmp ); - if( terrainBmp != null ) { - Window.ChangeTerrainAtlas( terrainBmp ); + + Window.AsyncDownloader.TryGetItem( womTerrainIdentifier, out item ); + if( item != null && item.Bmp != null ) { + Window.ChangeTerrainAtlas( item.Bmp ); } } diff --git a/Utils/Utils.cs b/Utils/Utils.cs index a62d6e5ea..10c9b350a 100644 --- a/Utils/Utils.cs +++ b/Utils/Utils.cs @@ -35,6 +35,10 @@ namespace ClassicalSharp { return next; } + public static bool IsUrl( string value ) { + return value.StartsWith( "http://" ) || value.StartsWith( "https://" ); + } + public static string StripColours( string value ) { if( value.IndexOf( '&' ) == -1 ) { return value;