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() {
if( HandlesAllInput ) {
game.chatInInputBuffer = textInput.chatInputText.ToString();
game.chatInInputBuffer = textInput.buffer.ToString();
game.CursorVisible = false;
} else {
game.chatInInputBuffer = null;
@ -321,8 +321,8 @@ namespace ClassicalSharp.Gui {
HandlesAllInput = true;
game.Keyboard.KeyRepeat = true;
textInput.chatInputText.Clear();
textInput.chatInputText.Append( 0, initialText );
textInput.buffer.Clear();
textInput.buffer.Append( 0, initialText );
textInput.Init();
}

View File

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

View File

@ -22,18 +22,18 @@ namespace ClassicalSharp.Gui {
textFont = new Font( game.FontName, 16, FontStyle.Bold );
arrowFont = new Font( game.FontName, 18, 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 );
buttons = new ButtonWidget[] {
MakeText( 0, -80, Get( 0 ) ),
MakeText( 0, -40, Get( 1 ) ),
MakeText( 0, -100, Get( 0 ) ),
MakeText( 0, -50, Get( 1 ) ),
MakeText( 0, 0, Get( 2 ) ),
MakeText( 0, 40, Get( 3 ) ),
MakeText( 0, 80, Get( 4 ) ),
MakeText( 0, 50, Get( 3 ) ),
MakeText( 0, 100, Get( 4 ) ),
Make( -160, 0, "<", (g, w) => PageClick( false ) ),
Make( 160, 0, ">", (g, w) => PageClick( true ) ),
Make( -220, 0, "<", (g, w) => PageClick( false ) ),
Make( 220, 0, ">", (g, w) => PageClick( true ) ),
null,
};
}
@ -52,12 +52,12 @@ namespace ClassicalSharp.Gui {
}
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 );
}
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 ) );
}

View File

