Merge branch 'master' of github.com:UnknownShadow200/ClassicalSharp

This commit is contained in:
UnknownShadow200 2016-05-09 10:37:12 +10:00
commit 7271985f13
61 changed files with 794 additions and 437 deletions

View File

@ -246,7 +246,7 @@ namespace ClassicalSharp.Gui {
public override void Dispose() { public override void Dispose() {
if( HandlesAllInput ) { if( HandlesAllInput ) {
game.chatInInputBuffer = textInput.chatInputText.ToString(); game.chatInInputBuffer = textInput.buffer.ToString();
game.CursorVisible = false; game.CursorVisible = false;
} else { } else {
game.chatInInputBuffer = null; game.chatInInputBuffer = null;
@ -321,8 +321,8 @@ namespace ClassicalSharp.Gui {
HandlesAllInput = true; HandlesAllInput = true;
game.Keyboard.KeyRepeat = true; game.Keyboard.KeyRepeat = true;
textInput.chatInputText.Clear(); textInput.buffer.Clear();
textInput.chatInputText.Append( 0, initialText ); textInput.buffer.Append( 0, initialText );
textInput.Init(); textInput.Init();
} }

View File

@ -58,6 +58,7 @@ namespace ClassicalSharp.Gui {
string connectString = "Connecting to " + game.IPAddress + ":" + game.Port + ".."; string connectString = "Connecting to " + game.IPAddress + ":" + game.Port + "..";
foreach( IGameComponent comp in game.Components ) foreach( IGameComponent comp in game.Components )
comp.Reset( game ); comp.Reset( game );
game.BlockInfo.Reset( game );
game.SetNewScreen( new LoadingMapScreen( game, connectString, "Waiting for handshake" ) ); game.SetNewScreen( new LoadingMapScreen( game, connectString, "Waiting for handshake" ) );
game.Network.Connect( game.IPAddress, game.Port ); game.Network.Connect( game.IPAddress, game.Port );

View File

@ -22,18 +22,18 @@ namespace ClassicalSharp.Gui {
textFont = new Font( game.FontName, 16, FontStyle.Bold ); textFont = new Font( game.FontName, 16, FontStyle.Bold );
arrowFont = new Font( game.FontName, 18, FontStyle.Bold ); arrowFont = new Font( game.FontName, 18, FontStyle.Bold );
titleFont = new Font( game.FontName, 16, FontStyle.Bold ); titleFont = new Font( game.FontName, 16, FontStyle.Bold );
title = ChatTextWidget.Create( game, 0, -130, titleText, title = ChatTextWidget.Create( game, 0, -155, titleText,
Anchor.Centre, Anchor.Centre, titleFont ); Anchor.Centre, Anchor.Centre, titleFont );
buttons = new ButtonWidget[] { buttons = new ButtonWidget[] {
MakeText( 0, -80, Get( 0 ) ), MakeText( 0, -100, Get( 0 ) ),
MakeText( 0, -40, Get( 1 ) ), MakeText( 0, -50, Get( 1 ) ),
MakeText( 0, 0, Get( 2 ) ), MakeText( 0, 0, Get( 2 ) ),
MakeText( 0, 40, Get( 3 ) ), MakeText( 0, 50, Get( 3 ) ),
MakeText( 0, 80, Get( 4 ) ), MakeText( 0, 100, Get( 4 ) ),
Make( -160, 0, "<", (g, w) => PageClick( false ) ), Make( -220, 0, "<", (g, w) => PageClick( false ) ),
Make( 160, 0, ">", (g, w) => PageClick( true ) ), Make( 220, 0, ">", (g, w) => PageClick( true ) ),
null, null,
}; };
} }
@ -52,12 +52,12 @@ namespace ClassicalSharp.Gui {
} }
ButtonWidget MakeText( int x, int y, string text ) { ButtonWidget MakeText( int x, int y, string text ) {
return ButtonWidget.Create( game, x, y, 240, 30, text, return ButtonWidget.Create( game, x, y, 301, 40, text,
Anchor.Centre, Anchor.Centre, textFont, TextButtonClick ); Anchor.Centre, Anchor.Centre, textFont, TextButtonClick );
} }
ButtonWidget Make( int x, int y, string text, Action<Game, Widget> onClick ) { ButtonWidget Make( int x, int y, string text, Action<Game, Widget> onClick ) {
return ButtonWidget.Create( game, x, y, 40, 40, text, return ButtonWidget.Create( game, x, y, 41, 40, text,
Anchor.Centre, Anchor.Centre, arrowFont, LeftOnly( onClick ) ); Anchor.Centre, Anchor.Centre, arrowFont, LeftOnly( onClick ) );
} }

View File

@ -6,7 +6,7 @@ using ClassicalSharp.GraphicsAPI;
namespace ClassicalSharp.Gui { namespace ClassicalSharp.Gui {
public class FpsScreen : Screen { public class FpsScreen : Screen, IGameComponent {
Font font, posFont; Font font, posFont;
StringBuffer text; StringBuffer text;
@ -15,6 +15,12 @@ namespace ClassicalSharp.Gui {
text = new StringBuffer( 128 ); text = new StringBuffer( 128 );
} }
public void Init( Game game ) { }
public void Ready( Game game) { Init(); }
public void Reset( Game game ) { }
public void OnNewMap( Game game ) { }
public void OnNewMapLoaded( Game game ) { }
TextWidget fpsText, hackStates; TextWidget fpsText, hackStates;
Texture posTex; Texture posTex;
public override void Render( double delta ) { public override void Render( double delta ) {
@ -158,7 +164,9 @@ namespace ClassicalSharp.Gui {
if( game.Fov != game.DefaultFov ) text.Append( ref index, "Zoom fov " ) if( game.Fov != game.DefaultFov ) text.Append( ref index, "Zoom fov " )
.AppendNum( ref index, lastFov ).Append( ref index, " " ); .AppendNum( ref index, lastFov ).Append( ref index, " " );
if( fly ) text.Append( ref index, "Fly ON " ); if( fly ) text.Append( ref index, "Fly ON " );
if( speeding || halfSpeeding ) text.Append( ref index, "Speed ON " );
bool showSpeedMsg = (speeding || halfSpeeding) && hacks.MaxSpeedMultiplier > 1;
if( showSpeedMsg ) text.Append( ref index, "Speed ON " );
if( noclip ) text.Append( ref index, "Noclip ON " ); if( noclip ) text.Append( ref index, "Noclip ON " );
hackStates.SetText( text.GetString() ); hackStates.SetText( text.GetString() );
} }
@ -166,7 +174,7 @@ namespace ClassicalSharp.Gui {
const string possibleChars = "0123456789-, ()"; const string possibleChars = "0123456789-, ()";
int[] widths = new int[possibleChars.Length]; int[] widths = new int[possibleChars.Length];
int baseWidth, curX, posHeight; int baseWidth, curX;
float texWidth; float texWidth;
void MakePosTextWidget() { void MakePosTextWidget() {
DrawTextArgs args = new DrawTextArgs( "", posFont, true ); DrawTextArgs args = new DrawTextArgs( "", posFont, true );

View File

@ -15,7 +15,8 @@ namespace ClassicalSharp.Gui {
PlayerListWidget playerList; PlayerListWidget playerList;
Font playerFont; Font playerFont;
public void Init( Game game ) { Init(); } public void Init( Game game ) { }
public void Ready( Game game) { Init(); }
public void Reset( Game game ) { } public void Reset( Game game ) { }
public void OnNewMap( Game game ) { } public void OnNewMap( Game game ) { }
public void OnNewMapLoaded( Game game ) { } public void OnNewMapLoaded( Game game ) { }
@ -35,7 +36,7 @@ namespace ClassicalSharp.Gui {
//graphicsApi.BindTexture( game.TerrainAtlas.TexId ); //graphicsApi.BindTexture( game.TerrainAtlas.TexId );
//IsometricBlockDrawer.Draw( game, (byte)Block.Brick, 30, game.Width - 50, game.Height - 20 ); //IsometricBlockDrawer.Draw( game, (byte)Block.Brick, 30, game.Width - 50, game.Height - 20 );
if( playerList != null ) { if( playerList != null && game.ActiveScreen == this ) {
playerList.Render( delta ); playerList.Render( delta );
// NOTE: Should usually be caught by KeyUp, but just in case. // NOTE: Should usually be caught by KeyUp, but just in case.
if( !game.IsKeyDown( KeyBinding.PlayerList ) ) { if( !game.IsKeyDown( KeyBinding.PlayerList ) ) {
@ -76,8 +77,6 @@ namespace ClassicalSharp.Gui {
} }
public void LoseFocus() { public void LoseFocus() {
if( playerList != null )
playerList.Dispose();
game.CursorVisible = true; game.CursorVisible = true;
} }

View File

@ -132,20 +132,12 @@ namespace ClassicalSharp.Gui {
RecreateBlockInfoTexture(); RecreateBlockInfoTexture();
} }
static string[] normalNames = null; void UpdateBlockInfoString( Block block ) {
void UpdateBlockInfoString( Block block ) {
if( normalNames == null )
MakeNormalNames();
int index = 0; int index = 0;
buffer.Clear(); buffer.Clear();
buffer.Append( ref index, "&f" ); buffer.Append( ref index, "&f" );
string value = game.BlockInfo.Name[(byte)block]; string value = game.BlockInfo.GetBlockName( (byte)block );
if( (byte)block < BlockInfo.CpeBlocksCount && value == "Invalid" ) { buffer.Append( ref index, value );
buffer.Append( ref index, normalNames[(byte)block] );
} else {
buffer.Append( ref index, value );
}
if( game.ClassicMode ) return; if( game.ClassicMode ) return;
buffer.Append( ref index, " (ID: " ); buffer.Append( ref index, " (ID: " );
@ -157,32 +149,6 @@ namespace ClassicalSharp.Gui {
buffer.Append( ref index, "&f)" ); buffer.Append( ref index, "&f)" );
} }
void MakeNormalNames() {
normalNames = new string[BlockInfo.CpeBlocksCount];
for( int i = 0; i < normalNames.Length; i++ ) {
string origName = Enum.GetName( typeof(Block), (byte)i );
buffer.Clear();
int index = 0;
SplitUppercase( origName, ref index );
normalNames[i] = buffer.ToString();
}
}
void SplitUppercase( string value, ref int index ) {
for( int i = 0; i < value.Length; i++ ) {
char c = value[i];
bool upper = Char.IsUpper( c ) && i > 0;
bool nextLower = i < value.Length - 1 && !Char.IsUpper( value[i + 1] );
if( upper && nextLower ) {
buffer.Append( ref index, ' ' );
buffer.Append( ref index, Char.ToLower( c ) );
} else {
buffer.Append( ref index, c );
}
}
}
int lastCreatedIndex = -1000; int lastCreatedIndex = -1000;
void RecreateBlockInfoTexture() { void RecreateBlockInfoTexture() {
if( selIndex == lastCreatedIndex ) return; if( selIndex == lastCreatedIndex ) return;

View File

@ -14,29 +14,31 @@ namespace ClassicalSharp.Gui {
MenuInputWidget inputWidget; MenuInputWidget inputWidget;
TextWidget descWidget; TextWidget descWidget;
const int overwriteIndex = 2;
FastColour grey = new FastColour( 150, 150, 150 );
public override void Render( double delta ) { public override void Render( double delta ) {
RenderMenuBounds(); RenderMenuBounds();
api.Texturing = true; api.Texturing = true;
RenderMenuWidgets( delta ); RenderMenuWidgets( delta );
inputWidget.Render( delta ); inputWidget.Render( delta );
if( descWidget != null ) if( descWidget != null ) descWidget.Render( delta );
descWidget.Render( delta );
api.Texturing = false; api.Texturing = false;
if( textPath != null ) { float cX = game.Width / 2, cY = game.Height / 2;
SaveMap( textPath ); api.Draw2DQuad( cX - 250, cY + 90, 500, 2, grey );
textPath = null; if( textPath == null ) return;
} SaveMap( textPath );
textPath = null;
} }
public override bool HandlesKeyPress( char key ) { public override bool HandlesKeyPress( char key ) {
RemoveOverwriteButton(); RemoveOverwrites();
return inputWidget.HandlesKeyPress( key ); return inputWidget.HandlesKeyPress( key );
} }
public override bool HandlesKeyDown( Key key ) { public override bool HandlesKeyDown( Key key ) {
RemoveOverwriteButton(); RemoveOverwrites();
if( key == Key.Escape ) { if( key == Key.Escape ) {
game.SetNewScreen( null ); game.SetNewScreen( null );
return true; return true;
@ -54,12 +56,16 @@ namespace ClassicalSharp.Gui {
regularFont = new Font( game.FontName, 16, FontStyle.Regular ); regularFont = new Font( game.FontName, 16, FontStyle.Regular );
inputWidget = MenuInputWidget.Create( inputWidget = MenuInputWidget.Create(
game, -30, 50, 500, 30, "", Anchor.Centre, Anchor.Centre, game, 0, -30, 500, 30, "", Anchor.Centre, Anchor.Centre,
regularFont, titleFont, new PathValidator() ); regularFont, titleFont, new PathValidator() );
widgets = new [] { widgets = new Widget[] {
ButtonWidget.Create( game, 260, 50, 60, 30, "Save", Anchor.Centre, ButtonWidget.Create( game, 0, 20, 301, 40, "Save", Anchor.Centre,
Anchor.Centre, titleFont, OkButtonClick ), Anchor.Centre, titleFont, SaveClassic ),
ButtonWidget.Create( game, -150, 120, 201, 40, "Save schematic", Anchor.Centre,
Anchor.Centre, titleFont, SaveSchematic ),
ChatTextWidget.Create( game, 110, 120, "&eCan be imported into MCedit", Anchor.Centre,
Anchor.Centre, regularFont ),
null, null,
MakeBack( false, titleFont, MakeBack( false, titleFont,
(g, w) => g.SetNewScreen( new PauseScreen( g ) ) ), (g, w) => g.SetNewScreen( new PauseScreen( g ) ) ),
@ -79,54 +85,58 @@ namespace ClassicalSharp.Gui {
base.Dispose(); base.Dispose();
} }
void OkButtonClick( Game game, Widget widget, MouseButton mouseBtn ) { void SaveClassic( Game game, Widget widget, MouseButton mouseBtn ) {
DoSave( widget, mouseBtn, ".cw" );
}
void SaveSchematic( Game game, Widget widget, MouseButton mouseBtn ) {
DoSave( widget, mouseBtn, ".schematic" );
}
void DoSave( Widget widget, MouseButton mouseBtn, string ext ) {
if( mouseBtn != MouseButton.Left ) return; if( mouseBtn != MouseButton.Left ) return;
string text = inputWidget.GetText(); string text = inputWidget.GetText();
if( text.Length == 0 ) { if( text.Length == 0 ) {
MakeDescWidget( "Please enter a filename" ); MakeDescWidget( "&ePlease enter a filename" ); return;
return;
} }
string file = Path.ChangeExtension( text, ".cw" ); string file = Path.ChangeExtension( text, ext );
text = Path.Combine( Program.AppDirectory, "maps" ); text = Path.Combine( Program.AppDirectory, "maps" );
text = Path.Combine( text, file ); text = Path.Combine( text, file );
if( File.Exists( text ) ) { if( File.Exists( text ) && widget.Metadata == null ) {
widgets[1] = ButtonWidget.Create( game, 0, 90, 260, 30, "Overwrite existing?", ((ButtonWidget)widget).SetText( "&cOverwrite existing?" );
Anchor.Centre, Anchor.Centre, titleFont, OverwriteButtonClick ); ((ButtonWidget)widget).Metadata = true;
} else { } else {
// NOTE: We don't immediately save here, because otherwise the 'saving...' // NOTE: We don't immediately save here, because otherwise the 'saving...'
// will not be rendered in time because saving is done on the main thread. // will not be rendered in time because saving is done on the main thread.
MakeDescWidget( "Saving.." ); MakeDescWidget( "Saving.." );
textPath = text; textPath = text;
RemoveOverwriteButton(); RemoveOverwrites();
} }
} }
void OverwriteButtonClick( Game game, Widget widget, MouseButton mouseBtn ) { void RemoveOverwrites() {
if( mouseBtn != MouseButton.Left ) return; RemoveOverwrite( widgets[0] ); RemoveOverwrite( widgets[1] );
string text = inputWidget.GetText();
string file = Path.ChangeExtension( text, ".cw" );
text = Path.Combine( Program.AppDirectory, "maps" );
text = Path.Combine( text, file );
MakeDescWidget( "Saving.." );
textPath = text;
RemoveOverwriteButton();
} }
void RemoveOverwriteButton() { void RemoveOverwrite( Widget widget ) {
if( widgets[1] == null ) return; ButtonWidget button = (ButtonWidget)widget;
widgets[1].Dispose(); if( button.Metadata == null ) return;
widgets[1] = null; button.Metadata = null;
button.SetText( "Save" );
} }
string textPath; string textPath;
void SaveMap( string path ) { void SaveMap( string path ) {
bool classic = path.EndsWith( ".cw" );
try { try {
if( File.Exists( path ) ) if( File.Exists( path ) )
File.Delete( path ); File.Delete( path );
using( FileStream fs = new FileStream( path, FileMode.CreateNew, FileAccess.Write ) ) { using( FileStream fs = new FileStream( path, FileMode.CreateNew, FileAccess.Write ) ) {
IMapFormatExporter exporter = new MapCwExporter(); IMapFormatExporter exporter = null;
if( classic ) exporter = new MapCwExporter();
else exporter = new MapSchematicExporter();
exporter.Save( fs, game ); exporter.Save( fs, game );
} }
} catch( Exception ex ) { } catch( Exception ex ) {
@ -140,7 +150,7 @@ namespace ClassicalSharp.Gui {
void MakeDescWidget( string text ) { void MakeDescWidget( string text ) {
DisposeDescWidget(); DisposeDescWidget();
descWidget = ChatTextWidget.Create( game, 0, 90, text, descWidget = ChatTextWidget.Create( game, 0, 65, text,
Anchor.Centre, Anchor.Centre, regularFont ); Anchor.Centre, Anchor.Centre, regularFont );
} }

View File

@ -90,15 +90,11 @@ namespace ClassicalSharp.Gui {
} }
public int GetUsedHeight() { public int GetUsedHeight() {
int sum = 0, max = Textures.Length; int sum = 0;
for( int i = 0; i < Textures.Length; i++ ) { for( int i = 0; i < Textures.Length; i++ ) {
if( Textures[i].IsValid ) { if( !Textures[i].IsValid ) continue;
max = i; break;
}
}
for( int i = max; i < Textures.Length; i++ )
sum += Textures[i].Height; sum += Textures[i].Height;
}
return sum; return sum;
} }

View File

@ -44,9 +44,9 @@ namespace ClassicalSharp.Gui {
} }
void TabKey() { void TabKey() {
int pos = caretPos == -1 ? chatInputText.Length - 1 : caretPos; int pos = caretPos == -1 ? buffer.Length - 1 : caretPos;
int start = pos; int start = pos;
char[] value = chatInputText.value; char[] value = buffer.value;
while( start >= 0 && IsNameChar( value[start] ) ) while( start >= 0 && IsNameChar( value[start] ) )
start--; start--;
@ -74,63 +74,76 @@ namespace ClassicalSharp.Gui {
if( caretPos == -1 ) pos++; if( caretPos == -1 ) pos++;
int len = pos - start; int len = pos - start;
for( int i = 0; i < len; i++ ) for( int i = 0; i < len; i++ )
chatInputText.DeleteAt( start ); buffer.DeleteAt( start );
if( caretPos != -1 ) caretPos -= len; if( caretPos != -1 ) caretPos -= len;
AppendText( matches[0] ); AppendText( matches[0] );
} else if( matches.Count > 1 ) { } else if( matches.Count > 1 ) {
StringBuffer buffer = new StringBuffer( 64 ); StringBuffer sb = new StringBuffer( 64 );
int index = 0; int index = 0;
buffer.Append( ref index, "&e" ); sb.Append( ref index, "&e" );
buffer.AppendNum( ref index, matches.Count ); sb.AppendNum( ref index, matches.Count );
buffer.Append( ref index, " matching names: " ); sb.Append( ref index, " matching names: " );
foreach( string match in matches ) { foreach( string match in matches ) {
if( (match.Length + 1 + buffer.Length) > LineLength ) break; if( (match.Length + 1 + sb.Length) > LineLength ) break;
buffer.Append( ref index, match ); sb.Append( ref index, match );
buffer.Append( ref index, ' ' ); sb.Append( ref index, ' ' );
} }
game.Chat.Add( buffer.ToString(), MessageType.ClientStatus5 ); game.Chat.Add( sb.ToString(), MessageType.ClientStatus5 );
} }
} }
bool IsNameChar( char c ) { bool IsNameChar( char c ) {
return c == '_' || c == '.' || (c >= '0' && c <= '9') return c == '_' || c == '.' || (c >= '0' && c <= '9')
|| (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
} }
void BackspaceKey( bool controlDown ) { void BackspaceKey( bool controlDown ) {
if( controlDown ) { if( controlDown ) {
if( caretPos == -1 ) if( caretPos == -1 )
caretPos = chatInputText.Length - 1; caretPos = buffer.Length - 1;
int len = chatInputText.GetBackLength( caretPos ); int len = buffer.GetBackLength( caretPos );
caretPos -= len; caretPos -= len;
if( caretPos < 0 ) caretPos = 0; if( caretPos < 0 ) caretPos = 0;
if( caretPos != 0 ) caretPos++; // Don't remove space. if( caretPos != 0 ) caretPos++; // Don't remove space.
for( int i = 0; i <= len; i++ ) for( int i = 0; i <= len; i++ )
chatInputText.DeleteAt( caretPos ); buffer.DeleteAt( caretPos );
Dispose(); Dispose();
Init(); Init();
return; } else if( !buffer.Empty && caretPos != 0 ) {
} DeleteChar();
BackspaceColourCode();
if( !chatInputText.Empty && caretPos != 0 ) {
if( caretPos == -1 ) {
chatInputText.DeleteAt( chatInputText.Length - 1 );
} else {
caretPos--;
chatInputText.DeleteAt( caretPos );
}
Dispose(); Dispose();
Init(); Init();
} }
} }
void BackspaceColourCode() {
// If text is XYZ%eH, backspaces to XYZ.
int index = caretPos == -1 ? buffer.Length - 1 : caretPos;
if( index <= 0 ) return;
if( index == 0 || buffer.value[index - 1] != '%'
|| !game.Drawer2D.ValidColour( buffer.value[index] ) )
return;
DeleteChar(); DeleteChar();
}
void DeleteChar() {
if( caretPos == -1 ) {
buffer.DeleteAt( buffer.Length - 1 );
} else {
caretPos--;
buffer.DeleteAt( caretPos );
}
}
void DeleteKey() { void DeleteKey() {
if( !chatInputText.Empty && caretPos != -1 ) { if( !buffer.Empty && caretPos != -1 ) {
chatInputText.DeleteAt( caretPos ); buffer.DeleteAt( caretPos );
if( caretPos >= chatInputText.Length ) caretPos = -1; if( caretPos >= buffer.Length ) caretPos = -1;
Dispose(); Dispose();
Init(); Init();
} }
@ -139,14 +152,14 @@ namespace ClassicalSharp.Gui {
void LeftKey( bool controlDown ) { void LeftKey( bool controlDown ) {
if( controlDown ) { if( controlDown ) {
if( caretPos == -1 ) if( caretPos == -1 )
caretPos = chatInputText.Length - 1; caretPos = buffer.Length - 1;
caretPos -= chatInputText.GetBackLength( caretPos ); caretPos -= buffer.GetBackLength( caretPos );
CalculateCaretData(); CalculateCaretData();
return; return;
} }
if( !chatInputText.Empty ) { if( !buffer.Empty ) {
if( caretPos == -1 ) caretPos = chatInputText.Length; if( caretPos == -1 ) caretPos = buffer.Length;
caretPos--; caretPos--;
if( caretPos < 0 ) caretPos = 0; if( caretPos < 0 ) caretPos = 0;
CalculateCaretData(); CalculateCaretData();
@ -155,15 +168,15 @@ namespace ClassicalSharp.Gui {
void RightKey( bool controlDown ) { void RightKey( bool controlDown ) {
if( controlDown ) { if( controlDown ) {
caretPos += chatInputText.GetForwardLength( caretPos ); caretPos += buffer.GetForwardLength( caretPos );
if( caretPos >= chatInputText.Length ) caretPos = -1; if( caretPos >= buffer.Length ) caretPos = -1;
CalculateCaretData(); CalculateCaretData();
return; return;
} }
if( !chatInputText.Empty && caretPos != -1 ) { if( !buffer.Empty && caretPos != -1 ) {
caretPos++; caretPos++;
if( caretPos >= chatInputText.Length ) caretPos = -1; if( caretPos >= buffer.Length ) caretPos = -1;
CalculateCaretData(); CalculateCaretData();
} }
} }
@ -171,7 +184,7 @@ namespace ClassicalSharp.Gui {
string originalText; string originalText;
void UpKey( bool controlDown ) { void UpKey( bool controlDown ) {
if( controlDown ) { if( controlDown ) {
int pos = caretPos == -1 ? chatInputText.Length : caretPos; int pos = caretPos == -1 ? buffer.Length : caretPos;
if( pos < LineLength ) return; if( pos < LineLength ) return;
caretPos = pos - LineLength; caretPos = pos - LineLength;
@ -180,12 +193,12 @@ namespace ClassicalSharp.Gui {
} }
if( typingLogPos == game.Chat.InputLog.Count ) if( typingLogPos == game.Chat.InputLog.Count )
originalText = chatInputText.ToString(); originalText = buffer.ToString();
if( game.Chat.InputLog.Count > 0 ) { if( game.Chat.InputLog.Count > 0 ) {
typingLogPos--; typingLogPos--;
if( typingLogPos < 0 ) typingLogPos = 0; if( typingLogPos < 0 ) typingLogPos = 0;
chatInputText.Clear(); buffer.Clear();
chatInputText.Append( 0, game.Chat.InputLog[typingLogPos] ); buffer.Append( 0, game.Chat.InputLog[typingLogPos] );
caretPos = -1; caretPos = -1;
Dispose(); Dispose();
Init(); Init();
@ -202,13 +215,13 @@ namespace ClassicalSharp.Gui {
if( game.Chat.InputLog.Count > 0 ) { if( game.Chat.InputLog.Count > 0 ) {
typingLogPos++; typingLogPos++;
chatInputText.Clear(); buffer.Clear();
if( typingLogPos >= game.Chat.InputLog.Count ) { if( typingLogPos >= game.Chat.InputLog.Count ) {
typingLogPos = game.Chat.InputLog.Count; typingLogPos = game.Chat.InputLog.Count;
if( originalText != null ) if( originalText != null )
chatInputText.Append( 0, originalText ); buffer.Append( 0, originalText );
} else { } else {
chatInputText.Append( 0, game.Chat.InputLog[typingLogPos] ); buffer.Append( 0, game.Chat.InputLog[typingLogPos] );
} }
caretPos = -1; caretPos = -1;
Dispose(); Dispose();
@ -217,7 +230,7 @@ namespace ClassicalSharp.Gui {
} }
void HomeKey() { void HomeKey() {
if( chatInputText.Empty ) return; if( buffer.Empty ) return;
caretPos = 0; caretPos = 0;
CalculateCaretData(); CalculateCaretData();
} }
@ -228,7 +241,7 @@ namespace ClassicalSharp.Gui {
} }
bool OtherKey( Key key ) { bool OtherKey( Key key ) {
if( key == Key.V && chatInputText.Length < TotalChars ) { if( key == Key.V && buffer.Length < TotalChars ) {
string text = null; string text = null;
try { try {
text = game.window.ClipboardText; text = game.window.ClipboardText;
@ -252,9 +265,9 @@ namespace ClassicalSharp.Gui {
AppendText( text ); AppendText( text );
return true; return true;
} else if( key == Key.C ) { } else if( key == Key.C ) {
if( chatInputText.Empty ) return true; if( buffer.Empty ) return true;
try { try {
game.window.ClipboardText = chatInputText.ToString(); game.window.ClipboardText = buffer.ToString();
} catch( Exception ex ) { } catch( Exception ex ) {
ErrorHandler.LogError( "Copy to clipboard", ex ); ErrorHandler.LogError( "Copy to clipboard", ex );
const string warning = "&cError while trying to copy to clipboard."; const string warning = "&cError while trying to copy to clipboard.";

View File

@ -12,7 +12,7 @@ namespace ClassicalSharp.Gui {
HorizontalAnchor = Anchor.LeftOrTop; HorizontalAnchor = Anchor.LeftOrTop;
VerticalAnchor = Anchor.BottomOrRight; VerticalAnchor = Anchor.BottomOrRight;
typingLogPos = game.Chat.InputLog.Count; // Index of newest entry + 1. typingLogPos = game.Chat.InputLog.Count; // Index of newest entry + 1.
chatInputText = new WrappableStringBuffer( 64 * lines ); buffer = new WrappableStringBuffer( 64 * lines );
DrawTextArgs args = new DrawTextArgs( "_", boldFont, true ); DrawTextArgs args = new DrawTextArgs( "_", boldFont, true );
caretTex = game.Drawer2D.MakeChatTextTexture( ref args, 0, 0 ); caretTex = game.Drawer2D.MakeChatTextTexture( ref args, 0, 0 );
@ -35,7 +35,7 @@ namespace ClassicalSharp.Gui {
int caretPos = -1, typingLogPos = 0; int caretPos = -1, typingLogPos = 0;
public int YOffset; public int YOffset;
int defaultCaretWidth, defaultWidth, defaultHeight; int defaultCaretWidth, defaultWidth, defaultHeight;
internal WrappableStringBuffer chatInputText; internal WrappableStringBuffer buffer;
readonly Font font; readonly Font font;
FastColour caretCol; FastColour caretCol;
@ -72,7 +72,7 @@ namespace ClassicalSharp.Gui {
public override void Init() { public override void Init() {
X = 5; X = 5;
chatInputText.WordWrap( game.Drawer2D, ref parts, ref partLens, buffer.WordWrap( game.Drawer2D, ref parts, ref partLens,
LineLength, TotalChars ); LineLength, TotalChars );
for( int y = 0; y < sizes.Length; y++ ) for( int y = 0; y < sizes.Length; y++ )
@ -89,10 +89,10 @@ namespace ClassicalSharp.Gui {
if( sizes[0].Height == 0 ) sizes[0].Height = defaultHeight; if( sizes[0].Height == 0 ) sizes[0].Height = defaultHeight;
bool supports = game.Network.ServerSupportsPartialMessages; bool supports = game.Network.ServerSupportsPartialMessages;
if( chatInputText.Length > LineLength && !shownWarning && !supports ) { if( buffer.Length > LineLength && !shownWarning && !supports ) {
game.Chat.Add( "&eNote: Each line will be sent as a separate packet.", MessageType.ClientStatus6 ); game.Chat.Add( "&eNote: Each line will be sent as a separate packet.", MessageType.ClientStatus6 );
shownWarning = true; shownWarning = true;
} else if( chatInputText.Length <= LineLength && shownWarning ) { } else if( buffer.Length <= LineLength && shownWarning ) {
game.Chat.Add( null, MessageType.ClientStatus6 ); game.Chat.Add( null, MessageType.ClientStatus6 );
shownWarning = false; shownWarning = false;
} }
@ -104,8 +104,8 @@ namespace ClassicalSharp.Gui {
} }
void CalculateCaretData() { void CalculateCaretData() {
if( caretPos >= chatInputText.Length ) caretPos = -1; if( caretPos >= buffer.Length ) caretPos = -1;
chatInputText.MakeCoords( caretPos, partLens, out indexX, out indexY ); buffer.MakeCoords( caretPos, partLens, out indexX, out indexY );
DrawTextArgs args = new DrawTextArgs( null, font, true ); DrawTextArgs args = new DrawTextArgs( null, font, true );
if( indexX == LineLength ) { if( indexX == LineLength ) {
@ -204,7 +204,7 @@ namespace ClassicalSharp.Gui {
public void SendTextInBufferAndReset() { public void SendTextInBufferAndReset() {
SendInBuffer(); SendInBuffer();
typingLogPos = game.Chat.InputLog.Count; // Index of newest entry + 1. typingLogPos = game.Chat.InputLog.Count; // Index of newest entry + 1.
chatInputText.Clear(); buffer.Clear();
caretPos = -1; caretPos = -1;
Dispose(); Dispose();
Height = defaultHeight; Height = defaultHeight;
@ -216,8 +216,8 @@ namespace ClassicalSharp.Gui {
} }
void SendInBuffer() { void SendInBuffer() {
if( chatInputText.Empty ) return; if( buffer.Empty ) return;
string allText = chatInputText.GetString(); string allText = buffer.GetString();
game.Chat.InputLog.Add( allText ); game.Chat.InputLog.Add( allText );
if( game.Network.ServerSupportsPartialMessages ) if( game.Network.ServerSupportsPartialMessages )
@ -257,38 +257,38 @@ namespace ClassicalSharp.Gui {
} }
public void Clear() { public void Clear() {
chatInputText.Clear(); buffer.Clear();
for( int i = 0; i < parts.Length; i++ ) { for( int i = 0; i < parts.Length; i++ ) {
parts[i] = null; parts[i] = null;
} }
} }
public void AppendText( string text ) { public void AppendText( string text ) {
if( chatInputText.Length + text.Length > TotalChars ) { if( buffer.Length + text.Length > TotalChars ) {
text = text.Substring( 0, TotalChars - chatInputText.Length ); text = text.Substring( 0, TotalChars - buffer.Length );
} }
if( text == "" ) return; if( text == "" ) return;
if( caretPos == -1 ) { if( caretPos == -1 ) {
chatInputText.InsertAt( chatInputText.Length, text ); buffer.InsertAt( buffer.Length, text );
} else { } else {
chatInputText.InsertAt( caretPos, text ); buffer.InsertAt( caretPos, text );
caretPos += text.Length; caretPos += text.Length;
if( caretPos >= chatInputText.Length ) caretPos = -1; if( caretPos >= buffer.Length ) caretPos = -1;
} }
Dispose(); Dispose();
Init(); Init();
} }
public void AppendChar( char c ) { public void AppendChar( char c ) {
if( chatInputText.Length == TotalChars ) return; if( buffer.Length == TotalChars ) return;
if( caretPos == -1 ) { if( caretPos == -1 ) {
chatInputText.InsertAt( chatInputText.Length, c ); buffer.InsertAt( buffer.Length, c );
} else { } else {
chatInputText.InsertAt( caretPos, c ); buffer.InsertAt( caretPos, c );
caretPos++; caretPos++;
if( caretPos >= chatInputText.Length ) caretPos = -1; if( caretPos >= buffer.Length ) caretPos = -1;
} }
Dispose(); Dispose();
Init(); Init();

View File

@ -109,12 +109,12 @@ namespace ClassicalSharp.Gui {
public sealed class PathValidator : MenuInputValidator { public sealed class PathValidator : MenuInputValidator {
public PathValidator() { public PathValidator() {
Range = "&7(Enter filename)"; Range = "&7(Enter name)";
} }
public override bool IsValidChar( char c ) { public override bool IsValidChar( char c ) {
return !(c == '/' || c == '\\' || c == '?' || c == '*' || c == ':' return !(c == '/' || c == '\\' || c == '?' || c == '*' || c == ':'
|| c == '<' || c == '>' || c == '|' || c == '"'); || c == '<' || c == '>' || c == '|' || c == '"' || c == '.');
} }
public override bool IsValidString( string s ) { return true; } public override bool IsValidString( string s ) { return true; }

View File

@ -89,8 +89,8 @@ namespace ClassicalSharp.Gui {
base.Init(); base.Init();
if( !extList ) { if( !extList ) {
game.EntityEvents.EntityAdded += PlayerSpawned; game.EntityEvents.Added += PlayerSpawned;
game.EntityEvents.EntityRemoved += PlayerDespawned; game.EntityEvents.Removed += PlayerDespawned;
} else { } else {
game.EntityEvents.CpeListInfoAdded += PlayerListInfoAdded; game.EntityEvents.CpeListInfoAdded += PlayerListInfoAdded;
game.EntityEvents.CpeListInfoRemoved += PlayerDespawned; game.EntityEvents.CpeListInfoRemoved += PlayerDespawned;
@ -102,8 +102,8 @@ namespace ClassicalSharp.Gui {
base.Dispose(); base.Dispose();
overview.Dispose(); overview.Dispose();
if( !extList ) { if( !extList ) {
game.EntityEvents.EntityAdded -= PlayerSpawned; game.EntityEvents.Added -= PlayerSpawned;
game.EntityEvents.EntityRemoved -= PlayerDespawned; game.EntityEvents.Removed -= PlayerDespawned;
} else { } else {
game.EntityEvents.CpeListInfoAdded -= PlayerListInfoAdded; game.EntityEvents.CpeListInfoAdded -= PlayerListInfoAdded;
game.EntityEvents.CpeListInfoChanged -= PlayerListInfoChanged; game.EntityEvents.CpeListInfoChanged -= PlayerListInfoChanged;

View File

@ -27,14 +27,14 @@ namespace ClassicalSharp.Gui {
public override void Init() { public override void Init() {
base.Init(); base.Init();
game.EntityEvents.EntityAdded += PlayerSpawned; game.EntityEvents.Added += PlayerSpawned;
game.EntityEvents.EntityRemoved += PlayerDespawned; game.EntityEvents.Removed += PlayerDespawned;
} }
public override void Dispose() { public override void Dispose() {
base.Dispose(); base.Dispose();
game.EntityEvents.EntityAdded -= PlayerSpawned; game.EntityEvents.Added -= PlayerSpawned;
game.EntityEvents.EntityRemoved -= PlayerDespawned; game.EntityEvents.Removed -= PlayerDespawned;
} }
void PlayerSpawned( object sender, IdEventArgs e ) { void PlayerSpawned( object sender, IdEventArgs e ) {

View File

@ -25,7 +25,8 @@ namespace ClassicalSharp.Audio {
game.UseSound = Options.GetBool( OptionsKey.UseSound, false ); game.UseSound = Options.GetBool( OptionsKey.UseSound, false );
SetSound( game.UseSound ); SetSound( game.UseSound );
} }
public void Ready( Game game ) { }
public void Reset( Game game ) { } public void Reset( Game game ) { }
public void OnNewMap( Game game ) { } public void OnNewMap( Game game ) { }
public void OnNewMapLoaded( Game game ) { } public void OnNewMapLoaded( Game game ) { }

View File

@ -58,6 +58,40 @@ namespace ClassicalSharp {
public const byte MaxDefinedBlock = byte.MaxValue; public const byte MaxDefinedBlock = byte.MaxValue;
public const int BlocksCount = MaxDefinedBlock + 1; public const int BlocksCount = MaxDefinedBlock + 1;
public void Reset( Game game ) {
// Reset properties
for( int i = 0; i < IsTransparent.Length; i++ ) IsTransparent[i] = false;
for( int i = 0; i < IsTranslucent.Length; i++ ) IsTranslucent[i] = false;
for( int i = 0; i < IsOpaque.Length; i++ ) IsOpaque[i] = false;
for( int i = 0; i < IsOpaqueY.Length; i++ ) IsOpaqueY[i] = false;
for( int i = 0; i < IsSprite.Length; i++ ) IsSprite[i] = false;
for( int i = 0; i < IsLiquid.Length; i++ ) IsLiquid[i] = false;
for( int i = 0; i < BlocksLight.Length; i++ ) BlocksLight[i] = false;
for( int i = 0; i < FullBright.Length; i++ ) FullBright[i] = false;
for( int i = 0; i < Name.Length; i++ ) Name[i] = "Invalid";
for( int i = 0; i < FogColour.Length; i++ ) FogColour[i] = default(FastColour);
for( int i = 0; i < FogDensity.Length; i++ ) FogDensity[i] = 0;
for( int i = 0; i < Collide.Length; i++ ) Collide[i] = CollideType.WalkThrough;
for( int i = 0; i < SpeedMultiplier.Length; i++ ) SpeedMultiplier[i] = 0;
for( int i = 0; i < CullWithNeighbours.Length; i++ ) CullWithNeighbours[i] = false;
for( int i = 0; i < LightOffset.Length; i++ ) LightOffset[i] = 0;
for( int i = 0; i < DefinedCustomBlocks.Length; i++ ) DefinedCustomBlocks[i] = 0;
// Reset textures
texId = 0;
for( int i = 0; i < textures.Length; i++ ) textures[i] = 0;
// Reset culling
for( int i = 0; i < hidden.Length; i++ ) hidden[i] = 0;
for( int i = 0; i < CanStretch.Length; i++ ) CanStretch[i] = false;
for( int i = 0; i < IsAir.Length; i++ ) IsAir[i] = false;
// Reset bounds
for( int i = 0; i < MinBB.Length; i++ ) MinBB[i] = Vector3.Zero;
for( int i = 0; i < MaxBB.Length; i++ ) MaxBB[i] = Vector3.One;
// Reset sounds
for( int i = 0; i < DigSounds.Length; i++ ) DigSounds[i] = SoundType.None;
for( int i = 0; i < StepSounds.Length; i++ ) StepSounds[i] = SoundType.None;
Init();
}
public void Init() { public void Init() {
for( int tile = 1; tile < BlocksCount; tile++ ) { for( int tile = 1; tile < BlocksCount; tile++ ) {
MaxBB[tile].Y = 1; MaxBB[tile].Y = 1;
@ -106,7 +140,7 @@ namespace ClassicalSharp {
IsOpaqueY[(byte)Block.Snow] = true; IsOpaqueY[(byte)Block.Snow] = true;
InitBoundingBoxes(); InitBoundingBoxes();
InitSounds(); InitSounds();
SetupCullingCache(); SetupCullingCache();
InitLightOffsets(); InitLightOffsets();
} }
@ -189,6 +223,45 @@ namespace ClassicalSharp {
StepSounds[id] = SoundType.None; StepSounds[id] = SoundType.None;
DigSounds[id] = SoundType.None; DigSounds[id] = SoundType.None;
} }
internal static string[] normalNames = null;
public string GetBlockName( byte block ) {
if( normalNames == null )
MakeNormalNames();
string value = Name[block];
if( block < CpeBlocksCount && value == "Invalid" )
return normalNames[block];
return value;
}
static void MakeNormalNames() {
StringBuffer buffer = new StringBuffer( 64 );
normalNames = new string[CpeBlocksCount];
for( int i = 0; i < normalNames.Length; i++ ) {
string origName = Enum.GetName( typeof(Block), (byte)i );
buffer.Clear();
int index = 0;
SplitUppercase( buffer, origName, ref index );
normalNames[i] = buffer.ToString();
}
}
static void SplitUppercase( StringBuffer buffer, string value, ref int index ) {
for( int i = 0; i < value.Length; i++ ) {
char c = value[i];
bool upper = Char.IsUpper( c ) && i > 0;
bool nextLower = i < value.Length - 1 && !Char.IsUpper( value[i + 1] );
if( upper && nextLower ) {
buffer.Append( ref index, ' ' );
buffer.Append( ref index, Char.ToLower( c ) );
} else {
buffer.Append( ref index, c );
}
}
}
} }
public enum CollideType : byte { public enum CollideType : byte {

View File

@ -145,6 +145,7 @@
<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="Blocks\BlockInfo.Sounds.cs" /> <Compile Include="Blocks\BlockInfo.Sounds.cs" />
<Compile Include="Commands\SinglePlayerCommands.cs" />
<Compile Include="Entities\AI\AI.cs" /> <Compile Include="Entities\AI\AI.cs" />
<Compile Include="Entities\AI\FleeAI.cs" /> <Compile Include="Entities\AI\FleeAI.cs" />
<Compile Include="Entities\AI\HostileAI.cs" /> <Compile Include="Entities\AI\HostileAI.cs" />
@ -165,6 +166,7 @@
<Compile Include="Entities\NetPlayer.cs" /> <Compile Include="Entities\NetPlayer.cs" />
<Compile Include="Events\EntityEvents.cs" /> <Compile Include="Events\EntityEvents.cs" />
<Compile Include="Events\Events.cs" /> <Compile Include="Events\Events.cs" />
<Compile Include="Events\UserEvents.cs" />
<Compile Include="Events\WorldEvents.cs" /> <Compile Include="Events\WorldEvents.cs" />
<Compile Include="Game\Game.Properties.cs" /> <Compile Include="Game\Game.Properties.cs" />
<Compile Include="Game\PickingHandler.cs" /> <Compile Include="Game\PickingHandler.cs" />
@ -174,6 +176,7 @@
<Compile Include="Generator\NotchyGenerator.cs" /> <Compile Include="Generator\NotchyGenerator.cs" />
<Compile Include="Generator\NotchyGenerator.Utils.cs" /> <Compile Include="Generator\NotchyGenerator.Utils.cs" />
<Compile Include="GraphicsAPI\OpenGLESApi.cs" /> <Compile Include="GraphicsAPI\OpenGLESApi.cs" />
<Compile Include="Map\Formats\MapSchematic.Exporter.cs" />
<Compile Include="Map\Formats\MapLvl.Importer.cs" /> <Compile Include="Map\Formats\MapLvl.Importer.cs" />
<Compile Include="Map\Formats\NbtFile.cs" /> <Compile Include="Map\Formats\NbtFile.cs" />
<Compile Include="Math\RayTracer.cs" /> <Compile Include="Math\RayTracer.cs" />
@ -208,7 +211,7 @@
<Compile Include="Map\ChunkMeshBuilder.cs" /> <Compile Include="Map\ChunkMeshBuilder.cs" />
<Compile Include="Map\ChunkMeshBuilder.FloodFill.cs" /> <Compile Include="Map\ChunkMeshBuilder.FloodFill.cs" />
<Compile Include="Map\ChunkMeshBuilderTex2Col4.cs" /> <Compile Include="Map\ChunkMeshBuilderTex2Col4.cs" />
<Compile Include="Map\Formats\IMapFileFormat.cs" /> <Compile Include="Map\Formats\IMapFormat.cs" />
<Compile Include="Map\Formats\MapCw.Exporter.cs" /> <Compile Include="Map\Formats\MapCw.Exporter.cs" />
<Compile Include="Map\Formats\MapCw.Importer.cs" /> <Compile Include="Map\Formats\MapCw.Importer.cs" />
<Compile Include="Map\Formats\MapDat.Importer.cs" /> <Compile Include="Map\Formats\MapDat.Importer.cs" />

View File

@ -21,10 +21,14 @@ namespace ClassicalSharp.Commands {
Register( new HelpCommand() ); Register( new HelpCommand() );
Register( new InfoCommand() ); Register( new InfoCommand() );
Register( new RenderTypeCommand() ); Register( new RenderTypeCommand() );
if( game.Network.IsSinglePlayer )
if( game.Network.IsSinglePlayer ) {
Register( new ModelCommand() ); Register( new ModelCommand() );
Register( new CuboidCommand() );
}
} }
public void Ready( Game game ) { }
public void Reset( Game game ) { } public void Reset( Game game ) { }
public void OnNewMap( Game game ) { } public void OnNewMap( Game game ) { }
public void OnNewMapLoaded( Game game ) { } public void OnNewMapLoaded( Game game ) { }

View File

@ -150,25 +150,4 @@ namespace ClassicalSharp.Commands {
} }
} }
} }
public sealed class ModelCommand : Command {
public ModelCommand() {
Name = "Model";
Help = new [] {
"&a/client model [name]",
"&bnames: &echibi, chicken, creeper, human, pig, sheep",
"&e skeleton, spider, zombie, <numerical block id>",
};
}
public override void Execute( CommandReader reader ) {
string name = reader.Next();
if( String.IsNullOrEmpty( name ) ) {
game.Chat.Add( "&e/client model: &cYou didn't specify a model name." );
} else {
game.LocalPlayer.SetModel( name );
}
}
}
} }

View File

@ -0,0 +1,115 @@
// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT
using System;
using System.Collections.Generic;
using System.Text;
using ClassicalSharp.Events;
using ClassicalSharp.Renderers;
using OpenTK.Input;
namespace ClassicalSharp.Commands {
public sealed class ModelCommand : Command {
public ModelCommand() {
Name = "Model";
Help = new [] {
"&a/client model [name]",
"&bnames: &echibi, chicken, creeper, human, pig, sheep",
"&e skeleton, spider, zombie, <numerical block id>",
};
}
public override void Execute( CommandReader reader ) {
string name = reader.Next();
if( String.IsNullOrEmpty( name ) ) {
game.Chat.Add( "&e/client model: &cYou didn't specify a model name." );
} else {
game.LocalPlayer.SetModel( name );
}
}
}
public sealed class CuboidCommand : Command {
public CuboidCommand() {
Name = "Cuboid";
Help = new [] {
"&a/client cuboid [block] [persist]",
"&eFills the 3D rectangle between two points with [block].",
"&eIf no block is given, uses your currently held block.",
"&e If persist is given and is \"yes\", then the command",
"&e will repeatedly cuboid, without needing to be typed in again.",
};
}
byte block = 0xFF;
Vector3I mark1, mark2;
bool persist = false;
public override void Execute( CommandReader reader ) {
game.UserEvents.BlockChanged -= BlockChanged;
block = 0xFF;
mark1 = new Vector3I( int.MaxValue );
mark2 = new Vector3I( int.MaxValue );
persist = false;
if( !ParseBlock( reader ) ) return;
string arg = reader.Next();
if( arg != null && Utils.CaselessEquals( arg, "yes" ) )
persist = true;
game.Chat.Add( "&eCuboid: &fPlace or delete a block.", MessageType.ClientStatus3 );
game.UserEvents.BlockChanged += BlockChanged;
}
bool ParseBlock( CommandReader reader ) {
string id = reader.Next();
if( id == null ) return true;
if( Utils.CaselessEquals( id, "yes" ) ) { persist = true; return true; }
byte blockID = 0;
if( !byte.TryParse( id, out blockID ) ) {
game.Chat.Add( "&eCuboid: &c\"" + id + "\" is not a valid block id." ); return false;
}
if( blockID >= BlockInfo.CpeBlocksCount && game.BlockInfo.Name[blockID] == "Invalid" ) {
game.Chat.Add( "&eCuboid: &cThere is no block with id \"" + id + "\"." ); return false;
}
block = blockID;
return true;
}
void BlockChanged( object sender, BlockChangedEventArgs e ) {
if( mark1.X == int.MaxValue ) {
mark1 = e.Coords;
game.UpdateBlock( mark1.X, mark1.Y, mark1.Z, e.OldBlock );
game.Chat.Add( "&eCuboid: &fMark 1 placed at (" + e.Coords + "), place mark 2.",
MessageType.ClientStatus3 );
} else {
mark2 = e.Coords;
DoCuboid();
game.Chat.Add( null, MessageType.ClientStatus3 );
if( !persist ) {
game.UserEvents.BlockChanged -= BlockChanged;
} else {
mark1 = new Vector3I( int.MaxValue );
game.Chat.Add( "&eCuboid: &fPlace or delete a block.", MessageType.ClientStatus3 );
}
}
}
void DoCuboid() {
Vector3I min = Vector3I.Min( mark1, mark2 );
Vector3I max = Vector3I.Max( mark1, mark2 );
if( !game.World.IsValidPos( min ) || !game.World.IsValidPos( max ) ) return;
byte id = block;
if( id == 0xFF ) id = (byte)game.Inventory.HeldBlock;
for( int y = min.Y; y <= max.Y; y++ )
for( int z = min.Z; z <= max.Z; z++ )
for( int x = min.X; x <= max.X; x++ )
{
game.UpdateBlock( x, y, z, id );
}
}
}
}

View File

@ -98,7 +98,7 @@ namespace ClassicalSharp.Entities {
} }
void TextureChanged( object sender, TextureEventArgs e ) { void TextureChanged( object sender, TextureEventArgs e ) {
if( e.Texture != "char" ) return; if( e.Name != "char.png" ) return;
for( int i = 0; i < Players.Length; i++ ) { for( int i = 0; i < Players.Length; i++ ) {
if( Players[i] == null || Players[i].TextureId != -1 ) continue; if( Players[i] == null || Players[i].TextureId != -1 ) continue;
Players[i].SkinType = game.DefaultPlayerSkinType; Players[i].SkinType = game.DefaultPlayerSkinType;

View File

@ -52,8 +52,6 @@ namespace ClassicalSharp.Entities {
Hacks.DoubleJump = !game.ClassicMode && Options.GetBool( OptionsKey.DoubleJump, false ); Hacks.DoubleJump = !game.ClassicMode && Options.GetBool( OptionsKey.DoubleJump, false );
Hacks.Enabled = !game.ClassicMode && Options.GetBool( OptionsKey.HacksEnabled, true ); Hacks.Enabled = !game.ClassicMode && Options.GetBool( OptionsKey.HacksEnabled, true );
if( game.ClassicMode && game.ClassicHacks ) Hacks.Enabled = true; if( game.ClassicMode && game.ClassicHacks ) Hacks.Enabled = true;
InitRenderingData();
} }
Vector3 lastSoundPos = new Vector3( float.PositiveInfinity ); Vector3 lastSoundPos = new Vector3( float.PositiveInfinity );

View File

@ -13,7 +13,6 @@ namespace ClassicalSharp.Entities {
SkinName = skinName; SkinName = skinName;
SkinIdentifier = "skin_" + id; SkinIdentifier = "skin_" + id;
interp = new InterpolatedComponent( game, this ); interp = new InterpolatedComponent( game, this );
InitRenderingData();
} }
public override void SetLocation( LocationUpdate update, bool interpolate ) { public override void SetLocation( LocationUpdate update, bool interpolate ) {

View File

@ -59,7 +59,7 @@ namespace ClassicalSharp.Entities {
game.Graphics.DeleteTexture( ref nameTex.ID ); game.Graphics.DeleteTexture( ref nameTex.ID );
} }
protected void InitRenderingData() { protected void MakeNameTexture() {
using( Font font = new Font( game.FontName, 24 ) ) { using( Font font = new Font( game.FontName, 24 ) ) {
DrawTextArgs args = new DrawTextArgs( DisplayName, font, true ); DrawTextArgs args = new DrawTextArgs( DisplayName, font, true );
nameTex = game.Drawer2D.MakeBitmappedTextTexture( ref args, 0, 0 ); nameTex = game.Drawer2D.MakeBitmappedTextTexture( ref args, 0, 0 );
@ -68,11 +68,13 @@ namespace ClassicalSharp.Entities {
public void UpdateName() { public void UpdateName() {
game.Graphics.DeleteTexture( ref nameTex ); game.Graphics.DeleteTexture( ref nameTex );
InitRenderingData(); MakeNameTexture();
} }
protected void DrawName() { protected void DrawName() {
if( nameTex.ID == 0 ) MakeNameTexture();
if( nameTex.ID == -1 ) return; if( nameTex.ID == -1 ) return;
IGraphicsApi api = game.Graphics; IGraphicsApi api = game.Graphics;
api.BindTexture( nameTex.ID ); api.BindTexture( nameTex.ID );
Vector3 pos = Position; pos.Y += Model.NameYOffset; Vector3 pos = Position; pos.Y += Model.NameYOffset;

View File

@ -10,12 +10,12 @@ namespace ClassicalSharp.Events {
IdEventArgs idArgs = new IdEventArgs(); IdEventArgs idArgs = new IdEventArgs();
/// <summary> Raised when an entity is spawned in the current world. </summary> /// <summary> Raised when an entity is spawned in the current world. </summary>
public event EventHandler<IdEventArgs> EntityAdded; public event EventHandler<IdEventArgs> Added;
internal void RaiseEntityAdded( byte id ) { idArgs.Id = id; Raise( EntityAdded, idArgs ); } internal void RaiseAdded( byte id ) { idArgs.Id = id; Raise( Added, idArgs ); }
/// <summary> Raised when an entity is despawned from the current world. </summary> /// <summary> Raised when an entity is despawned from the current world. </summary>
public event EventHandler<IdEventArgs> EntityRemoved; public event EventHandler<IdEventArgs> Removed;
internal void RaiseEntityRemoved( byte id ) { idArgs.Id = id; Raise( EntityRemoved, idArgs ); } internal void RaiseRemoved( byte id ) { idArgs.Id = id; Raise( Removed, idArgs ); }
/// <summary> Raised when a new CPE player list entry is created. </summary> /// <summary> Raised when a new CPE player list entry is created. </summary>
public event EventHandler<IdEventArgs> CpeListInfoAdded; public event EventHandler<IdEventArgs> CpeListInfoAdded;

View File

@ -11,8 +11,8 @@ namespace ClassicalSharp.Events {
/// <summary> Raised when a texture is changed. (such as "terrain", "rain") </summary> /// <summary> Raised when a texture is changed. (such as "terrain", "rain") </summary>
public event EventHandler<TextureEventArgs> TextureChanged; public event EventHandler<TextureEventArgs> TextureChanged;
internal void RaiseTextureChanged( string texture ) { internal void RaiseTextureChanged( string name, byte[] data ) {
texArgs.Texture = texture; Raise( TextureChanged, texArgs ); } texArgs.Name = name; texArgs.Data = data; Raise( TextureChanged, texArgs ); }
/// <summary> Raised when the user changed their view/fog distance. </summary> /// <summary> Raised when the user changed their view/fog distance. </summary>
public event EventHandler ViewDistanceChanged; public event EventHandler ViewDistanceChanged;
@ -78,8 +78,10 @@ namespace ClassicalSharp.Events {
public sealed class TextureEventArgs : EventArgs { public sealed class TextureEventArgs : EventArgs {
/// <summary> Location of the texture within a texture pack. (e.g. "snow", "default", "char") </summary> /// <summary> Location of the file within a texture pack, without a directory. (e.g. "snow.png") </summary>
/// <remarks> See TexturePackExtractor for a list of supported textures. </remarks> public string Name;
public string Texture;
/// <summary> Raw data of the file. </summary>
public byte[] Data;
} }
} }

View File

@ -0,0 +1,38 @@
// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT
using System;
namespace ClassicalSharp.Events {
public class UserEvents {
/// <summary> Raised when the user changes a block in the world. </summary>
public event EventHandler<BlockChangedEventArgs> BlockChanged;
internal void RaiseBlockChanged( Vector3I coords, byte old, byte block ) {
blockArgs.Coords = coords; blockArgs.OldBlock = old; blockArgs.Block = block;
Raise( BlockChanged, blockArgs );
}
BlockChangedEventArgs blockArgs = new BlockChangedEventArgs();
protected void Raise( EventHandler handler ) {
if( handler != null )
handler( this, EventArgs.Empty );
}
protected void Raise<T>( EventHandler<T> handler, T args ) where T : EventArgs {
if( handler != null )
handler( this, args );
}
}
public sealed class BlockChangedEventArgs : EventArgs {
/// <summary> Location within the world the block was updated at. </summary>
public Vector3I Coords;
/// <summary> Block ID that was at the given location before. </summary>
public byte OldBlock;
/// <summary> Block ID that is now at the given location. </summary>
public byte Block;
}
}

View File

@ -17,7 +17,8 @@ namespace ClassicalSharp {
public void Init( Game game ) { public void Init( Game game ) {
this.game = game; this.game = game;
} }
public void Ready( Game game ) { }
public void Reset( Game game ) { } public void Reset( Game game ) { }
public void OnNewMap( Game game ) { } public void OnNewMap( Game game ) { }
public void OnNewMapLoaded( Game game ) { } public void OnNewMapLoaded( Game game ) { }

View File

@ -25,9 +25,12 @@ namespace ClassicalSharp {
/// <summary> Represents a game component. </summary> /// <summary> Represents a game component. </summary>
public interface IGameComponent : IDisposable { public interface IGameComponent : IDisposable {
/// <summary> Called when the game has loaded. </summary> /// <summary> Called when the game is being loaded. </summary>
void Init( Game game ); void Init( Game game );
/// <summary> Called when the texture pack has been loaded and all components have been initalised. </summary>
void Ready( Game game );
/// <summary> Called to reset the component's state when the user is reconnecting to a server. </summary> /// <summary> Called to reset the component's state when the user is reconnecting to a server. </summary>
void Reset( Game game ); void Reset( Game game );
@ -102,6 +105,7 @@ namespace ClassicalSharp {
public OtherEvents Events = new OtherEvents(); public OtherEvents Events = new OtherEvents();
public EntityEvents EntityEvents = new EntityEvents(); public EntityEvents EntityEvents = new EntityEvents();
public WorldEvents WorldEvents = new WorldEvents(); public WorldEvents WorldEvents = new WorldEvents();
public UserEvents UserEvents = new UserEvents();
public InputHandler InputHandler; public InputHandler InputHandler;
public Chat Chat; public Chat Chat;
public BlockHandRenderer BlockHandRenderer; public BlockHandRenderer BlockHandRenderer;
@ -170,7 +174,7 @@ namespace ClassicalSharp {
public Vector3 CurrentCameraPos; public Vector3 CurrentCameraPos;
public Animations Animations; public Animations Animations;
internal int CloudsTexId, RainTexId, SnowTexId, GuiTexId, GuiClassicTexId; internal int CloudsTexId, GuiTexId, GuiClassicTexId;
internal bool screenshotRequested; internal bool screenshotRequested;
internal EntryList AcceptedUrls = new EntryList( "acceptedurls.txt" ); internal EntryList AcceptedUrls = new EntryList( "acceptedurls.txt" );
internal EntryList DeniedUrls = new EntryList( "deniedurls.txt" ); internal EntryList DeniedUrls = new EntryList( "deniedurls.txt" );

View File

@ -84,13 +84,7 @@ namespace ClassicalSharp {
TerrainAtlas1D = new TerrainAtlas1D( Graphics ); TerrainAtlas1D = new TerrainAtlas1D( Graphics );
TerrainAtlas = new TerrainAtlas2D( Graphics, Drawer2D ); TerrainAtlas = new TerrainAtlas2D( Graphics, Drawer2D );
Animations = new Animations( this ); Animations = AddComponent( new Animations() );
defTexturePack = Options.Get( OptionsKey.DefaultTexturePack ) ?? "default.zip";
TexturePackExtractor extractor = new TexturePackExtractor();
extractor.Extract( "default.zip", this );
// in case the user's default texture pack doesn't have all required textures
if( defTexturePack != "default.zip" )
extractor.Extract( DefaultTexturePack, this );
Inventory = AddComponent( new Inventory() ); Inventory = AddComponent( new Inventory() );
BlockInfo.SetDefaultBlockPermissions( Inventory.CanPlace, Inventory.CanDelete ); BlockInfo.SetDefaultBlockPermissions( Inventory.CanPlace, Inventory.CanDelete );
@ -124,8 +118,7 @@ namespace ClassicalSharp {
//Graphics.DepthWrite = true; //Graphics.DepthWrite = true;
Graphics.AlphaBlendFunc( BlendFunc.SourceAlpha, BlendFunc.InvSourceAlpha ); Graphics.AlphaBlendFunc( BlendFunc.SourceAlpha, BlendFunc.InvSourceAlpha );
Graphics.AlphaTestFunc( CompareFunc.Greater, 0.5f ); Graphics.AlphaTestFunc( CompareFunc.Greater, 0.5f );
fpsScreen = new FpsScreen( this ); fpsScreen = AddComponent( new FpsScreen( this ) );
fpsScreen.Init();
hudScreen = AddComponent( new HudScreen( this ) ); hudScreen = AddComponent( new HudScreen( this ) );
Culling = new FrustumCulling(); Culling = new FrustumCulling();
Picking = AddComponent( new PickedPosRenderer() ); Picking = AddComponent( new PickedPosRenderer() );
@ -134,6 +127,9 @@ namespace ClassicalSharp {
foreach( IGameComponent comp in Components ) foreach( IGameComponent comp in Components )
comp.Init( this ); comp.Init( this );
ExtractInitialTexturePack();
foreach( IGameComponent comp in Components )
comp.Ready( this );
LoadIcon(); LoadIcon();
string connectString = "Connecting to " + IPAddress + ":" + Port + ".."; string connectString = "Connecting to " + IPAddress + ":" + Port + "..";
@ -145,6 +141,15 @@ namespace ClassicalSharp {
Network.Connect( IPAddress, Port ); Network.Connect( IPAddress, Port );
} }
void ExtractInitialTexturePack() {
defTexturePack = Options.Get( OptionsKey.DefaultTexturePack ) ?? "default.zip";
TexturePackExtractor extractor = new TexturePackExtractor();
extractor.Extract( "default.zip", this );
// in case the user's default texture pack doesn't have all required textures
if( defTexturePack != "default.zip" )
extractor.Extract( DefaultTexturePack, this );
}
void LoadOptions() { void LoadOptions() {
ClassicMode = Options.GetBool( "mode-classic", false ); ClassicMode = Options.GetBool( "mode-classic", false );
ClassicHacks = Options.GetBool( OptionsKey.AllowClassicHacks, false ); ClassicHacks = Options.GetBool( OptionsKey.AllowClassicHacks, false );
@ -531,10 +536,7 @@ namespace ClassicalSharp {
Graphics.DeleteIb( defaultIb ); Graphics.DeleteIb( defaultIb );
Graphics.Dispose(); Graphics.Dispose();
Drawer2D.DisposeInstance(); Drawer2D.DisposeInstance();
Animations.Dispose();
Graphics.DeleteTexture( ref CloudsTexId ); Graphics.DeleteTexture( ref CloudsTexId );
Graphics.DeleteTexture( ref RainTexId );
Graphics.DeleteTexture( ref SnowTexId );
Graphics.DeleteTexture( ref GuiTexId ); Graphics.DeleteTexture( ref GuiTexId );
Graphics.DeleteTexture( ref GuiClassicTexId ); Graphics.DeleteTexture( ref GuiClassicTexId );
foreach( WarningScreen screen in WarningOverlays ) foreach( WarningScreen screen in WarningOverlays )
@ -555,6 +557,26 @@ namespace ClassicalSharp {
Inventory.CanPlace[block] && Inventory.CanDelete[block]; Inventory.CanPlace[block] && Inventory.CanDelete[block];
} }
/// <summary> Reads a bitmap from the stream (converting it to 32 bits per pixel if necessary),
/// and updates the native texture for it. </summary>
public void UpdateTexture( ref int texId, byte[] data, bool setSkinType ) {
MemoryStream stream = new MemoryStream( data );
Graphics.DeleteTexture( ref texId );
using( Bitmap bmp = Platform.ReadBmp( stream ) ) {
if( setSkinType )
DefaultPlayerSkinType = Utils.GetSkinType( bmp );
if( !FastBitmap.CheckFormat( bmp.PixelFormat ) ) {
using( Bitmap bmp32 = Drawer2D.ConvertTo32Bpp( bmp ) )
texId = Graphics.CreateTexture( bmp32 );
} else {
texId = Graphics.CreateTexture( bmp );
}
}
}
public Game( string username, string mppass, string skinServer, public Game( string username, string mppass, string skinServer,
bool nullContext, int width, int height ) { bool nullContext, int width, int height ) {
window = new DesktopWindow( this, username, nullContext, width, height ); window = new DesktopWindow( this, username, nullContext, width, height );

View File

@ -21,7 +21,8 @@ namespace ClassicalSharp {
Hotbar[6] = Block.Leaves; Hotbar[7] = Block.Grass; Hotbar[6] = Block.Leaves; Hotbar[7] = Block.Grass;
Hotbar[8] = Block.Slab; Hotbar[8] = Block.Slab;
} }
public void Ready( Game game ) { }
public void Reset( Game game ) { } public void Reset( Game game ) { }
public void OnNewMap( Game game ) { } public void OnNewMap( Game game ) { }
public void OnNewMapLoaded( Game game ) { } public void OnNewMapLoaded( Game game ) { }

View File

@ -13,7 +13,7 @@ namespace ClassicalSharp {
public PickingHandler( Game game, InputHandler input ) { public PickingHandler( Game game, InputHandler input ) {
this.game = game; this.game = game;
this.input = input; this.input = input;
} }
internal DateTime lastClick = DateTime.MinValue; internal DateTime lastClick = DateTime.MinValue;
public void PickBlocks( bool cooldown, bool left, bool middle, bool right ) { public void PickBlocks( bool cooldown, bool left, bool middle, bool right ) {
@ -32,47 +32,51 @@ namespace ClassicalSharp {
} }
int buttonsDown = (left ? 1 : 0) + (right ? 1 : 0) + (middle ? 1 : 0); int buttonsDown = (left ? 1 : 0) + (right ? 1 : 0) + (middle ? 1 : 0);
if( buttonsDown > 1 || game.ActiveScreen.HandlesAllInput || if( buttonsDown > 1 || game.ActiveScreen.HandlesAllInput ||
inv.HeldBlock == Block.Air ) return; inv.HeldBlock == Block.Air ) return;
// always play delete animations, even if we aren't picking a block. // always play delete animations, even if we aren't picking a block.
if( left ) game.BlockHandRenderer.SetAnimationClick( true ); if( left ) game.BlockHandRenderer.SetAnimationClick( true );
if( !game.SelectedPos.Valid ) return; if( !game.SelectedPos.Valid ) return;
BlockInfo info = game.BlockInfo;
if( middle ) { if( middle ) {
Vector3I pos = game.SelectedPos.BlockPos; Vector3I pos = game.SelectedPos.BlockPos;
byte block = 0; if( !game.World.IsValidPos( pos ) ) return;
if( game.World.IsValidPos( pos ) && (block = game.World.GetBlock( pos )) != 0 byte old = game.World.GetBlock( pos );
&& (inv.CanPlace[block] || inv.CanDelete[block]) ) {
if( !info.IsAir[old] && (inv.CanPlace[old] || inv.CanDelete[old]) ) {
for( int i = 0; i < inv.Hotbar.Length; i++ ) { for( int i = 0; i < inv.Hotbar.Length; i++ ) {
if( inv.Hotbar[i] == (Block)block ) { if( inv.Hotbar[i] == (Block)old ) {
inv.HeldBlockIndex = i; return; inv.HeldBlockIndex = i; return;
} }
} }
inv.HeldBlock = (Block)block; inv.HeldBlock = (Block)old;
} }
} else if( left ) { } else if( left ) {
Vector3I pos = game.SelectedPos.BlockPos; Vector3I pos = game.SelectedPos.BlockPos;
byte block = 0; if( !game.World.IsValidPos( pos ) ) return;
if( game.World.IsValidPos( pos ) && (block = game.World.GetBlock( pos )) != 0 byte old = game.World.GetBlock( pos );
&& inv.CanDelete[block] ) {
game.ParticleManager.BreakBlockEffect( pos, block ); if( !info.IsAir[old] && inv.CanDelete[old] ) {
game.AudioPlayer.PlayDigSound( game.BlockInfo.DigSounds[block] ); game.ParticleManager.BreakBlockEffect( pos, old );
game.AudioPlayer.PlayDigSound( game.BlockInfo.DigSounds[old] );
game.UpdateBlock( pos.X, pos.Y, pos.Z, 0 ); game.UpdateBlock( pos.X, pos.Y, pos.Z, 0 );
game.Network.SendSetBlock( pos.X, pos.Y, pos.Z, false, (byte)inv.HeldBlock ); game.Network.SendSetBlock( pos.X, pos.Y, pos.Z, false, (byte)inv.HeldBlock );
game.UserEvents.RaiseBlockChanged( pos, old, 0 );
} }
} else if( right ) { } else if( right ) {
Vector3I pos = game.SelectedPos.TranslatedPos; Vector3I pos = game.SelectedPos.TranslatedPos;
if( !game.World.IsValidPos( pos ) ) return; if( !game.World.IsValidPos( pos ) ) return;
byte old = game.World.GetBlock( pos );
byte block = (byte)inv.HeldBlock; byte block = (byte)inv.HeldBlock;
if( !game.CanPick( game.World.GetBlock( pos ) ) && inv.CanPlace[block]
&& CheckIsFree( game.SelectedPos, block ) ) { if( !game.CanPick( old ) && inv.CanPlace[block] && CheckIsFree( game.SelectedPos, block ) ) {
game.UpdateBlock( pos.X, pos.Y, pos.Z, block ); game.UpdateBlock( pos.X, pos.Y, pos.Z, block );
game.AudioPlayer.PlayDigSound( game.BlockInfo.StepSounds[block] ); game.AudioPlayer.PlayDigSound( game.BlockInfo.StepSounds[block] );
game.Network.SendSetBlock( pos.X, pos.Y, pos.Z, true, block ); game.Network.SendSetBlock( pos.X, pos.Y, pos.Z, true, block );
game.BlockHandRenderer.SetAnimationClick( false ); game.BlockHandRenderer.SetAnimationClick( false );
game.UserEvents.RaiseBlockChanged( pos, old, block );
} }
} }
} }

View File

@ -131,8 +131,6 @@ namespace ClassicalSharp.GraphicsAPI {
} }
public override void SetFogStart( float value ) { public override void SetFogStart( float value ) {
if( value == fogStart ) return;
fogStart = value;
device.SetRenderState( RenderState.FogStart, value ); device.SetRenderState( RenderState.FogStart, value );
} }

View File

@ -81,13 +81,13 @@ namespace ClassicalSharp.GraphicsAPI {
} }
} }
float lastFogStart = -1, lastFogEnd = -1, lastFogDensity = -1; float lastFogEnd = -1, lastFogDensity = -1;
public override void SetFogDensity( float value ) { public override void SetFogDensity( float value ) {
FogParam( FogParameter.FogDensity, value, ref lastFogDensity ); FogParam( FogParameter.FogDensity, value, ref lastFogDensity );
} }
public override void SetFogStart( float value ) { public override void SetFogStart( float value ) {
FogParam( FogParameter.FogStart, value, ref lastFogStart ); GL.Fogf( FogParameter.FogStart, value );
} }
public override void SetFogEnd( float value ) { public override void SetFogEnd( float value ) {
@ -95,10 +95,9 @@ namespace ClassicalSharp.GraphicsAPI {
} }
static void FogParam( FogParameter param, float value, ref float last ) { static void FogParam( FogParameter param, float value, ref float last ) {
if( value != last ) { if( value == last ) return;
GL.Fogf( param, value ); GL.Fogf( param, value );
last = value; last = value;
}
} }
Fog lastFogMode = (Fog)999; Fog lastFogMode = (Fog)999;

View File

@ -67,11 +67,11 @@ namespace ClassicalSharp.Map {
nbt.Write( NbtTagType.Int8 ); nbt.Write( NbtTagType.Int8 );
nbt.Write( "H" ); nbt.Write( "H" );
nbt.WriteUInt8( (byte)Utils.DegreesToPacked( p.SpawnYaw, 256 ) ); nbt.WriteUInt8( (byte)Utils.DegreesToPacked( p.SpawnYaw ) );
nbt.Write( NbtTagType.Int8 ); nbt.Write( NbtTagType.Int8 );
nbt.Write( "P" ); nbt.Write( "P" );
nbt.WriteUInt8( (byte)Utils.DegreesToPacked( p.SpawnPitch, 256 ) ); nbt.WriteUInt8( (byte)Utils.DegreesToPacked( p.SpawnPitch ) );
nbt.Write( NbtTagType.End ); nbt.Write( NbtTagType.End );
} }

View File

@ -75,9 +75,13 @@ namespace ClassicalSharp.Map {
map.SetShadowlight( GetColour( "Ambient", World.DefaultShadowlight ) ); map.SetShadowlight( GetColour( "Ambient", World.DefaultShadowlight ) );
} }
if( CheckKey( "EnvMapAppearance", 1, metadata ) ) { if( CheckKey( "EnvMapAppearance", 1, metadata ) ) {
string url = null;
if( curCpeExt.ContainsKey( "TextureURL" ) ) if( curCpeExt.ContainsKey( "TextureURL" ) )
map.TextureUrl = (string)curCpeExt["TextureURL"].Value; url = (string)curCpeExt["TextureURL"].Value;
if( map.TextureUrl.Length == 0 ) map.TextureUrl = null; if( url.Length == 0 ) url = null;
if( game.AllowServerTextures && url != null )
game.Network.RetrieveTexturePack( url );
byte sidesBlock = (byte)curCpeExt["SideBlock"].Value; byte sidesBlock = (byte)curCpeExt["SideBlock"].Value;
byte edgeBlock = (byte)curCpeExt["EdgeBlock"].Value; byte edgeBlock = (byte)curCpeExt["EdgeBlock"].Value;
map.SetSidesBlock( (Block)sidesBlock ); map.SetSidesBlock( (Block)sidesBlock );

View File

@ -15,34 +15,33 @@ namespace ClassicalSharp.Map {
const byte Revision = 13; const byte Revision = 13;
public byte[] Load( Stream stream, Game game, out int width, out int height, out int length ) { public byte[] Load( Stream stream, Game game, out int width, out int height, out int length ) {
BinaryReader reader = new BinaryReader( stream ); BinaryReader r = new BinaryReader( stream );
if( reader.ReadInt32() != Identifier || reader.ReadByte() != Revision ) { if( r.ReadInt32() != Identifier || r.ReadByte() != Revision )
throw new InvalidDataException( "Unexpected constant in .fcm file" ); throw new InvalidDataException( "Unexpected constant in .fcm file" );
}
width = reader.ReadInt16(); width = r.ReadInt16();
height = reader.ReadInt16(); height = r.ReadInt16();
length = reader.ReadInt16(); length = r.ReadInt16();
LocalPlayer p = game.LocalPlayer; LocalPlayer p = game.LocalPlayer;
p.Spawn.X = reader.ReadInt32() / 32f; p.Spawn.X = r.ReadInt32() / 32f;
p.Spawn.Y = reader.ReadInt32() / 32f; p.Spawn.Y = r.ReadInt32() / 32f;
p.Spawn.Z = reader.ReadInt32() / 32f; p.Spawn.Z = r.ReadInt32() / 32f;
p.SpawnYaw = (float)Utils.PackedToDegrees( reader.ReadByte() ); p.SpawnYaw = (float)Utils.PackedToDegrees( r.ReadByte() );
p.SpawnPitch = (float)Utils.PackedToDegrees( reader.ReadByte() ); p.SpawnPitch = (float)Utils.PackedToDegrees( r.ReadByte() );
reader.ReadUInt32(); // date modified r.ReadUInt32(); // date modified
reader.ReadUInt32(); // date created r.ReadUInt32(); // date created
game.World.Uuid = new Guid( reader.ReadBytes( 16 ) ); game.World.Uuid = new Guid( r.ReadBytes( 16 ) );
reader.ReadBytes( 26 ); // layer index r.ReadBytes( 26 ); // layer index
int metaSize = reader.ReadInt32(); int metaSize = r.ReadInt32();
using( DeflateStream ds = new DeflateStream( stream, CompressionMode.Decompress ) ) { using( DeflateStream ds = new DeflateStream( stream, CompressionMode.Decompress ) ) {
reader = new BinaryReader( ds ); r = new BinaryReader( ds );
for( int i = 0; i < metaSize; i++ ) { for( int i = 0; i < metaSize; i++ ) {
string group = ReadString( reader ); string group = ReadString( r );
string key = ReadString( reader ); string key = ReadString( r );
string value = ReadString( reader ); string value = ReadString( r );
} }
byte[] blocks = new byte[width * height * length]; byte[] blocks = new byte[width * height * length];

View File

@ -13,27 +13,29 @@ namespace ClassicalSharp.Map {
public sealed class MapLvlImporter : IMapFormatImporter { public sealed class MapLvlImporter : IMapFormatImporter {
const int Version = 1874; const int Version = 1874;
const byte customTile = 163;
public byte[] Load( Stream stream, Game game, out int width, out int height, out int length ) { public byte[] Load( Stream stream, Game game, out int width, out int height, out int length ) {
GZipHeaderReader gsHeader = new GZipHeaderReader(); GZipHeaderReader gsHeader = new GZipHeaderReader();
while( !gsHeader.ReadHeader( stream ) ) { } while( !gsHeader.ReadHeader( stream ) ) { }
using( DeflateStream gs = new DeflateStream( stream, CompressionMode.Decompress ) ) { using( DeflateStream gs = new DeflateStream( stream, CompressionMode.Decompress ) ) {
BinaryReader reader = new BinaryReader( gs ); BinaryReader r = new BinaryReader( gs );
ushort header = reader.ReadUInt16(); ushort header = r.ReadUInt16();
width = header == Version ? reader.ReadUInt16() : header; width = header == Version ? r.ReadUInt16() : header;
length = reader.ReadUInt16(); length = r.ReadUInt16();
height = reader.ReadUInt16(); height = r.ReadUInt16();
LocalPlayer p = game.LocalPlayer; LocalPlayer p = game.LocalPlayer;
p.Spawn.X = reader.ReadUInt16(); p.Spawn.X = r.ReadUInt16();
p.Spawn.Z = reader.ReadUInt16(); p.Spawn.Z = r.ReadUInt16();
p.Spawn.Y = reader.ReadUInt16(); p.Spawn.Y = r.ReadUInt16();
p.SpawnYaw = (float)Utils.PackedToDegrees( reader.ReadByte() ); p.SpawnYaw = (float)Utils.PackedToDegrees( r.ReadByte() );
p.SpawnPitch = (float)Utils.PackedToDegrees( reader.ReadByte() ); p.SpawnPitch = (float)Utils.PackedToDegrees( r.ReadByte() );
if( header == Version ) if( header == Version )
reader.ReadUInt16(); // pervisit and perbuild perms r.ReadUInt16(); // pervisit and perbuild perms
byte[] blocks = new byte[width * height * length]; byte[] blocks = new byte[width * height * length];
int read = gs.Read( blocks, 0, blocks.Length ); int read = gs.Read( blocks, 0, blocks.Length );
ConvertPhysicsBlocks( blocks ); ConvertPhysicsBlocks( blocks );
@ -59,7 +61,7 @@ namespace ClassicalSharp.Map {
int bx = i & 0xF, by = (i >> 8) & 0xF, bz = (i >> 4) & 0xF; int bx = i & 0xF, by = (i >> 8) & 0xF, bz = (i >> 4) & 0xF;
int index = baseIndex + (by * length + bz) * width + bx; int index = baseIndex + (by * length + bz) * width + bx;
if( blocks[index] == 163 ) // custom block id if( blocks[index] == customTile )
blocks[index] = chunk[i]; blocks[index] = chunk[i];
} }
} }
@ -82,8 +84,8 @@ namespace ClassicalSharp.Map {
34, 35, 36, 22, 20, 49, 45, 1, 4, 0, 9, 11, 4, 19, 5, 17, 10, 49, 20, 1, 34, 35, 36, 22, 20, 49, 45, 1, 4, 0, 9, 11, 4, 19, 5, 17, 10, 49, 20, 1,
18, 12, 5, 25, 46, 44, 17, 49, 20, 1, 18, 12, 5, 25, 36, 34, 0, 9, 11, 46, 18, 12, 5, 25, 46, 44, 17, 49, 20, 1, 18, 12, 5, 25, 36, 34, 0, 9, 11, 46,
44, 0, 9, 11, 8, 10, 22, 27, 22, 8, 10, 28, 17, 49, 20, 1, 18, 12, 5, 25, 46, 44, 0, 9, 11, 8, 10, 22, 27, 22, 8, 10, 28, 17, 49, 20, 1, 18, 12, 5, 25, 46,
44, 11, 9, 0, 9, 11, 163, 0, 0, 9, 11, 0, 0, 0, 0, 0, 0, 0, 28, 22, 21, 11, 44, 11, 9, 0, 9, 11, customTile, 0, 0, 9, 11, 0, 0, 0, 0, 0, 0, 0, 28, 22, 21,
0, 0, 0, 46, 46, 10, 10, 46, 20, 41, 42, 11, 9, 0, 8, 10, 10, 8, 0, 22, 22, 11, 0, 0, 0, 46, 46, 10, 10, 46, 20, 41, 42, 11, 9, 0, 8, 10, 10, 8, 0, 22, 22,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 10, 0, 0, 0, 0, 0, 22, 22, 42, 3, 2, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 10, 0, 0, 0, 0, 0, 22, 22, 42, 3, 2, 29,
47, 0, 0, 0, 0, 0, 27, 46, 48, 24, 22, 36, 34, 8, 10, 21, 29, 22, 10, 22, 22, 47, 0, 0, 0, 0, 0, 27, 46, 48, 24, 22, 36, 34, 8, 10, 21, 29, 22, 10, 22, 22,
41, 19, 35, 21, 29, 49, 34, 16, 41, 0, 22 }; 41, 19, 35, 21, 29, 49, 34, 16, 41, 0, 22 };

View File

@ -0,0 +1,73 @@
// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT
using System;
using System.IO;
using System.IO.Compression;
namespace ClassicalSharp.Map {
public sealed class MapSchematicExporter : IMapFormatExporter {
public void Save( Stream stream, Game game ) {
using( GZipStream wrapper = new GZipStream( stream, CompressionMode.Compress ) ) {
BinaryWriter writer = new BinaryWriter( wrapper );
NbtFile nbt = new NbtFile( writer );
World map = game.World;
nbt.Write( NbtTagType.Compound ); nbt.Write( "Schematic" );
nbt.Write( NbtTagType.String );
nbt.Write( "Materials" ); nbt.Write( "Classic" );
nbt.Write( NbtTagType.Int16 );
nbt.Write( "Width" ); nbt.WriteInt16( (short)map.Width );
nbt.Write( NbtTagType.Int16 );
nbt.Write( "Height" ); nbt.WriteInt16( (short)map.Height );
nbt.Write( NbtTagType.Int16 );
nbt.Write( "Length" ); nbt.WriteInt16( (short)map.Length );
WriteBlocks( nbt, map.mapData );
WriteBlockData( nbt, map.mapData );
nbt.Write( NbtTagType.List );
nbt.Write( "Entities" );
nbt.Write( NbtTagType.Compound ); nbt.WriteInt32( 0 );
nbt.Write( NbtTagType.List );
nbt.Write( "TileEntities" );
nbt.Write( NbtTagType.Compound ); nbt.WriteInt32( 0 );
nbt.Write( NbtTagType.End );
}
}
void WriteBlocks( NbtFile nbt, byte[] blocks ) {
const int chunkSize = 64 * 1024 * 32;
nbt.Write( NbtTagType.Int8Array );
nbt.Write( "Blocks" );
nbt.WriteInt32( blocks.Length );
for( int i = 0; i < blocks.Length; i += chunkSize ) {
int count = Math.Min( chunkSize, blocks.Length - i );
nbt.WriteBytes( blocks, i, count );
}
}
void WriteBlockData( NbtFile nbt, byte[] blocks ) {
const int chunkSize = 64 * 1024;
byte[] chunk = new byte[chunkSize];
nbt.Write( NbtTagType.Int8Array );
nbt.Write( "Data" );
nbt.WriteInt32( blocks.Length );
for( int i = 0; i < blocks.Length; i += chunkSize ) {
// All 0 so we can skip this.
int count = Math.Min( chunkSize, blocks.Length - i );
nbt.WriteBytes( chunk, 0, count );
}
}
}
}

View File

@ -55,6 +55,8 @@ namespace ClassicalSharp.Map {
public void WriteBytes( byte[] v ) { writer.Write( v ); } public void WriteBytes( byte[] v ) { writer.Write( v ); }
public void WriteBytes( byte[] v, int index, int count ) { writer.Write( v, index, count ); }
public void Write( string value ) { public void Write( string value ) {
ushort len = (ushort)value.Length; ushort len = (ushort)value.Length;
byte[] data = Encoding.UTF8.GetBytes( value ); byte[] data = Encoding.UTF8.GetBytes( value );

View File

@ -56,6 +56,13 @@ namespace ClassicalSharp {
other.Max.X <= Max.X && other.Max.Y <= Max.Y && other.Max.Z <= Max.Z; other.Max.X <= Max.X && other.Max.Y <= Max.Y && other.Max.Z <= Max.Z;
} }
/// <summary> Determines whether this bounding box entirely contains
/// the coordinates on all axes. </summary>
public bool Contains( Vector3 P ) {
return P.X >= Min.X && P.Y >= Min.Y && P.Z >= Min.Z &&
P.X <= Max.X && P.Y <= Max.Y && P.Z <= Max.Z;
}
/// <summary> Determines whether this bounding box intersects /// <summary> Determines whether this bounding box intersects
/// the given bounding box on the X axis. </summary> /// the given bounding box on the X axis. </summary>
public bool XIntersects( BoundingBox box ) { public bool XIntersects( BoundingBox box ) {

View File

@ -2,6 +2,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using ClassicalSharp.Events;
using ClassicalSharp.GraphicsAPI; using ClassicalSharp.GraphicsAPI;
namespace ClassicalSharp.Model { namespace ClassicalSharp.Model {
@ -12,7 +13,7 @@ namespace ClassicalSharp.Model {
IGraphicsApi api; IGraphicsApi api;
public ModelCache( Game window ) { public ModelCache( Game window ) {
this.game = window; this.game = window;
api = game.Graphics; api = game.Graphics;
} }
public CustomModel[] CustomModels = new CustomModel[256]; public CustomModel[] CustomModels = new CustomModel[256];
@ -23,6 +24,7 @@ namespace ClassicalSharp.Model {
model.CreateParts(); model.CreateParts();
cache["humanoid"] = model; cache["humanoid"] = model;
cache["human"] = cache["humanoid"]; cache["human"] = cache["humanoid"];
game.Events.TextureChanged += TextureChanged;
} }
internal int vb; internal int vb;
@ -57,15 +59,16 @@ namespace ClassicalSharp.Model {
else if( modelName == "zombie" ) return new ZombieModel( game ); else if( modelName == "zombie" ) return new ZombieModel( game );
else if( modelName == "block" ) return new BlockModel( game ); else if( modelName == "block" ) return new BlockModel( game );
else if( modelName == "chibi" ) return new ChibiModel( game ); else if( modelName == "chibi" ) return new ChibiModel( game );
else if( modelName == "giant" ) return new GiantModel( game ); else if( modelName == "giant" ) return new GiantModel( game );
return null; return null;
} }
public void Dispose() { public void Dispose() {
foreach( var entry in cache ) { foreach( var entry in cache )
entry.Value.Dispose(); entry.Value.Dispose();
}
api.DeleteDynamicVb( vb ); api.DeleteDynamicVb( vb );
game.Events.TextureChanged -= TextureChanged;
api.DeleteTexture( ref ChickenTexId ); api.DeleteTexture( ref ChickenTexId );
api.DeleteTexture( ref CreeperTexId ); api.DeleteTexture( ref CreeperTexId );
api.DeleteTexture( ref PigTexId ); api.DeleteTexture( ref PigTexId );
@ -74,7 +77,30 @@ namespace ClassicalSharp.Model {
api.DeleteTexture( ref SpiderTexId ); api.DeleteTexture( ref SpiderTexId );
api.DeleteTexture( ref ZombieTexId ); api.DeleteTexture( ref ZombieTexId );
api.DeleteTexture( ref SheepFurTexId ); api.DeleteTexture( ref SheepFurTexId );
api.DeleteTexture( ref HumanoidTexId ); api.DeleteTexture( ref HumanoidTexId );
}
void TextureChanged( object sender, TextureEventArgs e ) {
switch( e.Name ) {
case "chicken.png":
game.UpdateTexture( ref ChickenTexId, e.Data, false ); break;
case "creeper.png":
game.UpdateTexture( ref CreeperTexId, e.Data, false ); break;
case "pig.png":
game.UpdateTexture( ref PigTexId, e.Data, false ); break;
case "sheep.png":
game.UpdateTexture( ref SheepTexId, e.Data, false ); break;
case "skeleton.png":
game.UpdateTexture( ref SkeletonTexId, e.Data, false ); break;
case "spider.png":
game.UpdateTexture( ref SpiderTexId, e.Data, false ); break;
case "zombie.png":
game.UpdateTexture( ref ZombieTexId, e.Data, false ); break;
case "sheep_fur.png":
game.UpdateTexture( ref SheepFurTexId, e.Data, false ); break;
case "char.png":
game.UpdateTexture( ref HumanoidTexId, e.Data, true ); break;
}
} }
} }
} }

View File

@ -128,7 +128,7 @@ namespace ClassicalSharp {
if( item.Data != null ) { if( item.Data != null ) {
Bitmap bmp = (Bitmap)item.Data; Bitmap bmp = (Bitmap)item.Data;
game.World.TextureUrl = item.Url; game.World.TextureUrl = item.Url;
game.Animations.Dispose(); game.Animations.Clear();
if( !FastBitmap.CheckFormat( bmp.PixelFormat ) ) { if( !FastBitmap.CheckFormat( bmp.PixelFormat ) ) {
Utils.LogDebug( "Converting terrain atlas to 32bpp image" ); Utils.LogDebug( "Converting terrain atlas to 32bpp image" );
@ -142,7 +142,7 @@ namespace ClassicalSharp {
if( bmp == null ) {// Should never happen, but handle anyways. if( bmp == null ) {// Should never happen, but handle anyways.
ExtractDefault(); ExtractDefault();
} else if( item.Url != game.World.TextureUrl ) { } else if( item.Url != game.World.TextureUrl ) {
game.Animations.Dispose(); game.Animations.Clear();
if( !game.ChangeTerrainAtlas( bmp ) ) { bmp.Dispose(); return; } if( !game.ChangeTerrainAtlas( bmp ) ) { bmp.Dispose(); return; }
} }
@ -155,7 +155,7 @@ namespace ClassicalSharp {
if( game.AsyncDownloader.TryGetItem( "texturePack", out item ) ) { if( game.AsyncDownloader.TryGetItem( "texturePack", out item ) ) {
if( item.Data != null ) { if( item.Data != null ) {
game.World.TextureUrl = item.Url; game.World.TextureUrl = item.Url;
game.Animations.Dispose(); game.Animations.Clear();
TexturePackExtractor extractor = new TexturePackExtractor(); TexturePackExtractor extractor = new TexturePackExtractor();
extractor.Extract( (byte[])item.Data, game ); extractor.Extract( (byte[])item.Data, game );
@ -166,7 +166,7 @@ namespace ClassicalSharp {
if( data == null ) { // Should never happen, but handle anyways. if( data == null ) { // Should never happen, but handle anyways.
ExtractDefault(); ExtractDefault();
} else if( item.Url != game.World.TextureUrl ) { } else if( item.Url != game.World.TextureUrl ) {
game.Animations.Dispose(); game.Animations.Clear();
TexturePackExtractor extractor = new TexturePackExtractor(); TexturePackExtractor extractor = new TexturePackExtractor();
extractor.Extract( data, game ); extractor.Extract( data, game );
} }

View File

@ -57,8 +57,8 @@ namespace ClassicalSharp.Net {
writer.WriteInt16( (short)(pos.X * 32) ); writer.WriteInt16( (short)(pos.X * 32) );
writer.WriteInt16( (short)((int)(pos.Y * 32) + 51) ); writer.WriteInt16( (short)((int)(pos.Y * 32) + 51) );
writer.WriteInt16( (short)(pos.Z * 32) ); writer.WriteInt16( (short)(pos.Z * 32) );
writer.WriteUInt8( (byte)Utils.DegreesToPacked( yaw, 256 ) ); writer.WriteUInt8( (byte)Utils.DegreesToPacked( yaw ) );
writer.WriteUInt8( (byte)Utils.DegreesToPacked( pitch, 256 ) ); writer.WriteUInt8( (byte)Utils.DegreesToPacked( pitch ) );
} }
#endregion #endregion
@ -172,8 +172,6 @@ namespace ClassicalSharp.Net {
sentWomId = true; sentWomId = true;
} }
gzipStream = null; gzipStream = null;
ServerName = null;
ServerMotd = null;
GC.Collect(); GC.Collect();
} }
@ -277,11 +275,11 @@ namespace ClassicalSharp.Net {
if( entityId != 0xFF ) { if( entityId != 0xFF ) {
Player oldPlayer = game.Players[entityId]; Player oldPlayer = game.Players[entityId];
if( oldPlayer != null ) { if( oldPlayer != null ) {
game.EntityEvents.RaiseEntityRemoved( entityId ); game.EntityEvents.RaiseRemoved( entityId );
oldPlayer.Despawn(); oldPlayer.Despawn();
} }
game.Players[entityId] = new NetPlayer( displayName, skinName, game, entityId ); game.Players[entityId] = new NetPlayer( displayName, skinName, game, entityId );
game.EntityEvents.RaiseEntityAdded( entityId ); game.EntityEvents.RaiseAdded( entityId );
} else { } else {
// Server is only allowed to change our own name colours. // Server is only allowed to change our own name colours.
if( Utils.StripColours( displayName ) != game.Username ) if( Utils.StripColours( displayName ) != game.Username )
@ -309,7 +307,7 @@ namespace ClassicalSharp.Net {
if( player == null ) return; if( player == null ) return;
if( entityId != 0xFF ) { if( entityId != 0xFF ) {
game.EntityEvents.RaiseEntityRemoved( entityId ); game.EntityEvents.RaiseRemoved( entityId );
player.Despawn(); player.Despawn();
game.Players[entityId] = null; game.Players[entityId] = null;
} }

View File

@ -36,7 +36,8 @@ namespace ClassicalSharp.Network {
worker.IsBackground = true; worker.IsBackground = true;
worker.Start(); worker.Start();
} }
public void Ready( Game game ) { }
public void Reset( Game game ) { public void Reset( Game game ) {
lock( requestLocker ) lock( requestLocker )
requests.Clear(); requests.Clear();

View File

@ -13,13 +13,12 @@ namespace ClassicalSharp.Particles {
int[] terrain1DCount, terrain1DIndices; int[] terrain1DCount, terrain1DIndices;
Game game; Game game;
Random rnd; Random rnd = new Random();
int vb; int vb;
const int maxParticles = 600; const int maxParticles = 600;
public ParticleManager( Game game ) { public ParticleManager( Game game ) {
this.game = game; this.game = game;
rnd = new Random();
vb = game.Graphics.CreateDynamicVb( VertexFormat.P3fT2fC4b, maxParticles * 4 ); vb = game.Graphics.CreateDynamicVb( VertexFormat.P3fT2fC4b, maxParticles * 4 );
game.Events.TerrainAtlasChanged += TerrainAtlasChanged; game.Events.TerrainAtlasChanged += TerrainAtlasChanged;
} }

View File

@ -29,7 +29,8 @@ namespace ClassicalSharp.Renderers {
lastType = (byte)game.Inventory.HeldBlock; lastType = (byte)game.Inventory.HeldBlock;
game.Events.HeldBlockChanged += HeldBlockChanged; game.Events.HeldBlockChanged += HeldBlockChanged;
} }
public void Ready( Game game ) { }
public void Reset( Game game ) { } public void Reset( Game game ) { }
public void OnNewMap( Game game ) { } public void OnNewMap( Game game ) { }
public void OnNewMapLoaded( Game game ) { } public void OnNewMapLoaded( Game game ) { }

View File

@ -27,13 +27,8 @@ namespace ClassicalSharp.Renderers {
this.renderer = renderer; this.renderer = renderer;
info = game.BlockInfo; info = game.BlockInfo;
renderer._1DUsed = game.TerrainAtlas1D.CalcMaxUsedRow( game.TerrainAtlas, info );
renderer.totalUsed = new int[game.TerrainAtlas1D.TexIds.Length];
RecalcBooleans( true );
builder = new ChunkMeshBuilder( game ); builder = new ChunkMeshBuilder( game );
api = game.Graphics; api = game.Graphics;
elementsPerBitmap = game.TerrainAtlas1D.elementsPerBitmap;
game.Events.TerrainAtlasChanged += TerrainAtlasChanged; game.Events.TerrainAtlasChanged += TerrainAtlasChanged;
game.WorldEvents.OnNewMap += OnNewMap; game.WorldEvents.OnNewMap += OnNewMap;
@ -60,8 +55,8 @@ namespace ClassicalSharp.Renderers {
public void Refresh() { public void Refresh() {
chunkPos = new Vector3I( int.MaxValue ); chunkPos = new Vector3I( int.MaxValue );
renderer.totalUsed = new int[game.TerrainAtlas1D.TexIds.Length]; renderer.totalUsed = new int[game.TerrainAtlas1D.TexIds.Length];
if( renderer.chunks == null || game.World.IsNotLoaded ) return; if( renderer.chunks == null || game.World.IsNotLoaded ) return;
ClearChunkCache(); ClearChunkCache();
ResetChunkCache(); ResetChunkCache();
} }
@ -93,11 +88,15 @@ namespace ClassicalSharp.Renderers {
} }
void TerrainAtlasChanged( object sender, EventArgs e ) { void TerrainAtlasChanged( object sender, EventArgs e ) {
bool refreshRequired = elementsPerBitmap != game.TerrainAtlas1D.elementsPerBitmap; if( renderer._1DUsed == -1 ) {
elementsPerBitmap = game.TerrainAtlas1D.elementsPerBitmap; renderer.totalUsed = new int[game.TerrainAtlas1D.TexIds.Length];
renderer._1DUsed = game.TerrainAtlas1D.CalcMaxUsedRow( game.TerrainAtlas, info ); } else {
bool refreshRequired = elementsPerBitmap != game.TerrainAtlas1D.elementsPerBitmap;
if( refreshRequired ) Refresh();
}
if( refreshRequired ) Refresh(); renderer._1DUsed = game.TerrainAtlas1D.CalcMaxUsedRow( game.TerrainAtlas, info );
elementsPerBitmap = game.TerrainAtlas1D.elementsPerBitmap;
RecalcBooleans( true ); RecalcBooleans( true );
} }
@ -139,9 +138,9 @@ namespace ClassicalSharp.Renderers {
} }
for( int i = 0; i < used; i++ ) { for( int i = 0; i < used; i++ ) {
renderer.pendingTranslucent[i] = true; renderer.pendingTranslucent[i] = true;
renderer.usedTranslucent[i] = false; renderer.usedTranslucent[i] = false;
renderer.pendingNormal[i] = true; renderer.pendingNormal[i] = true;
renderer.usedNormal[i] = false; renderer.usedNormal[i] = false;
} }
} }

View File

@ -19,6 +19,7 @@ namespace ClassicalSharp.Renderers {
game.WorldEvents.EnvVariableChanged += EnvVariableChanged; game.WorldEvents.EnvVariableChanged += EnvVariableChanged;
} }
public void Ready( Game game ) { }
public virtual void Reset( Game game ) { OnNewMap( game ); } public virtual void Reset( Game game ) { OnNewMap( game ); }
public abstract void OnNewMap( Game game ); public abstract void OnNewMap( Game game );

View File

@ -33,10 +33,6 @@ namespace ClassicalSharp.Renderers {
game.WorldEvents.EnvVariableChanged += EnvVariableChanged; game.WorldEvents.EnvVariableChanged += EnvVariableChanged;
game.Events.ViewDistanceChanged += ResetSidesAndEdges; game.Events.ViewDistanceChanged += ResetSidesAndEdges;
game.Events.TerrainAtlasChanged += ResetTextures; game.Events.TerrainAtlasChanged += ResetTextures;
MakeTexture( ref edgeTexId, ref lastEdgeTexLoc, map.EdgeBlock );
MakeTexture( ref sideTexId, ref lastSideTexLoc, map.SidesBlock );
ResetSidesAndEdges( null, null );
} }
public void Render( double deltaTime ) { public void Render( double deltaTime ) {
@ -80,7 +76,8 @@ namespace ClassicalSharp.Renderers {
graphics.DeleteVb( edgesVb ); graphics.DeleteVb( edgesVb );
sidesVb = edgesVb = -1; sidesVb = edgesVb = -1;
} }
public void Ready( Game game ) { }
public void Reset( Game game ) { OnNewMap( game ); } public void Reset( Game game ) { OnNewMap( game ); }
public void OnNewMap( Game game ) { public void OnNewMap( Game game ) {

View File

@ -42,7 +42,7 @@ namespace ClassicalSharp.Renderers {
Game game; Game game;
IGraphicsApi api; IGraphicsApi api;
internal int _1DUsed = 1; internal int _1DUsed = -1;
internal ChunkInfo[] chunks, unsortedChunks; internal ChunkInfo[] chunks, unsortedChunks;
internal bool[] usedTranslucent, usedNormal; internal bool[] usedTranslucent, usedNormal;
internal bool[] pendingTranslucent, pendingNormal; internal bool[] pendingTranslucent, pendingNormal;

View File

@ -37,14 +37,14 @@ namespace ClassicalSharp.Renderers {
} }
RenderClouds( deltaTime ); RenderClouds( deltaTime );
ResetFog(); UpdateFog();
} }
protected override void EnvVariableChanged( object sender, EnvVarEventArgs e ) { protected override void EnvVariableChanged( object sender, EnvVarEventArgs e ) {
if( e.Var == EnvVar.SkyColour ) { if( e.Var == EnvVar.SkyColour ) {
ResetSky(); ResetSky();
} else if( e.Var == EnvVar.FogColour ) { } else if( e.Var == EnvVar.FogColour ) {
ResetFog(); UpdateFog();
} else if( e.Var == EnvVar.CloudsColour ) { } else if( e.Var == EnvVar.CloudsColour ) {
ResetClouds(); ResetClouds();
} else if( e.Var == EnvVar.CloudsLevel ) { } else if( e.Var == EnvVar.CloudsLevel ) {
@ -55,6 +55,7 @@ namespace ClassicalSharp.Renderers {
public override void Init( Game game ) { public override void Init( Game game ) {
base.Init( game ); base.Init( game );
graphics.SetFogStart( 0 );
graphics.Fog = true; graphics.Fog = true;
ResetAllEnv( null, null ); ResetAllEnv( null, null );
game.Events.ViewDistanceChanged += ResetAllEnv; game.Events.ViewDistanceChanged += ResetAllEnv;
@ -73,7 +74,7 @@ namespace ClassicalSharp.Renderers {
} }
void ResetAllEnv( object sender, EventArgs e ) { void ResetAllEnv( object sender, EventArgs e ) {
ResetFog(); UpdateFog();
ResetSky(); ResetSky();
ResetClouds(); ResetClouds();
} }
@ -116,30 +117,27 @@ namespace ClassicalSharp.Renderers {
return blend; return blend;
} }
void ResetFog() { void UpdateFog() {
if( map.IsNotLoaded ) return; if( map.IsNotLoaded ) return;
FastColour adjFogCol = FastColour.White; FastColour adjFogCol = FastColour.White;
BlockInfo info = game.BlockInfo; BlockInfo info = game.BlockInfo;
BoundingBox pBounds = game.LocalPlayer.CollisionBounds;
Vector3I headCoords = Vector3I.Floor( game.LocalPlayer.EyePosition ); Vector3 pos = game.CurrentCameraPos;
Vector3 pos = (Vector3)headCoords; Vector3I coords = Vector3I.Floor( pos );
byte headBlock = game.World.SafeGetBlock( headCoords ); byte block = game.World.SafeGetBlock( coords );
BoundingBox blockBB = new BoundingBox( pos + game.BlockInfo.MinBB[headBlock], BoundingBox blockBB = new BoundingBox(
pos + game.BlockInfo.MaxBB[headBlock] ); (Vector3)coords + info.MinBB[block],
BoundingBox localBB = game.LocalPlayer.CollisionBounds; (Vector3)coords + info.MaxBB[block] );
bool intersecting = blockBB.Intersects( localBB );
if( intersecting && info.FogDensity[headBlock] != 0 ) { if( blockBB.Contains( pos ) && info.FogDensity[block] != 0 ) {
graphics.SetFogMode( Fog.Exp ); graphics.SetFogMode( Fog.Exp );
graphics.SetFogDensity( info.FogDensity[headBlock] ); graphics.SetFogDensity( info.FogDensity[block] );
adjFogCol = info.FogColour[headBlock]; adjFogCol = info.FogColour[block];
} else { } else {
// Blend fog and sky together // Blend fog and sky together
float blend = (float)BlendFactor( game.ViewDistance ); float blend = (float)BlendFactor( game.ViewDistance );
adjFogCol = FastColour.Lerp( map.FogCol, map.SkyCol, blend ); adjFogCol = FastColour.Lerp( map.FogCol, map.SkyCol, blend );
graphics.SetFogMode( Fog.Linear ); graphics.SetFogMode( Fog.Linear );
graphics.SetFogStart( 0 );
graphics.SetFogEnd( game.ViewDistance ); graphics.SetFogEnd( game.ViewDistance );
} }
graphics.ClearColour( adjFogCol ); graphics.ClearColour( adjFogCol );
@ -173,7 +171,7 @@ namespace ClassicalSharp.Renderers {
extent = Utils.AdjViewDist( extent ); extent = Utils.AdjViewDist( extent );
int x1 = -extent, x2 = map.Width + extent; int x1 = -extent, x2 = map.Width + extent;
int z1 = -extent, z2 = map.Length + extent; int z1 = -extent, z2 = map.Length + extent;
skyVertices = Utils.CountVertices( x2 - x1, z2 - z1, axisSize ); skyVertices = Utils.CountVertices( x2 - x1, z2 - z1, axisSize );
VertexP3fC4b[] vertices = new VertexP3fC4b[skyVertices]; VertexP3fC4b[] vertices = new VertexP3fC4b[skyVertices];
int height = Math.Max( map.Height + 2 + 6, map.CloudHeight + 6); int height = Math.Max( map.Height + 2 + 6, map.CloudHeight + 6);

View File

@ -1,5 +1,7 @@
// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT // ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT
using System; using System;
using System.IO;
using ClassicalSharp.Events;
using ClassicalSharp.GraphicsAPI; using ClassicalSharp.GraphicsAPI;
using ClassicalSharp.Map; using ClassicalSharp.Map;
using OpenTK; using OpenTK;
@ -12,6 +14,7 @@ namespace ClassicalSharp.Renderers {
World map; World map;
IGraphicsApi graphics; IGraphicsApi graphics;
BlockInfo info; BlockInfo info;
public int RainTexId, SnowTexId;
public void Init( Game game ) { public void Init( Game game ) {
this.game = game; this.game = game;
@ -19,7 +22,8 @@ namespace ClassicalSharp.Renderers {
graphics = game.Graphics; graphics = game.Graphics;
info = game.BlockInfo; info = game.BlockInfo;
weatherVb = graphics.CreateDynamicVb( VertexFormat.P3fT2fC4b, vertices.Length ); weatherVb = graphics.CreateDynamicVb( VertexFormat.P3fT2fC4b, vertices.Length );
} game.Events.TextureChanged += TextureChanged;
}
int weatherVb; int weatherVb;
short[] heightmap; short[] heightmap;
@ -34,7 +38,7 @@ namespace ClassicalSharp.Renderers {
if( weather == Weather.Sunny ) return; if( weather == Weather.Sunny ) return;
if( heightmap == null ) InitHeightmap(); if( heightmap == null ) InitHeightmap();
graphics.BindTexture( weather == Weather.Rainy ? game.RainTexId : game.SnowTexId ); graphics.BindTexture( weather == Weather.Rainy ? RainTexId : SnowTexId );
Vector3 camPos = game.CurrentCameraPos; Vector3 camPos = game.CurrentCameraPos;
Vector3I pos = Vector3I.Floor( camPos ); Vector3I pos = Vector3I.Floor( camPos );
bool moved = pos != lastPos; bool moved = pos != lastPos;
@ -94,6 +98,7 @@ namespace ClassicalSharp.Renderers {
} }
int length, width, maxY, oneY; int length, width, maxY, oneY;
public void Ready( Game game ) { }
public void Reset( Game game ) { OnNewMap( game ); } public void Reset( Game game ) { OnNewMap( game ); }
public void OnNewMap( Game game ) { public void OnNewMap( Game game ) {
@ -108,6 +113,21 @@ namespace ClassicalSharp.Renderers {
oneY = length * width; oneY = length * width;
} }
void TextureChanged( object sender, TextureEventArgs e ) {
if( e.Name == "snow.png" ) {
game.UpdateTexture( ref SnowTexId, e.Data, false );
} else if( e.Name == "rain.png" ) {
game.UpdateTexture( ref RainTexId, e.Data, false );
}
}
public void Dispose() {
game.Graphics.DeleteTexture( ref RainTexId );
game.Graphics.DeleteTexture( ref SnowTexId );
graphics.DeleteDynamicVb( weatherVb );
game.Events.TextureChanged -= TextureChanged;
}
void InitHeightmap() { void InitHeightmap() {
heightmap = new short[map.Width * map.Length]; heightmap = new short[map.Width * map.Length];
for( int i = 0; i < heightmap.Length; i++ ) { for( int i = 0; i < heightmap.Length; i++ ) {
@ -115,10 +135,6 @@ namespace ClassicalSharp.Renderers {
} }
} }
public void Dispose() {
graphics.DeleteDynamicVb( weatherVb );
}
float GetRainHeight( int x, int z ) { float GetRainHeight( int x, int z ) {
if( x < 0 || z < 0 || x >= width || z >= length ) return map.EdgeHeight; if( x < 0 || z < 0 || x >= width || z >= length ) return map.EdgeHeight;
int index = (x * length) + z; int index = (x * length) + z;

View File

@ -14,7 +14,8 @@ namespace ClassicalSharp.Selections {
public void Init( Game game ) { public void Init( Game game ) {
this.game = game; this.game = game;
} }
public void Ready( Game game ) { }
public void Reset( Game game ) { } public void Reset( Game game ) { }
public void OnNewMap( Game game ) { } public void OnNewMap( Game game ) { }
public void OnNewMapLoaded( Game game ) { } public void OnNewMapLoaded( Game game ) { }

View File

@ -16,7 +16,8 @@ namespace ClassicalSharp.Renderers {
vb = graphics.CreateDynamicVb( VertexFormat.P3fC4b, verticesCount ); vb = graphics.CreateDynamicVb( VertexFormat.P3fC4b, verticesCount );
this.game = game; this.game = game;
} }
public void Ready( Game game ) { }
public void Reset( Game game ) { } public void Reset( Game game ) { }
public void OnNewMap( Game game ) { } public void OnNewMap( Game game ) { }
public void OnNewMapLoaded( Game game ) { } public void OnNewMapLoaded( Game game ) { }

View File

@ -17,7 +17,8 @@ namespace ClassicalSharp.Selections {
this.game = game; this.game = game;
Graphics = game.Graphics; Graphics = game.Graphics;
} }
public void Ready( Game game ) { }
public void Reset( Game game ) { selections.Clear(); } public void Reset( Game game ) { selections.Clear(); }
public void OnNewMap( Game game ) { selections.Clear(); } public void OnNewMap( Game game ) { selections.Clear(); }
public void OnNewMapLoaded( Game game ) { } public void OnNewMapLoaded( Game game ) { }

View File

@ -36,8 +36,8 @@ namespace ClassicalSharp.Singleplayer {
game.LocalPlayer.SkinName ); game.LocalPlayer.SkinName );
game.Events.RaiseBlockPermissionsChanged(); game.Events.RaiseBlockPermissionsChanged();
int seed = 500;//new Random().Next(); int seed = new Random().Next();
GenMap( 256, 256, 256, seed, new NotchyGenerator() ); GenMap( 128, 64, 128, seed, new NotchyGenerator() );
} }
char lastCol = '\0'; char lastCol = '\0';
@ -102,9 +102,8 @@ namespace ClassicalSharp.Singleplayer {
IMapGenerator gen = generator; IMapGenerator gen = generator;
game.World.SetData( generatedMap, gen.Width, gen.Height, gen.Length ); game.World.SetData( generatedMap, gen.Width, gen.Height, gen.Length );
generatedMap = null; generatedMap = null;
game.WorldEvents.RaiseOnNewMapLoaded();
ResetPlayerPosition(); ResetPlayerPosition();
game.WorldEvents.RaiseOnNewMapLoaded();
} }
generator = null; generator = null;
@ -133,6 +132,7 @@ namespace ClassicalSharp.Singleplayer {
LocationUpdate update = LocationUpdate.MakePosAndOri( x, y, z, 0, 0, false ); LocationUpdate update = LocationUpdate.MakePosAndOri( x, y, z, 0, 0, false );
game.LocalPlayer.SetLocation( update, false ); game.LocalPlayer.SetLocation( update, false );
game.LocalPlayer.Spawn = new Vector3( x, y, z ); game.LocalPlayer.Spawn = new Vector3( x, y, z );
game.CurrentCameraPos = game.Camera.GetCameraPos( game.LocalPlayer.EyePosition );
} }
} }
} }

View File

@ -3,6 +3,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.IO; using System.IO;
using ClassicalSharp.Events;
using ClassicalSharp.GraphicsAPI; using ClassicalSharp.GraphicsAPI;
#if ANDROID #if ANDROID
using Android.Graphics; using Android.Graphics;
@ -11,7 +12,7 @@ using Android.Graphics;
namespace ClassicalSharp.TexturePack { namespace ClassicalSharp.TexturePack {
/// <summary> Contains and describes the various animations applied to the terrain atlas. </summary> /// <summary> Contains and describes the various animations applied to the terrain atlas. </summary>
public class Animations { public class Animations : IGameComponent {
Game game; Game game;
IGraphicsApi api; IGraphicsApi api;
@ -19,14 +20,34 @@ namespace ClassicalSharp.TexturePack {
FastBitmap fastBmp; FastBitmap fastBmp;
List<AnimationData> animations = new List<AnimationData>(); List<AnimationData> animations = new List<AnimationData>();
public Animations( Game game ) { public void Init( Game game ) {
this.game = game; this.game = game;
api = game.Graphics; api = game.Graphics;
game.Events.TextureChanged += TextureChanged;
}
public void Ready( Game game ) { }
public void Reset( Game game ) { }
public void OnNewMap( Game game ) { }
public void OnNewMapLoaded( Game game ) { }
void TextureChanged( object sender, TextureEventArgs e ) {
if( e.Name == "animations.png" || e.Name == "animation.png" ) {
MemoryStream stream = new MemoryStream( e.Data );
SetAtlas( Platform.ReadBmp( stream ) );
} else if( e.Name == "animations.txt" || e.Name == "animation.txt" ) {
MemoryStream stream = new MemoryStream( e.Data );
StreamReader reader = new StreamReader( stream );
ReadAnimationsDescription( reader );
}
} }
/// <summary> Sets the atlas bitmap that animation frames are contained within. </summary> /// <summary> Sets the atlas bitmap that animation frames are contained within. </summary>
public void SetAtlas( Bitmap bmp ) { public void SetAtlas( Bitmap bmp ) {
Dispose(); if( !FastBitmap.CheckFormat( bmp.PixelFormat ) )
game.Drawer2D.ConvertTo32Bpp( ref bmp );
Clear();
this.bmp = bmp; this.bmp = bmp;
fastBmp = new FastBitmap( bmp, true, true ); fastBmp = new FastBitmap( bmp, true, true );
} }
@ -124,12 +145,17 @@ namespace ClassicalSharp.TexturePack {
/// <summary> Disposes the atlas bitmap that contains animation frames, and clears /// <summary> Disposes the atlas bitmap that contains animation frames, and clears
/// the list of defined animations. </summary> /// the list of defined animations. </summary>
public void Dispose() { public void Clear() {
animations.Clear(); animations.Clear();
if( bmp == null ) return; if( bmp == null ) return;
fastBmp.Dispose(); fastBmp = null; fastBmp.Dispose(); fastBmp = null;
bmp.Dispose(); bmp = null; bmp.Dispose(); bmp = null;
} }
public void Dispose() {
Clear();
game.Events.TextureChanged -= TextureChanged;
}
} }
} }

View File

@ -26,7 +26,7 @@ namespace ClassicalSharp.TexturePack {
void Extract( Stream stream, Game game ) { void Extract( Stream stream, Game game ) {
this.game = game; this.game = game;
game.Animations.Dispose(); game.Animations.Clear();
ZipReader reader = new ZipReader(); ZipReader reader = new ZipReader();
reader.ShouldProcessZipEntry = (f) => true; reader.ShouldProcessZipEntry = (f) => true;
@ -50,53 +50,20 @@ namespace ClassicalSharp.TexturePack {
Bitmap atlas = Platform.ReadBmp( stream ); Bitmap atlas = Platform.ReadBmp( stream );
if( !game.ChangeTerrainAtlas( atlas ) ) atlas.Dispose(); if( !game.ChangeTerrainAtlas( atlas ) ) atlas.Dispose();
break; break;
case "chicken.png":
UpdateTexture( ref cache.ChickenTexId, stream, false ); break;
case "creeper.png":
UpdateTexture( ref cache.CreeperTexId, stream, false ); break;
case "pig.png":
UpdateTexture( ref cache.PigTexId, stream, false ); break;
case "sheep.png":
UpdateTexture( ref cache.SheepTexId, stream, false ); break;
case "skeleton.png":
UpdateTexture( ref cache.SkeletonTexId, stream, false ); break;
case "spider.png":
UpdateTexture( ref cache.SpiderTexId, stream, false ); break;
case "zombie.png":
UpdateTexture( ref cache.ZombieTexId, stream, false ); break;
case "sheep_fur.png":
UpdateTexture( ref cache.SheepFurTexId, stream, false ); break;
case "char.png":
UpdateTexture( ref cache.HumanoidTexId, stream, true ); break;
case "clouds.png": case "clouds.png":
case "cloud.png": case "cloud.png":
UpdateTexture( ref game.CloudsTexId, stream, false ); break; game.UpdateTexture( ref game.CloudsTexId, data, false ); break;
case "rain.png":
UpdateTexture( ref game.RainTexId, stream, false ); break;
case "snow.png":
UpdateTexture( ref game.SnowTexId, stream, false ); break;
case "gui.png": case "gui.png":
UpdateTexture( ref game.GuiTexId, stream, false ); break; game.UpdateTexture( ref game.GuiTexId, data, false ); break;
case "gui_classic.png": case "gui_classic.png":
UpdateTexture( ref game.GuiClassicTexId, stream, false ); break; game.UpdateTexture( ref game.GuiClassicTexId, data, false ); break;
case "animations.png":
case "animation.png":
game.Animations.SetAtlas( Platform.ReadBmp( stream ) ); break;
case "animations.txt":
case "animation.txt":
StreamReader reader = new StreamReader( stream );
game.Animations.ReadAnimationsDescription( reader );
break;
case "particles.png": case "particles.png":
UpdateTexture( ref game.ParticleManager.ParticlesTexId, game.UpdateTexture( ref game.ParticleManager.ParticlesTexId,
stream, false ); break; data, false ); break;
case "default.png": case "default.png":
SetFontBitmap( game, stream ); break; SetFontBitmap( game, stream ); break;
} }
game.Events.RaiseTextureChanged( name, data );
if( !name.EndsWith( ".png" ) ) return;
string tex = name.Substring( 0, name.Length - 4 );
game.Events.RaiseTextureChanged( tex );
} }
void SetFontBitmap( Game game, Stream stream ) { void SetFontBitmap( Game game, Stream stream ) {
@ -106,20 +73,5 @@ namespace ClassicalSharp.TexturePack {
game.Drawer2D.SetFontBitmap( bmp ); game.Drawer2D.SetFontBitmap( bmp );
game.Events.RaiseChatFontChanged(); game.Events.RaiseChatFontChanged();
} }
void UpdateTexture( ref int texId, Stream stream, bool setSkinType ) {
game.Graphics.DeleteTexture( ref texId );
using( Bitmap bmp = Platform.ReadBmp( stream ) ) {
if( setSkinType )
game.DefaultPlayerSkinType = Utils.GetSkinType( bmp );
if( !FastBitmap.CheckFormat( bmp.PixelFormat ) ) {
using( Bitmap bmp32 = game.Drawer2D.ConvertTo32Bpp( bmp ) )
texId = game.Graphics.CreateTexture( bmp32 );
} else {
texId = game.Graphics.CreateTexture( bmp );
}
}
}
} }
} }

View File

@ -60,7 +60,7 @@ namespace ClassicalSharp {
} }
public override void GetPickedBlock( PickedPos pos ) { public override void GetPickedBlock( PickedPos pos ) {
Vector3 dir = Utils.GetDirVector( player.HeadYawRadians, Vector3 dir = Utils.GetDirVector( player.HeadYawRadians,
AdjustPitch( player.PitchDegrees ) ); AdjustPitch( player.PitchDegrees ) );
Vector3 eyePos = player.EyePosition; Vector3 eyePos = player.EyePosition;
float reach = game.LocalPlayer.ReachDistance; float reach = game.LocalPlayer.ReachDistance;
@ -110,15 +110,28 @@ namespace ClassicalSharp {
UpdateMouseRotation(); UpdateMouseRotation();
} }
protected float bobYOffset = 0; protected float bobYOffset = 0, tilt = 0;
bool finishedTilt = true;
protected void CalcViewBobbing( double delta ) { protected void CalcViewBobbing( double delta ) {
LocalPlayer p = game.LocalPlayer;
if( !game.ViewBobbing || !game.LocalPlayer.onGround ) { if( !game.ViewBobbing || !game.LocalPlayer.onGround ) {
tiltMatrix = Matrix4.Identity; // When player leaves the ground, still want to finish the current bob cycle.
bobYOffset = 0; if( finishedTilt || FinishTilt() ) return;
} else {
tiltMatrix = Matrix4.RotateZ( game.LocalPlayer.anim.tilt );
bobYOffset = game.LocalPlayer.anim.bobYOffset * (2.0f/2.5f);
} }
tilt = p.anim.tilt;
tiltMatrix = Matrix4.RotateZ( tilt );
bobYOffset = p.anim.bobYOffset * (2.0f/2.5f);
finishedTilt = false;
}
bool FinishTilt() {
LocalPlayer p = game.LocalPlayer;
if( Math.Sign( tilt ) == Math.Sign( p.anim.tilt ) ) return false;
tiltMatrix = Matrix4.Identity;
bobYOffset = 0;
finishedTilt = true;
return true;
} }
} }
@ -138,7 +151,7 @@ namespace ClassicalSharp {
Vector3 eyePos = player.EyePosition; Vector3 eyePos = player.EyePosition;
eyePos.Y += bobYOffset; eyePos.Y += bobYOffset;
Vector3 dir = -Utils.GetDirVector( player.HeadYawRadians, Vector3 dir = -Utils.GetDirVector( player.HeadYawRadians,
AdjustPitch( player.PitchDegrees ) ); AdjustPitch( player.PitchDegrees ) );
Picking.ClipCameraPos( game, eyePos, dir, dist, game.CameraClipPos ); Picking.ClipCameraPos( game, eyePos, dir, dist, game.CameraClipPos );
Vector3 cameraPos = game.CameraClipPos.IntersectPoint; Vector3 cameraPos = game.CameraClipPos.IntersectPoint;
@ -148,7 +161,7 @@ namespace ClassicalSharp {
public override bool IsThirdPerson { get { return true; } } public override bool IsThirdPerson { get { return true; } }
public override Vector3 GetCameraPos( Vector3 eyePos ) { public override Vector3 GetCameraPos( Vector3 eyePos ) {
Vector3 dir = -Utils.GetDirVector( player.HeadYawRadians, Vector3 dir = -Utils.GetDirVector( player.HeadYawRadians,
AdjustPitch( player.PitchDegrees ) ); AdjustPitch( player.PitchDegrees ) );
Picking.ClipCameraPos( game, eyePos, dir, dist, game.CameraClipPos ); Picking.ClipCameraPos( game, eyePos, dir, dist, game.CameraClipPos );
return game.CameraClipPos.IntersectPoint; return game.CameraClipPos.IntersectPoint;
@ -171,7 +184,7 @@ namespace ClassicalSharp {
Vector3 eyePos = player.EyePosition; Vector3 eyePos = player.EyePosition;
eyePos.Y += bobYOffset; eyePos.Y += bobYOffset;
Vector3 dir = Utils.GetDirVector( player.HeadYawRadians, Vector3 dir = Utils.GetDirVector( player.HeadYawRadians,
AdjustPitch( player.PitchDegrees ) ); AdjustPitch( player.PitchDegrees ) );
Picking.ClipCameraPos( game, eyePos, dir, dist, game.CameraClipPos ); Picking.ClipCameraPos( game, eyePos, dir, dist, game.CameraClipPos );
Vector3 cameraPos = game.CameraClipPos.IntersectPoint; Vector3 cameraPos = game.CameraClipPos.IntersectPoint;
@ -181,7 +194,7 @@ namespace ClassicalSharp {
public override bool IsThirdPerson { get { return true; } } public override bool IsThirdPerson { get { return true; } }
public override Vector3 GetCameraPos( Vector3 eyePos ) { public override Vector3 GetCameraPos( Vector3 eyePos ) {
Vector3 dir = Utils.GetDirVector( player.HeadYawRadians, Vector3 dir = Utils.GetDirVector( player.HeadYawRadians,
AdjustPitch( player.PitchDegrees ) ); AdjustPitch( player.PitchDegrees ) );
Picking.ClipCameraPos( game, eyePos, dir, dist, game.CameraClipPos ); Picking.ClipCameraPos( game, eyePos, dir, dist, game.CameraClipPos );
return game.CameraClipPos.IntersectPoint; return game.CameraClipPos.IntersectPoint;
@ -191,13 +204,13 @@ namespace ClassicalSharp {
public class FirstPersonCamera : PerspectiveCamera { public class FirstPersonCamera : PerspectiveCamera {
public FirstPersonCamera( Game window ) : base( window ) { public FirstPersonCamera( Game window ) : base( window ) {
} }
public override Matrix4 GetView( double delta ) { public override Matrix4 GetView( double delta ) {
CalcViewBobbing( delta ); CalcViewBobbing( delta );
Vector3 eyePos = player.EyePosition; Vector3 eyePos = player.EyePosition;
eyePos.Y += bobYOffset; eyePos.Y += bobYOffset;
Vector3 cameraDir = Utils.GetDirVector( player.HeadYawRadians, Vector3 cameraDir = Utils.GetDirVector( player.HeadYawRadians,
AdjustPitch( player.PitchDegrees ) ); AdjustPitch( player.PitchDegrees ) );
return Matrix4.LookAt( eyePos, eyePos + cameraDir, Vector3.UnitY ) * tiltMatrix; return Matrix4.LookAt( eyePos, eyePos + cameraDir, Vector3.UnitY ) * tiltMatrix;
} }

View File

@ -150,6 +150,10 @@ namespace ClassicalSharp {
return (int)(degrees * period / 360.0) % period; return (int)(degrees * period / 360.0) % period;
} }
public static int DegreesToPacked( double degrees ) {
return (int)(degrees * 256 / 360.0) & 0xFF;
}
public static double PackedToDegrees( byte packed ) { public static double PackedToDegrees( byte packed ) {
return packed * 360.0 / 256.0; return packed * 360.0 / 256.0;
} }