using System;
using System.Drawing;
using ClassicalSharp.Model;
using ClassicalSharp.Network;
using OpenTK;
namespace ClassicalSharp {
public abstract partial class Player : AnimatedEntity {
/// Gets the position of the player's eye in the world.
public Vector3 EyePosition {
get { return new Vector3( Position.X, Position.Y + Model.GetEyeY( this ), Position.Z ); }
}
public string DisplayName, SkinName, SkinIdentifier;
public SkinType SkinType;
public Player( Game game ) : base( game ) {
this.game = game;
StepSize = 0.5f;
SkinType = game.DefaultPlayerSkinType;
SetModel( "humanoid" );
}
/// Gets the block just underneath the player's feet position.
public Block BlockUnderFeet {
get { return GetBlock( new Vector3( Position.X, Position.Y - 0.01f, Position.Z ) ); }
}
/// Gets the block at player's eye position.
public Block BlockAtHead {
get { return GetBlock( EyePosition ); }
}
protected Block GetBlock( Vector3 coords ) {
return (Block)game.Map.SafeGetBlock( Vector3I.Floor( coords ) );
}
public abstract void Tick( double delta );
public abstract void SetLocation( LocationUpdate update, bool interpolate );
protected void CheckSkin() {
DownloadedItem item;
game.AsyncDownloader.TryGetItem( SkinIdentifier, out item );
if( item != null && item.Data != null ) {
Bitmap bmp = (Bitmap)item.Data;
game.Graphics.DeleteTexture( ref PlayerTextureId );
if( !FastBitmap.CheckFormat( bmp.PixelFormat ) )
game.Drawer2D.ConvertTo32Bpp( ref bmp );
try {
SkinType = Utils.GetSkinType( bmp );
if( Model is PlayerModel )
ClearHat( bmp, SkinType );
PlayerTextureId = game.Graphics.CreateTexture( bmp );
MobTextureId = -1;
// Custom mob textures.
if( Utils.IsUrlPrefix( SkinName ) && item.TimeAdded > lastModelChange )
MobTextureId = PlayerTextureId;
} catch( NotSupportedException ) {
ResetSkin( bmp );
}
bmp.Dispose();
}
}
void ResetSkin( Bitmap bmp ) {
string formatString = "Skin {0} has unsupported dimensions({1}, {2}), reverting to default.";
Utils.LogDebug( formatString, SkinName, bmp.Width, bmp.Height );
MobTextureId = -1;
PlayerTextureId = -1;
SkinType = game.DefaultPlayerSkinType;
}
DateTime lastModelChange = new DateTime( 1, 1, 1 );
public void SetModel( string modelName ) {
ModelName = modelName;
Model = game.ModelCache.GetModel( ModelName );
lastModelChange = DateTime.UtcNow;
MobTextureId = -1;
}
unsafe static void ClearHat( Bitmap bmp, SkinType skinType ) {
using( FastBitmap fastBmp = new FastBitmap( bmp, true ) ) {
int sizeX = (bmp.Width / 64) * 32;
int yScale = skinType == SkinType.Type64x32 ? 32 : 64;
int sizeY = (bmp.Height / yScale) * 16;
// determine if we actually need filtering
for( int y = 0; y < sizeY; y++ ) {
int* row = fastBmp.GetRowPtr( y );
row += sizeX;
for( int x = 0; x < sizeX; x++ ) {
byte alpha = (byte)(row[x] >> 24);
if( alpha != 255 ) return;
}
}
// only perform filtering when the entire hat is opaque
int fullWhite = FastColour.White.ToArgb();
int fullBlack = FastColour.Black.ToArgb();
for( int y = 0; y < sizeY; y++ ) {
int* row = fastBmp.GetRowPtr( y );
row += sizeX;
for( int x = 0; x < sizeX; x++ ) {
int pixel = row[x];
if( pixel == fullWhite || pixel == fullBlack ) row[x] = 0;
}
}
}
}
}
}