@ -6,7 +6,7 @@ using ClassicalSharp.GraphicsAPI;
namespace ClassicalSharp.Gui {
public class FpsScreen : Screen {
public class FpsScreen : Screen, IGameComponent {
Font font, posFont;
StringBuffer text;
@ -15,6 +15,12 @@ namespace ClassicalSharp.Gui {
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;
Texture posTex;
public override void Render( double delta ) {
@ -158,7 +164,9 @@ namespace ClassicalSharp.Gui {
if( game.Fov != game.DefaultFov ) text.Append( ref index, "Zoom fov " )
.AppendNum( ref index, lastFov ).Append( ref index, " " );
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 " );
hackStates.SetText( text.GetString() );
}
@ -166,7 +174,7 @@ namespace ClassicalSharp.Gui {
const string possibleChars = "0123456789-, ()";
int[] widths = new int[possibleChars.Length];
int baseWidth, curX, posHeight;
int baseWidth, curX;
float texWidth;
void MakePosTextWidget() {
DrawTextArgs args = new DrawTextArgs( "", posFont, true );

View File

@ -15,7 +15,8 @@ namespace ClassicalSharp.Gui {
PlayerListWidget playerList;
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 OnNewMap( Game game ) { }
public void OnNewMapLoaded( Game game ) { }
@ -35,7 +36,7 @@ namespace ClassicalSharp.Gui {
//graphicsApi.BindTexture( game.TerrainAtlas.TexId );
//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 );
// NOTE: Should usually be caught by KeyUp, but just in case.
if( !game.IsKeyDown( KeyBinding.PlayerList ) ) {
@ -76,8 +77,6 @@ namespace ClassicalSharp.Gui {
}
public void LoseFocus() {
if( playerList != null )
playerList.Dispose();
game.CursorVisible = true;
}

View File

@ -132,20 +132,12 @@ namespace ClassicalSharp.Gui {
RecreateBlockInfoTexture();
}
static string[] normalNames = null;
void UpdateBlockInfoString( Block block ) {
if( normalNames == null )
MakeNormalNames();
int index = 0;
buffer.Clear();
buffer.Append( ref index, "&f" );
string value = game.BlockInfo.Name[(byte)block];
if( (byte)block < BlockInfo.CpeBlocksCount && value == "Invalid" ) {
buffer.Append( ref index, normalNames[(byte)block] );
} else {
string value = game.BlockInfo.GetBlockName( (byte)block );
buffer.Append( ref index, value );
}
if( game.ClassicMode ) return;
buffer.Append( ref index, " (ID: " );
@ -157,32 +149,6 @@ namespace ClassicalSharp.Gui {
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;
void RecreateBlockInfoTexture() {
if( selIndex == lastCreatedIndex ) return;

View File

@ -14,29 +14,31 @@ namespace ClassicalSharp.Gui {
MenuInputWidget inputWidget;
TextWidget descWidget;
const int overwriteIndex = 2;
FastColour grey = new FastColour( 150, 150, 150 );
public override void Render( double delta ) {
RenderMenuBounds();
api.Texturing = true;
RenderMenuWidgets( delta );
inputWidget.Render( delta );
if( descWidget != null )
descWidget.Render( delta );
if( descWidget != null ) descWidget.Render( delta );
api.Texturing = false;
if( textPath != null ) {
float cX = game.Width / 2, cY = game.Height / 2;
api.Draw2DQuad( cX - 250, cY + 90, 500, 2, grey );
if( textPath == null ) return;
SaveMap( textPath );
textPath = null;
}
}
public override bool HandlesKeyPress( char key ) {
RemoveOverwriteButton();
RemoveOverwrites();
return inputWidget.HandlesKeyPress( key );
}
public override bool HandlesKeyDown( Key key ) {
RemoveOverwriteButton();
RemoveOverwrites();
if( key == Key.Escape ) {
game.SetNewScreen( null );
return true;
@ -54,12 +56,16 @@ namespace ClassicalSharp.Gui {
regularFont = new Font( game.FontName, 16, FontStyle.Regular );
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() );
widgets = new [] {
ButtonWidget.Create( game, 260, 50, 60, 30, "Save", Anchor.Centre,
Anchor.Centre, titleFont, OkButtonClick ),
widgets = new Widget[] {
ButtonWidget.Create( game, 0, 20, 301, 40, "Save", Anchor.Centre,
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,
MakeBack( false, titleFont,
(g, w) => g.SetNewScreen( new PauseScreen( g ) ) ),
@ -79,54 +85,58 @@ namespace ClassicalSharp.Gui {
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;
string text = inputWidget.GetText();
if( text.Length == 0 ) {
MakeDescWidget( "Please enter a filename" );
return;
MakeDescWidget( "&ePlease enter a filename" ); return;
}
string file = Path.ChangeExtension( text, ".cw" );
string file = Path.ChangeExtension( text, ext );
text = Path.Combine( Program.AppDirectory, "maps" );
text = Path.Combine( text, file );
if( File.Exists( text ) ) {
widgets[1] = ButtonWidget.Create( game, 0, 90, 260, 30, "Overwrite existing?",
Anchor.Centre, Anchor.Centre, titleFont, OverwriteButtonClick );
if( File.Exists( text ) && widget.Metadata == null ) {
((ButtonWidget)widget).SetText( "&cOverwrite existing?" );
((ButtonWidget)widget).Metadata = true;
} else {
// 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.
MakeDescWidget( "Saving.." );
textPath = text;
RemoveOverwriteButton();
RemoveOverwrites();
}
}
void OverwriteButtonClick( Game game, Widget widget, MouseButton mouseBtn ) {
if( mouseBtn != MouseButton.Left ) return;
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 RemoveOverwrites() {
RemoveOverwrite( widgets[0] ); RemoveOverwrite( widgets[1] );
}
void RemoveOverwriteButton() {
if( widgets[1] == null ) return;
widgets[1].Dispose();
widgets[1] = null;
void RemoveOverwrite( Widget widget ) {
ButtonWidget button = (ButtonWidget)widget;
if( button.Metadata == null ) return;
button.Metadata = null;
button.SetText( "Save" );
}
string textPath;
void SaveMap( string path ) {
bool classic = path.EndsWith( ".cw" );
try {
if( File.Exists( path ) )
File.Delete( path );
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 );
}
} catch( Exception ex ) {
@ -140,7 +150,7 @@ namespace ClassicalSharp.Gui {
void MakeDescWidget( string text ) {
DisposeDescWidget();
descWidget = ChatTextWidget.Create( game, 0, 90, text,
descWidget = ChatTextWidget.Create( game, 0, 65, text,
Anchor.Centre, Anchor.Centre, regularFont );
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -26,6 +26,7 @@ namespace ClassicalSharp.Audio {
SetSound( game.UseSound );
}
public void Ready( Game game ) { }
public void Reset( Game game ) { }
public void OnNewMap( Game game ) { }
public void OnNewMapLoaded( Game game ) { }

View File

@ -58,6 +58,40 @@ namespace ClassicalSharp {
public const byte MaxDefinedBlock = byte.MaxValue;
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() {
for( int tile = 1; tile < BlocksCount; tile++ ) {
MaxBB[tile].Y = 1;
@ -189,6 +223,45 @@ namespace ClassicalSharp {
StepSounds[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 {

View File

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

View File

@ -21,10 +21,14 @@ namespace ClassicalSharp.Commands {
Register( new HelpCommand() );
Register( new InfoCommand() );
Register( new RenderTypeCommand() );
if( game.Network.IsSinglePlayer )
if( game.Network.IsSinglePlayer ) {
Register( new ModelCommand() );
Register( new CuboidCommand() );
}
}
public void Ready( Game game ) { }
public void Reset( Game game ) { }
public void OnNewMap( 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 ) {
if( e.Texture != "char" ) return;
if( e.Name != "char.png" ) return;
for( int i = 0; i < Players.Length; i++ ) {
if( Players[i] == null || Players[i].TextureId != -1 ) continue;
Players[i].SkinType = game.DefaultPlayerSkinType;

View File

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

View File

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

View File

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

View File

@ -10,12 +10,12 @@ namespace ClassicalSharp.Events {
IdEventArgs idArgs = new IdEventArgs();
/// <summary> Raised when an entity is spawned in the current world. </summary>
public event EventHandler<IdEventArgs> EntityAdded;
internal void RaiseEntityAdded( byte id ) { idArgs.Id = id; Raise( EntityAdded, idArgs ); }
public event EventHandler<IdEventArgs> Added;
internal void RaiseAdded( byte id ) { idArgs.Id = id; Raise( Added, idArgs ); }
/// <summary> Raised when an entity is despawned from the current world. </summary>
public event EventHandler<IdEventArgs> EntityRemoved;
internal void RaiseEntityRemoved( byte id ) { idArgs.Id = id; Raise( EntityRemoved, idArgs ); }
public event EventHandler<IdEventArgs> Removed;
internal void RaiseRemoved( byte id ) { idArgs.Id = id; Raise( Removed, idArgs ); }
/// <summary> Raised when a new CPE player list entry is created. </summary>
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>
public event EventHandler<TextureEventArgs> TextureChanged;
internal void RaiseTextureChanged( string texture ) {
texArgs.Texture = texture; Raise( TextureChanged, texArgs ); }
internal void RaiseTextureChanged( string name, byte[] data ) {
texArgs.Name = name; texArgs.Data = data; Raise( TextureChanged, texArgs ); }
/// <summary> Raised when the user changed their view/fog distance. </summary>
public event EventHandler ViewDistanceChanged;
@ -78,8 +78,10 @@ namespace ClassicalSharp.Events {
public sealed class TextureEventArgs : EventArgs {
/// <summary> Location of the texture within a texture pack. (e.g. "snow", "default", "char") </summary>
/// <remarks> See TexturePackExtractor for a list of supported textures. </remarks>
public string Texture;
/// <summary> Location of the file within a texture pack, without a directory. (e.g. "snow.png") </summary>
public string Name;
/// <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

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

View File

@ -25,9 +25,12 @@ namespace ClassicalSharp {
/// <summary> Represents a game component. </summary>
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 );
/// <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>
void Reset( Game game );
@ -102,6 +105,7 @@ namespace ClassicalSharp {
public OtherEvents Events = new OtherEvents();
public EntityEvents EntityEvents = new EntityEvents();
public WorldEvents WorldEvents = new WorldEvents();
public UserEvents UserEvents = new UserEvents();
public InputHandler InputHandler;
public Chat Chat;
public BlockHandRenderer BlockHandRenderer;
@ -170,7 +174,7 @@ namespace ClassicalSharp {
public Vector3 CurrentCameraPos;
public Animations Animations;
internal int CloudsTexId, RainTexId, SnowTexId, GuiTexId, GuiClassicTexId;
internal int CloudsTexId, GuiTexId, GuiClassicTexId;
internal bool screenshotRequested;
internal EntryList AcceptedUrls = new EntryList( "acceptedurls.txt" );
internal EntryList DeniedUrls = new EntryList( "deniedurls.txt" );

View File

@ -84,13 +84,7 @@ namespace ClassicalSharp {
TerrainAtlas1D = new TerrainAtlas1D( Graphics );
TerrainAtlas = new TerrainAtlas2D( Graphics, Drawer2D );
Animations = new Animations( this );
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 );
Animations = AddComponent( new Animations() );
Inventory = AddComponent( new Inventory() );
BlockInfo.SetDefaultBlockPermissions( Inventory.CanPlace, Inventory.CanDelete );
@ -124,8 +118,7 @@ namespace ClassicalSharp {
//Graphics.DepthWrite = true;
Graphics.AlphaBlendFunc( BlendFunc.SourceAlpha, BlendFunc.InvSourceAlpha );
Graphics.AlphaTestFunc( CompareFunc.Greater, 0.5f );
fpsScreen = new FpsScreen( this );
fpsScreen.Init();
fpsScreen = AddComponent( new FpsScreen( this ) );
hudScreen = AddComponent( new HudScreen( this ) );
Culling = new FrustumCulling();
Picking = AddComponent( new PickedPosRenderer() );
@ -134,6 +127,9 @@ namespace ClassicalSharp {
foreach( IGameComponent comp in Components )
comp.Init( this );
ExtractInitialTexturePack();
foreach( IGameComponent comp in Components )
comp.Ready( this );
LoadIcon();
string connectString = "Connecting to " + IPAddress + ":" + Port + "..";
@ -145,6 +141,15 @@ namespace ClassicalSharp {
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() {
ClassicMode = Options.GetBool( "mode-classic", false );
ClassicHacks = Options.GetBool( OptionsKey.AllowClassicHacks, false );
@ -531,10 +536,7 @@ namespace ClassicalSharp {
Graphics.DeleteIb( defaultIb );
Graphics.Dispose();
Drawer2D.DisposeInstance();
Animations.Dispose();
Graphics.DeleteTexture( ref CloudsTexId );
Graphics.DeleteTexture( ref RainTexId );
Graphics.DeleteTexture( ref SnowTexId );
Graphics.DeleteTexture( ref GuiTexId );
Graphics.DeleteTexture( ref GuiClassicTexId );
foreach( WarningScreen screen in WarningOverlays )
@ -555,6 +557,26 @@ namespace ClassicalSharp {
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,
bool nullContext, int width, int height ) {
window = new DesktopWindow( this, username, nullContext, width, height );

View File

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

View File

@ -38,41 +38,45 @@ namespace ClassicalSharp {
// always play delete animations, even if we aren't picking a block.
if( left ) game.BlockHandRenderer.SetAnimationClick( true );
if( !game.SelectedPos.Valid ) return;
BlockInfo info = game.BlockInfo;
if( middle ) {
Vector3I pos = game.SelectedPos.BlockPos;
byte block = 0;
if( game.World.IsValidPos( pos ) && (block = game.World.GetBlock( pos )) != 0
&& (inv.CanPlace[block] || inv.CanDelete[block]) ) {
if( !game.World.IsValidPos( pos ) ) return;
byte old = game.World.GetBlock( pos );
if( !info.IsAir[old] && (inv.CanPlace[old] || inv.CanDelete[old]) ) {
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.HeldBlock = (Block)block;
inv.HeldBlock = (Block)old;
}
} else if( left ) {
Vector3I pos = game.SelectedPos.BlockPos;
byte block = 0;
if( game.World.IsValidPos( pos ) && (block = game.World.GetBlock( pos )) != 0
&& inv.CanDelete[block] ) {
game.ParticleManager.BreakBlockEffect( pos, block );
game.AudioPlayer.PlayDigSound( game.BlockInfo.DigSounds[block] );
if( !game.World.IsValidPos( pos ) ) return;
byte old = game.World.GetBlock( pos );
if( !info.IsAir[old] && inv.CanDelete[old] ) {
game.ParticleManager.BreakBlockEffect( pos, old );
game.AudioPlayer.PlayDigSound( game.BlockInfo.DigSounds[old] );
game.UpdateBlock( pos.X, pos.Y, pos.Z, 0 );
game.Network.SendSetBlock( pos.X, pos.Y, pos.Z, false, (byte)inv.HeldBlock );
game.UserEvents.RaiseBlockChanged( pos, old, 0 );
}
} else if( right ) {
Vector3I pos = game.SelectedPos.TranslatedPos;
if( !game.World.IsValidPos( pos ) ) return;
byte old = game.World.GetBlock( pos );
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.AudioPlayer.PlayDigSound( game.BlockInfo.StepSounds[block] );
game.Network.SendSetBlock( pos.X, pos.Y, pos.Z, true, block );
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 ) {
if( value == fogStart ) return;
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 ) {
FogParam( FogParameter.FogDensity, value, ref lastFogDensity );
}
public override void SetFogStart( float value ) {
FogParam( FogParameter.FogStart, value, ref lastFogStart );
GL.Fogf( FogParameter.FogStart, value );
}
public override void SetFogEnd( float value ) {
@ -95,11 +95,10 @@ namespace ClassicalSharp.GraphicsAPI {
}
static void FogParam( FogParameter param, float value, ref float last ) {
if( value != last ) {
if( value == last ) return;
GL.Fogf( param, value );
last = value;
}
}
Fog lastFogMode = (Fog)999;
FogMode[] fogModes;

View File

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

View File

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

View File

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

View File

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

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, int index, int count ) { writer.Write( v, index, count ); }
public void Write( string value ) {
ushort len = (ushort)value.Length;
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;
}
/// <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
/// the given bounding box on the X axis. </summary>
public bool XIntersects( BoundingBox box ) {

View File

@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using ClassicalSharp.Events;
using ClassicalSharp.GraphicsAPI;
namespace ClassicalSharp.Model {
@ -23,6 +24,7 @@ namespace ClassicalSharp.Model {
model.CreateParts();
cache["humanoid"] = model;
cache["human"] = cache["humanoid"];
game.Events.TextureChanged += TextureChanged;
}
internal int vb;
@ -62,10 +64,11 @@ namespace ClassicalSharp.Model {
}
public void Dispose() {
foreach( var entry in cache ) {
foreach( var entry in cache )
entry.Value.Dispose();
}
api.DeleteDynamicVb( vb );
game.Events.TextureChanged -= TextureChanged;
api.DeleteTexture( ref ChickenTexId );
api.DeleteTexture( ref CreeperTexId );
api.DeleteTexture( ref PigTexId );
@ -76,5 +79,28 @@ namespace ClassicalSharp.Model {
api.DeleteTexture( ref SheepFurTexId );
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 ) {
Bitmap bmp = (Bitmap)item.Data;
game.World.TextureUrl = item.Url;
game.Animations.Dispose();
game.Animations.Clear();
if( !FastBitmap.CheckFormat( bmp.PixelFormat ) ) {
Utils.LogDebug( "Converting terrain atlas to 32bpp image" );
@ -142,7 +142,7 @@ namespace ClassicalSharp {
if( bmp == null ) {// Should never happen, but handle anyways.
ExtractDefault();
} else if( item.Url != game.World.TextureUrl ) {
game.Animations.Dispose();
game.Animations.Clear();
if( !game.ChangeTerrainAtlas( bmp ) ) { bmp.Dispose(); return; }
}
@ -155,7 +155,7 @@ namespace ClassicalSharp {
if( game.AsyncDownloader.TryGetItem( "texturePack", out item ) ) {
if( item.Data != null ) {
game.World.TextureUrl = item.Url;
game.Animations.Dispose();
game.Animations.Clear();
TexturePackExtractor extractor = new TexturePackExtractor();
extractor.Extract( (byte[])item.Data, game );
@ -166,7 +166,7 @@ namespace ClassicalSharp {
if( data == null ) { // Should never happen, but handle anyways.
ExtractDefault();
} else if( item.Url != game.World.TextureUrl ) {
game.Animations.Dispose();
game.Animations.Clear();
TexturePackExtractor extractor = new TexturePackExtractor();
extractor.Extract( data, game );
}

View File

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

View File

@ -37,6 +37,7 @@ namespace ClassicalSharp.Network {
worker.Start();
}
public void Ready( Game game ) { }
public void Reset( Game game ) {
lock( requestLocker )
requests.Clear();

View File

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

View File

@ -30,6 +30,7 @@ namespace ClassicalSharp.Renderers {
game.Events.HeldBlockChanged += HeldBlockChanged;
}
public void Ready( Game game ) { }
public void Reset( Game game ) { }
public void OnNewMap( Game game ) { }
public void OnNewMapLoaded( Game game ) { }

View File

@ -27,13 +27,8 @@ namespace ClassicalSharp.Renderers {
this.renderer = renderer;
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 );
api = game.Graphics;
elementsPerBitmap = game.TerrainAtlas1D.elementsPerBitmap;
game.Events.TerrainAtlasChanged += TerrainAtlasChanged;
game.WorldEvents.OnNewMap += OnNewMap;
@ -93,11 +88,15 @@ namespace ClassicalSharp.Renderers {
}
void TerrainAtlasChanged( object sender, EventArgs e ) {
if( renderer._1DUsed == -1 ) {
renderer.totalUsed = new int[game.TerrainAtlas1D.TexIds.Length];
} else {
bool refreshRequired = elementsPerBitmap != game.TerrainAtlas1D.elementsPerBitmap;
elementsPerBitmap = game.TerrainAtlas1D.elementsPerBitmap;
renderer._1DUsed = game.TerrainAtlas1D.CalcMaxUsedRow( game.TerrainAtlas, info );
if( refreshRequired ) Refresh();
}
renderer._1DUsed = game.TerrainAtlas1D.CalcMaxUsedRow( game.TerrainAtlas, info );
elementsPerBitmap = game.TerrainAtlas1D.elementsPerBitmap;
RecalcBooleans( true );
}

View File

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

View File

@ -33,10 +33,6 @@ namespace ClassicalSharp.Renderers {
game.WorldEvents.EnvVariableChanged += EnvVariableChanged;
game.Events.ViewDistanceChanged += ResetSidesAndEdges;
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 ) {
@ -81,6 +77,7 @@ namespace ClassicalSharp.Renderers {
sidesVb = edgesVb = -1;
}
public void Ready( Game game ) { }
public void Reset( Game game ) { OnNewMap( game ); }
public void OnNewMap( Game game ) {

View File

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

View File

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

View File

@ -1,5 +1,7 @@
// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT
using System;
using System.IO;
using ClassicalSharp.Events;
using ClassicalSharp.GraphicsAPI;
using ClassicalSharp.Map;
using OpenTK;
@ -12,6 +14,7 @@ namespace ClassicalSharp.Renderers {
World map;
IGraphicsApi graphics;
BlockInfo info;
public int RainTexId, SnowTexId;
public void Init( Game game ) {
this.game = game;
@ -19,6 +22,7 @@ namespace ClassicalSharp.Renderers {
graphics = game.Graphics;
info = game.BlockInfo;
weatherVb = graphics.CreateDynamicVb( VertexFormat.P3fT2fC4b, vertices.Length );
game.Events.TextureChanged += TextureChanged;
}
int weatherVb;
@ -34,7 +38,7 @@ namespace ClassicalSharp.Renderers {
if( weather == Weather.Sunny ) return;
if( heightmap == null ) InitHeightmap();
graphics.BindTexture( weather == Weather.Rainy ? game.RainTexId : game.SnowTexId );
graphics.BindTexture( weather == Weather.Rainy ? RainTexId : SnowTexId );
Vector3 camPos = game.CurrentCameraPos;
Vector3I pos = Vector3I.Floor( camPos );
bool moved = pos != lastPos;
@ -94,6 +98,7 @@ namespace ClassicalSharp.Renderers {
}
int length, width, maxY, oneY;
public void Ready( Game game ) { }
public void Reset( Game game ) { OnNewMap( game ); }
public void OnNewMap( Game game ) {
@ -108,6 +113,21 @@ namespace ClassicalSharp.Renderers {
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() {
heightmap = new short[map.Width * map.Length];
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 ) {
if( x < 0 || z < 0 || x >= width || z >= length ) return map.EdgeHeight;
int index = (x * length) + z;

View File

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

View File

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

View File

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

View File

@ -36,8 +36,8 @@ namespace ClassicalSharp.Singleplayer {
game.LocalPlayer.SkinName );
game.Events.RaiseBlockPermissionsChanged();
int seed = 500;//new Random().Next();
GenMap( 256, 256, 256, seed, new NotchyGenerator() );
int seed = new Random().Next();
GenMap( 128, 64, 128, seed, new NotchyGenerator() );
}
char lastCol = '\0';
@ -102,9 +102,8 @@ namespace ClassicalSharp.Singleplayer {
IMapGenerator gen = generator;
game.World.SetData( generatedMap, gen.Width, gen.Height, gen.Length );
generatedMap = null;
game.WorldEvents.RaiseOnNewMapLoaded();
ResetPlayerPosition();
game.WorldEvents.RaiseOnNewMapLoaded();
}
generator = null;
@ -133,6 +132,7 @@ namespace ClassicalSharp.Singleplayer {
LocationUpdate update = LocationUpdate.MakePosAndOri( x, y, z, 0, 0, false );
game.LocalPlayer.SetLocation( update, false );
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.Drawing;
using System.IO;
using ClassicalSharp.Events;
using ClassicalSharp.GraphicsAPI;
#if ANDROID
using Android.Graphics;
@ -11,7 +12,7 @@ using Android.Graphics;
namespace ClassicalSharp.TexturePack {
/// <summary> Contains and describes the various animations applied to the terrain atlas. </summary>
public class Animations {
public class Animations : IGameComponent {
Game game;
IGraphicsApi api;
@ -19,14 +20,34 @@ namespace ClassicalSharp.TexturePack {
FastBitmap fastBmp;
List<AnimationData> animations = new List<AnimationData>();
public Animations( Game game ) {
public void Init( Game game ) {
this.game = game;
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>
public void SetAtlas( Bitmap bmp ) {
Dispose();
if( !FastBitmap.CheckFormat( bmp.PixelFormat ) )
game.Drawer2D.ConvertTo32Bpp( ref bmp );
Clear();
this.bmp = bmp;
fastBmp = new FastBitmap( bmp, true, true );
}
@ -124,12 +145,17 @@ namespace ClassicalSharp.TexturePack {
/// <summary> Disposes the atlas bitmap that contains animation frames, and clears
/// the list of defined animations. </summary>
public void Dispose() {
public void Clear() {
animations.Clear();
if( bmp == null ) return;
fastBmp.Dispose(); fastBmp = 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 ) {
this.game = game;
game.Animations.Dispose();
game.Animations.Clear();
ZipReader reader = new ZipReader();
reader.ShouldProcessZipEntry = (f) => true;
@ -50,53 +50,20 @@ namespace ClassicalSharp.TexturePack {
Bitmap atlas = Platform.ReadBmp( stream );
if( !game.ChangeTerrainAtlas( atlas ) ) atlas.Dispose();
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 "cloud.png":
UpdateTexture( ref game.CloudsTexId, stream, false ); break;
case "rain.png":
UpdateTexture( ref game.RainTexId, stream, false ); break;
case "snow.png":
UpdateTexture( ref game.SnowTexId, stream, false ); break;
game.UpdateTexture( ref game.CloudsTexId, data, false ); break;
case "gui.png":
UpdateTexture( ref game.GuiTexId, stream, false ); break;
game.UpdateTexture( ref game.GuiTexId, data, false ); break;
case "gui_classic.png":
UpdateTexture( ref game.GuiClassicTexId, stream, 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;
game.UpdateTexture( ref game.GuiClassicTexId, data, false ); break;
case "particles.png":
UpdateTexture( ref game.ParticleManager.ParticlesTexId,
stream, false ); break;
game.UpdateTexture( ref game.ParticleManager.ParticlesTexId,
data, false ); break;
case "default.png":
SetFontBitmap( game, stream ); break;
}
if( !name.EndsWith( ".png" ) ) return;
string tex = name.Substring( 0, name.Length - 4 );
game.Events.RaiseTextureChanged( tex );
game.Events.RaiseTextureChanged( name, data );
}
void SetFontBitmap( Game game, Stream stream ) {
@ -106,20 +73,5 @@ namespace ClassicalSharp.TexturePack {
game.Drawer2D.SetFontBitmap( bmp );
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

@ -110,15 +110,28 @@ namespace ClassicalSharp {
UpdateMouseRotation();
}
protected float bobYOffset = 0;
protected float bobYOffset = 0, tilt = 0;
bool finishedTilt = true;
protected void CalcViewBobbing( double delta ) {
LocalPlayer p = game.LocalPlayer;
if( !game.ViewBobbing || !game.LocalPlayer.onGround ) {
// When player leaves the ground, still want to finish the current bob cycle.
if( finishedTilt || FinishTilt() ) return;
}
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;
} else {
tiltMatrix = Matrix4.RotateZ( game.LocalPlayer.anim.tilt );
bobYOffset = game.LocalPlayer.anim.bobYOffset * (2.0f/2.5f);
}
finishedTilt = true;
return true;
}
}

View File

@ -150,6 +150,10 @@ namespace ClassicalSharp {
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 ) {
return packed * 360.0 / 256.0;
}