Simplify and modularise AsyncDownloader, remove duplicate entity spwaning code, remove EntityInfoChange event (broken, as it didn't change the in game entity display name)

This commit is contained in:
UnknownShadow200 2015-05-13 19:47:12 +10:00
parent 12bcf5d335
commit 714f03e893
7 changed files with 121 additions and 174 deletions

View File

@ -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++ ) {

View File

@ -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 );

View File

@ -9,10 +9,6 @@ namespace ClassicalSharp {
/// <summary> Raised when a player is spawned in the current world. </summary>
public event EventHandler<IdEventArgs> EntityAdded;
/// <summary> Raised when information(display name and/or skin name) is changed about a player. </summary>
/// <remarks> Note this event is only raised when using the CPE player list extension. </remarks>
public event EventHandler<IdEventArgs> EntityInfoChanged;
/// <summary> Raised when a player is despawned from the current world. </summary>
public event EventHandler<IdEventArgs> 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 );

View File

@ -15,76 +15,38 @@ namespace ClassicalSharp.Network {
readonly object requestLocker = new object();
List<DownloadRequest> requests = new List<DownloadRequest>();
readonly object downloadedLocker = new object();
Dictionary<string, DownloadedRequest> downloaded = new Dictionary<string, DownloadedRequest>();
Dictionary<string, DownloadedItem> downloaded = new Dictionary<string, DownloadedItem>();
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 );
}
/// <summary> Downloads an image, asynchronously, from the specified url. </summary>
/// <param name="url"> URL the image is located at. </param>
/// <param name="priority"> If this is true, the request is added straight to the
/// start of the requests queue. (otherwise added to the end)</param>
/// <param name="identifier"> Unique identifier for the image. (e.g. skin_test)</param>
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 );
}
/// <summary> Downloads a page, asynchronously, from the specified url. </summary>
/// <param name="url"> URL the image is located at. </param>
/// <param name="priority"> If this is true, the request is added straight to the
/// start of the requests queue. (otherwise added to the end)</param>
/// <param name="identifier"> Unique identifier for the image. (e.g. skin_test)</param>
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();
}
/// <summary> Removes all entries from the downloaded images queue that are
/// older (relative to the current time) than the given number of seconds. </summary>
public void PurgeOldEntries( int seconds ) {
lock( downloadedLocker ) {
DateTime now = DateTime.UtcNow;
List<string> requestsToRemove = new List<string>( downloaded.Count );
List<string> itemsToRemove = new List<string>( 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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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 );
}
}

View File

@ -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;