More comments, more refactoring. Remove WoM terrain atlas support because WoM's file server has been down for quite a long time now.

This commit is contained in:
UnknownShadow200 2015-10-10 20:29:29 +11:00
parent 448ec55e6e
commit 00945a6095
11 changed files with 112 additions and 95 deletions

View File

@ -13,31 +13,44 @@ namespace ClassicalSharp {
/// <summary> Sets the underlying bitmap that drawing operations will be performed on. </summary> /// <summary> Sets the underlying bitmap that drawing operations will be performed on. </summary>
public abstract void SetBitmap( Bitmap bmp ); public abstract void SetBitmap( Bitmap bmp );
/// <summary> Draws a string using the specified arguments and fonts at the
/// specified coordinates in the currently bound bitmap. </summary>
public abstract void DrawText( Font font, ref DrawTextArgs args, float x, float y ); public abstract void DrawText( Font font, ref DrawTextArgs args, float x, float y );
/// <summary> Draws a 2D flat rectangle of the specified dimensions at the
/// specified coordinates in the currently bound bitmap. </summary>
public abstract void DrawRect( Color colour, int x, int y, int width, int height ); public abstract void DrawRect( Color colour, int x, int y, int width, int height );
/// <summary> Draws the outline of a 2D flat rectangle of the specified dimensions
/// at the specified coordinates in the currently bound bitmap. </summary>
public abstract void DrawRectBounds( Color colour, float lineWidth, int x, int y, int width, int height ); public abstract void DrawRectBounds( Color colour, float lineWidth, int x, int y, int width, int height );
/// <summary> Draws a 2D rectangle with rounded borders of the specified dimensions
/// at the specified coordinates in the currently bound bitmap. </summary>
public abstract void DrawRoundedRect( Color colour, float radius, float x, float y, float width, float height ); public abstract void DrawRoundedRect( Color colour, float radius, float x, float y, float width, float height );
/// <summary> Clears the entire bound bitmap to the specified colour. </summary>
public abstract void Clear( Color colour ); public abstract void Clear( Color colour );
/// <summary> Disposes of any resources used by this class that are associated with the underlying bitmap. </summary> /// <summary> Disposes of any resources used by this class that are associated with the underlying bitmap. </summary>
public abstract void Dispose(); public abstract void Dispose();
/// <summary> Returns a new bitmap that has 32-bpp pixel format. </summary>
public abstract Bitmap ConvertTo32Bpp( Bitmap src ); public abstract Bitmap ConvertTo32Bpp( Bitmap src );
/// <summary> Returns the size of a bitmap needed to contain the specified text with the given arguments. </summary>
public abstract Size MeasureSize( string text, Font font, bool shadow ); public abstract Size MeasureSize( string text, Font font, bool shadow );
/// <summary> Disposes of all native resources used by this class. </summary> /// <summary> Disposes of all native resources used by this class. </summary>
/// <remarks> You will no longer be able to perform measuring or drawing calls after this. </remarks> /// <remarks> You will no longer be able to perform measuring or drawing calls after this. </remarks>
public abstract void DisposeInstance(); public abstract void DisposeInstance();
public Texture MakeTextTexture( Font font, int screenX, int screenY, ref DrawTextArgs args ) { /// <summary> Draws the specified string from the arguments into a new bitmap,
/// them creates a 2D texture with origin at the specified window coordinates. </summary>
public Texture MakeTextTexture( Font font, int windowX, int windowY, ref DrawTextArgs args ) {
Size size = MeasureSize( args.Text, font, args.UseShadow ); Size size = MeasureSize( args.Text, font, args.UseShadow );
if( parts.Count == 0 ) if( parts.Count == 0 )
return new Texture( -1, screenX, screenY, 0, 0, 1, 1 ); return new Texture( -1, windowX, windowY, 0, 0, 1, 1 );
using( Bitmap bmp = CreatePow2Bitmap( size ) ) { using( Bitmap bmp = CreatePow2Bitmap( size ) ) {
SetBitmap( bmp ); SetBitmap( bmp );
@ -45,17 +58,18 @@ namespace ClassicalSharp {
DrawText( font, ref args, 0, 0 ); DrawText( font, ref args, 0, 0 );
Dispose(); Dispose();
return Make2DTexture( bmp, size, screenX, screenY ); return Make2DTexture( bmp, size, windowX, windowY );
} }
} }
public Texture Make2DTexture( Bitmap bmp, Size used, int screenX, int screenY ) { /// <summary> Creates a 2D texture with origin at the specified window coordinates. </summary>
public Texture Make2DTexture( Bitmap bmp, Size used, int windowX, int windowY ) {
int texId = graphics.CreateTexture( bmp ); int texId = graphics.CreateTexture( bmp );
return new Texture( texId, screenX, screenY, used.Width, used.Height, return new Texture( texId, windowX, windowY, used.Width, used.Height,
(float)used.Width / bmp.Width, (float)used.Height / bmp.Height ); (float)used.Width / bmp.Width, (float)used.Height / bmp.Height );
} }
/// <summary> Creates a power-of-2 sized bitmap larger or equal to to the given size. </summary>
public static Bitmap CreatePow2Bitmap( Size size ) { public static Bitmap CreatePow2Bitmap( Size size ) {
return new Bitmap( Utils.NextPowerOf2( size.Width ), Utils.NextPowerOf2( size.Height ) ); return new Bitmap( Utils.NextPowerOf2( size.Width ), Utils.NextPowerOf2( size.Height ) );
} }
@ -91,9 +105,9 @@ namespace ClassicalSharp {
if( partLength > 0 ) { if( partLength > 0 ) {
string part = value.Substring( i, partLength ); string part = value.Substring( i, partLength );
Color col = Color.FromArgb( Color col = Color.FromArgb(
191 * ( ( code >> 2 ) & 0x1 ) + 64 * ( code >> 3 ), 191 * ((code >> 2) & 1) + 64 * (code >> 3),
191 * ( ( code >> 1 ) & 0x1 ) + 64 * ( code >> 3 ), 191 * ((code >> 1) & 1) + 64 * (code >> 3),
191 * ( ( code >> 0 ) & 0x1 ) + 64 * ( code >> 3 ) ); 191 * ((code >> 0) & 1) + 64 * (code >> 3) );
parts.Add( new TextPart( part, col ) ); parts.Add( new TextPart( part, col ) );
} }
i += partLength + 1; i += partLength + 1;

View File

@ -41,7 +41,7 @@ namespace ClassicalSharp {
} }
protected override void CreateInitialPlayerInfo() { protected override void CreateInitialPlayerInfo() {
for( int i = 0; i < game.Players.MaxCount; i++ ) { for( int i = 0; i < EntityList.MaxCount; i++ ) {
Player player = game.Players[i]; Player player = game.Players[i];
if( player != null ) { if( player != null ) {
AddPlayerInfo( player ); AddPlayerInfo( player );

View File

@ -103,6 +103,7 @@
<Compile Include="Blocks\BlockInfo.cs" /> <Compile Include="Blocks\BlockInfo.cs" />
<Compile Include="Blocks\BlockInfo.Culling.cs" /> <Compile Include="Blocks\BlockInfo.Culling.cs" />
<Compile Include="Blocks\BlockInfo.Atlas.cs" /> <Compile Include="Blocks\BlockInfo.Atlas.cs" />
<Compile Include="Entities\AnimatedEntity.cs" />
<Compile Include="Entities\Entity.cs" /> <Compile Include="Entities\Entity.cs" />
<Compile Include="Entities\EntityList.cs" /> <Compile Include="Entities\EntityList.cs" />
<Compile Include="Entities\LocalPlayer.cs" /> <Compile Include="Entities\LocalPlayer.cs" />

View File

@ -0,0 +1,54 @@
using System;
using OpenTK;
namespace ClassicalSharp {
/// <summary> Entity that is animated depending on movement speed and time. </summary>
public abstract class AnimatedEntity : PhysicsEntity {
public AnimatedEntity( Game game ) : base( game ) {
}
public float leftLegXRot, leftArmXRot, leftArmZRot;
public float rightLegXRot, rightArmXRot, rightArmZRot;
protected float walkTimeO, walkTimeN, swingO, swingN;
/// <summary> Calculates the next animation state based on old and new position. </summary>
protected void UpdateAnimState( Vector3 oldPos, Vector3 newPos, double delta ) {
walkTimeO = walkTimeN;
swingO = swingN;
float dx = newPos.X - oldPos.X;
float dz = newPos.Z - oldPos.Z;
double distance = Math.Sqrt( dx * dx + dz * dz );
if( distance > 0.05 ) {
walkTimeN += (float)distance * 2 * (float)(20 * delta);
swingN += (float)delta * 3;
} else {
swingN -= (float)delta * 3;
}
Utils.Clamp( ref swingN, 0, 1 );
}
const float armMax = 60 * Utils.Deg2Rad;
const float legMax = 80 * Utils.Deg2Rad;
const float idleMax = 3 * Utils.Deg2Rad;
const float idleXPeriod = (float)(2 * Math.PI / 5.0f);
const float idleZPeriod = (float)(2 * Math.PI / 3.5f);
/// <summary> Calculates the interpolated state between the last and next animation state. </summary>
protected void GetCurrentAnimState( float t ) {
float swing = Utils.Lerp( swingO, swingN, t );
float walkTime = Utils.Lerp( walkTimeO, walkTimeN, t );
float idleTime = (float)game.accumulator;
float idleXRot = (float)(Math.Sin( idleTime * idleXPeriod ) * idleMax);
float idleZRot = (float)(idleMax + Math.Cos(idleTime * idleZPeriod) * idleMax);
leftArmXRot = (float)(Math.Cos( walkTime ) * swing * armMax) - idleXRot;
rightArmXRot = -leftArmXRot;
rightLegXRot = (float)(Math.Cos( walkTime ) * swing * legMax);
leftLegXRot = -rightLegXRot;
rightArmZRot = idleZRot;
leftArmZRot = -idleZRot;
}
}
}

View File

@ -7,7 +7,7 @@ namespace ClassicalSharp {
public abstract class Entity { public abstract class Entity {
public Entity( Game game ) { public Entity( Game game ) {
map = game.Map; this.game = game;
info = game.BlockInfo; info = game.BlockInfo;
} }
@ -19,7 +19,7 @@ namespace ClassicalSharp {
public Vector3 Velocity; public Vector3 Velocity;
public float YawDegrees, PitchDegrees; public float YawDegrees, PitchDegrees;
protected float StepSize; protected float StepSize;
protected Map map; protected Game game;
protected BlockInfo info; protected BlockInfo info;
public float YawRadians { public float YawRadians {
@ -75,8 +75,8 @@ namespace ClassicalSharp {
for( int x = bbMin.X; x <= bbMax.X; x++ ) { for( int x = bbMin.X; x <= bbMax.X; x++ ) {
for( int y = bbMin.Y; y <= bbMax.Y; y++ ) { for( int y = bbMin.Y; y <= bbMax.Y; y++ ) {
for( int z = bbMin.Z; z <= bbMax.Z; z++ ) { for( int z = bbMin.Z; z <= bbMax.Z; z++ ) {
if( !map.IsValidPos( x, y, z ) ) continue; if( !game.Map.IsValidPos( x, y, z ) ) continue;
byte block = map.GetBlock( x, y, z ); byte block = game.Map.GetBlock( x, y, z );
if( condition( block ) ) { if( condition( block ) ) {
float blockHeight = info.Height[block]; float blockHeight = info.Height[block];
Vector3 min = new Vector3( x, y, z ); Vector3 min = new Vector3( x, y, z );

View File

@ -5,9 +5,10 @@ namespace ClassicalSharp {
public class EntityList : IDisposable { public class EntityList : IDisposable {
public int MaxCount = 256; public const int MaxCount = 256;
public Player[] Players = new Player[256]; public Player[] Players = new Player[MaxCount];
/// <summary> Performs a tick call for all player entities contained in this list. </summary>
public void Tick( double delta ) { public void Tick( double delta ) {
for( int i = 0; i < Players.Length; i++ ) { for( int i = 0; i < Players.Length; i++ ) {
if( Players[i] != null ) { if( Players[i] != null ) {
@ -16,6 +17,7 @@ namespace ClassicalSharp {
} }
} }
/// <summary> Renders all player entities contained in this list. </summary>
public void Render( double delta, float t ) { public void Render( double delta, float t ) {
for( int i = 0; i < Players.Length; i++ ) { for( int i = 0; i < Players.Length; i++ ) {
if( Players[i] != null ) { if( Players[i] != null ) {
@ -24,6 +26,7 @@ namespace ClassicalSharp {
} }
} }
/// <summary> Disposes of all player entities contained in this list. </summary>
public void Dispose() { public void Dispose() {
for( int i = 0; i < Players.Length; i++ ) { for( int i = 0; i < Players.Length; i++ ) {
if( Players[i] != null ) { if( Players[i] != null ) {
@ -52,6 +55,7 @@ namespace ClassicalSharp {
return targetId; return targetId;
} }
/// <summary> Gets or sets the player entity for the specified id. </summary>
public Player this[int id] { public Player this[int id] {
get { return Players[id]; } get { return Players[id]; }
set { set {

View File

@ -87,7 +87,7 @@ namespace ClassicalSharp {
InitRenderingData(); InitRenderingData();
game.AsyncDownloader.DownloadSkin( SkinName ); game.AsyncDownloader.DownloadSkin( SkinName );
} }
SetCurrentAnimState( t ); GetCurrentAnimState( t );
RenderModel( deltaTime ); RenderModel( deltaTime );
} }
@ -291,7 +291,7 @@ namespace ClassicalSharp {
for( int x = bbMin.X; x <= bbMax.X; x++ ) { for( int x = bbMin.X; x <= bbMax.X; x++ ) {
for( int y = bbMin.Y; y <= bbMax.Y; y++ ) { for( int y = bbMin.Y; y <= bbMax.Y; y++ ) {
for( int z = bbMin.Z; z <= bbMax.Z; z++ ) { for( int z = bbMin.Z; z <= bbMax.Z; z++ ) {
byte block = map.SafeGetBlock( x, y, z ); byte block = game.Map.SafeGetBlock( x, y, z );
if( block == 0 ) continue; if( block == 0 ) continue;
modifier = Math.Min( modifier, info.SpeedMultiplier[block] ); modifier = Math.Min( modifier, info.SpeedMultiplier[block] );

View File

@ -91,7 +91,7 @@ namespace ClassicalSharp {
YawDegrees = Utils.InterpAngle( oldState.yaw, newState.yaw, t ); YawDegrees = Utils.InterpAngle( oldState.yaw, newState.yaw, t );
PitchDegrees = Utils.InterpAngle( oldState.pitch, newState.pitch, t ); PitchDegrees = Utils.InterpAngle( oldState.pitch, newState.pitch, t );
SetCurrentAnimState( t ); GetCurrentAnimState( t );
RenderModel( deltaTime ); RenderModel( deltaTime );
} }
} }

View File

@ -4,6 +4,7 @@ using OpenTK;
namespace ClassicalSharp { namespace ClassicalSharp {
/// <summary> Entity that performs collision detection. </summary>
public abstract class PhysicsEntity : Entity { public abstract class PhysicsEntity : Entity {
public PhysicsEntity( Game game ) : base( game ) { public PhysicsEntity( Game game ) : base( game ) {
@ -11,9 +12,11 @@ namespace ClassicalSharp {
protected bool onGround, collideX, collideY, collideZ; protected bool onGround, collideX, collideY, collideZ;
protected byte GetPhysicsBlockId( int x, int y, int z ) { protected byte GetPhysicsBlockId( int x, int y, int z ) {
if( x < 0 || x >= map.Width || z < 0 || z >= map.Length || y < 0 ) return (byte)Block.Bedrock; if( x < 0 || x >= game.Map.Width || z < 0 ||
if( y >= map.Height ) return (byte)Block.Air; z >= game.Map.Length || y < 0 ) return (byte)Block.Bedrock;
return map.GetBlock( x, y, z );
if( y >= game.Map.Height ) return (byte)Block.Air;
return game.Map.GetBlock( x, y, z );
} }
bool GetBoundingBox( byte block, int x, int y, int z, out BoundingBox box ) { bool GetBoundingBox( byte block, int x, int y, int z, out BoundingBox box ) {

View File

@ -5,14 +5,13 @@ using OpenTK;
namespace ClassicalSharp { namespace ClassicalSharp {
public abstract partial class Player : PhysicsEntity { public abstract partial class Player : AnimatedEntity {
/// <summary> Gets the position of the player's eye in the world. </summary> /// <summary> Gets the position of the player's eye in the world. </summary>
public Vector3 EyePosition { public Vector3 EyePosition {
get { return new Vector3( Position.X, Position.Y + Model.GetEyeY( this ), Position.Z ); } get { return new Vector3( Position.X, Position.Y + Model.GetEyeY( this ), Position.Z ); }
} }
protected Game game;
public string DisplayName, SkinName; public string DisplayName, SkinName;
public SkinType SkinType; public SkinType SkinType;
@ -33,55 +32,15 @@ namespace ClassicalSharp {
get { return GetBlock( EyePosition ); } get { return GetBlock( EyePosition ); }
} }
Block GetBlock( Vector3 coords ) { protected Block GetBlock( Vector3 coords ) {
Vector3I p = Vector3I.Floor( coords ); Vector3I p = Vector3I.Floor( coords );
return (Block)map.SafeGetBlock( p.X, p.Y, p.Z ); return (Block)game.Map.SafeGetBlock( p.X, p.Y, p.Z );
} }
public abstract void Tick( double delta ); public abstract void Tick( double delta );
public abstract void SetLocation( LocationUpdate update, bool interpolate ); public abstract void SetLocation( LocationUpdate update, bool interpolate );
public float leftLegXRot, leftArmXRot, leftArmZRot;
public float rightLegXRot, rightArmXRot, rightArmZRot;
protected float walkTimeO, walkTimeN, swingO, swingN;
protected void UpdateAnimState( Vector3 oldPos, Vector3 newPos, double delta ) {
walkTimeO = walkTimeN;
swingO = swingN;
float dx = newPos.X - oldPos.X;
float dz = newPos.Z - oldPos.Z;
double distance = Math.Sqrt( dx * dx + dz * dz );
if( distance > 0.05 ) {
walkTimeN += (float)distance * 2 * (float)( 20 * delta );
swingN += (float)delta * 3;
} else {
swingN -= (float)delta * 3;
}
Utils.Clamp( ref swingN, 0, 1 );
}
const float armMax = 60 * Utils.Deg2Rad;
const float legMax = 80 * Utils.Deg2Rad;
const float idleMax = 3 * Utils.Deg2Rad;
const float idleXPeriod = (float)(2 * Math.PI / 5.0f);
const float idleZPeriod = (float)(2 * Math.PI / 3.5f);
protected void SetCurrentAnimState( float t ) {
float swing = Utils.Lerp( swingO, swingN, t );
float walkTime = Utils.Lerp( walkTimeO, walkTimeN, t );
float idleTime = (float)game.accumulator;
float idleXRot = (float)(Math.Sin( idleTime * idleXPeriod ) * idleMax);
float idleZRot = (float)(idleMax + Math.Cos(idleTime * idleZPeriod) * idleMax);
leftArmXRot = (float)(Math.Cos( walkTime ) * swing * armMax) - idleXRot;
rightArmXRot = -leftArmXRot;
rightLegXRot = (float)(Math.Cos( walkTime ) * swing * legMax);
leftLegXRot = -rightLegXRot;
rightArmZRot = idleZRot;
leftArmZRot = -idleZRot;
}
protected void CheckSkin() { protected void CheckSkin() {
DownloadedItem item; DownloadedItem item;
game.AsyncDownloader.TryGetItem( "skin_" + SkinName, out item ); game.AsyncDownloader.TryGetItem( "skin_" + SkinName, out item );
@ -117,7 +76,15 @@ namespace ClassicalSharp {
} }
unsafe bool HasHat( Bitmap bmp, SkinType skinType ) { 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 bool HasHat( Bitmap bmp, SkinType skinType ) {
using( FastBitmap fastBmp = new FastBitmap( bmp, true ) ) { using( FastBitmap fastBmp = new FastBitmap( bmp, true ) ) {
int sizeX = (bmp.Width / 64) * 32; int sizeX = (bmp.Width / 64) * 32;
int yScale = skinType == SkinType.Type64x32 ? 32 : 64; int yScale = skinType == SkinType.Type64x32 ? 32 : 64;
@ -138,13 +105,5 @@ namespace ClassicalSharp {
} }
return false; return false;
} }
DateTime lastModelChange = new DateTime( 1, 1, 1 );
public void SetModel( string modelName ) {
ModelName = modelName;
Model = game.ModelCache.GetModel( ModelName );
lastModelChange = DateTime.UtcNow;
MobTextureId = -1;
}
} }
} }

View File

@ -1,4 +1,5 @@
// This class was partially based on information from http://files.worldofminecraft.com/texturing/ // This class was partially based on information from http://files.worldofminecraft.com/texturing/
// NOTE: http://files.worldofminecraft.com/ has been down for quite a while, so support was removed on Oct 10, 2015
using System; using System;
using System.Drawing; using System.Drawing;
using System.IO; using System.IO;
@ -8,7 +9,7 @@ namespace ClassicalSharp {
public partial class NetworkProcessor { public partial class NetworkProcessor {
string womEnvIdentifier = "womenv_0", womTerrainIdentifier = "womterrain_0"; string womEnvIdentifier = "womenv_0";
int womCounter = 0; int womCounter = 0;
bool sendWomId = false, sentWomId = false; bool sendWomId = false, sentWomId = false;
@ -18,11 +19,6 @@ namespace ClassicalSharp {
if( item != null && item.Data != null ) { if( item != null && item.Data != null ) {
ParseWomConfig( (string)item.Data ); ParseWomConfig( (string)item.Data );
} }
game.AsyncDownloader.TryGetItem( womTerrainIdentifier, out item );
if( item != null && item.Data != null ) {
game.ChangeTerrainAtlas( (Bitmap)item.Data );
}
} }
void ParseWomConfig( string page ) { void ParseWomConfig( string page ) {
@ -48,12 +44,6 @@ namespace ClassicalSharp {
int waterLevel = 0; int waterLevel = 0;
if( Int32.TryParse( value, out waterLevel ) ) if( Int32.TryParse( value, out waterLevel ) )
game.Map.SetWaterLevel( waterLevel ); game.Map.SetWaterLevel( waterLevel );
} else if( key == "environment.terrain" ) {
GetWomImageAsync( "terrain", value );
} else if( key == "environment.edge" ) { // TODO: custom edges and sides
//GetWomImageAsync( "edge", value );
} else if( key == "environment.side" ) {
//GetWomImageAsync( "side", value );
} else if( key == "user.detail" && !useMessageTypes ) { } else if( key == "user.detail" && !useMessageTypes ) {
game.Chat.Add( value, CpeMessage.Status2 ); game.Chat.Add( value, CpeMessage.Status2 );
} }
@ -61,13 +51,6 @@ namespace ClassicalSharp {
} }
} }
void GetWomImageAsync( string type, string id ) {
const string hostFormat = "http://files.worldofminecraft.com/skin.php?type={0}&id={1}";
string url = String.Format( hostFormat, type, Uri.EscapeDataString( id ) );
string identifier = "wom" + type + "_" + womCounter;
game.AsyncDownloader.DownloadImage( url, true, identifier );
}
void ReadWomConfigurationAsync() { void ReadWomConfigurationAsync() {
string host = ServerMotd.Substring( ServerMotd.IndexOf( "cfg=" ) + 4 ); string host = ServerMotd.Substring( ServerMotd.IndexOf( "cfg=" ) + 4 );
string url = "http://" + host; string url = "http://" + host;
@ -77,7 +60,6 @@ namespace ClassicalSharp {
// new world if the async 'get request' didn't complete before the new world was loaded. // new world if the async 'get request' didn't complete before the new world was loaded.
womCounter++; womCounter++;
womEnvIdentifier = "womenv_" + womCounter; womEnvIdentifier = "womenv_" + womCounter;
womTerrainIdentifier = "womterrain_" + womCounter;
game.AsyncDownloader.DownloadPage( url, true, womEnvIdentifier ); game.AsyncDownloader.DownloadPage( url, true, womEnvIdentifier );
sendWomId = true; sendWomId = true;
} }