diff --git a/ClassicalSharp/2D/Screens/BlockSelectScreen.cs b/ClassicalSharp/2D/Screens/BlockSelectScreen.cs index 4f748071e..6780c8753 100644 --- a/ClassicalSharp/2D/Screens/BlockSelectScreen.cs +++ b/ClassicalSharp/2D/Screens/BlockSelectScreen.cs @@ -130,7 +130,7 @@ namespace ClassicalSharp { Block block = blocksTable[selectedIndex].BlockId; UpdateBlockInfoString( block ); - string value = buffer.UpdateCachedString(); + string value = buffer.GetString(); Size size = Utils2D.MeasureSize( value, font, true ); int x = startX + ( blockSize * blocksPerRow ) / 2 - size.Width / 2; diff --git a/ClassicalSharp/2D/Screens/FpsScreen.cs b/ClassicalSharp/2D/Screens/FpsScreen.cs index d5de28130..2302255ef 100644 --- a/ClassicalSharp/2D/Screens/FpsScreen.cs +++ b/ClassicalSharp/2D/Screens/FpsScreen.cs @@ -38,7 +38,7 @@ namespace ClassicalSharp { .Append( ref ptr2, ", vertices: " ).AppendNum( ref ptr2, game.Vertices ); } - string textString = text.UpdateCachedString(); + string textString = text.GetString(); fpsTextWidget.SetText( textString ); maxDelta = 0; accumulator = 0; diff --git a/ClassicalSharp/2D/Widgets/TextInputWidget.cs b/ClassicalSharp/2D/Widgets/TextInputWidget.cs index 498de49b2..08c6e7753 100644 --- a/ClassicalSharp/2D/Widgets/TextInputWidget.cs +++ b/ClassicalSharp/2D/Widgets/TextInputWidget.cs @@ -40,7 +40,7 @@ namespace ClassicalSharp { X = 10; DrawTextArgs caretArgs = new DrawTextArgs( graphicsApi, "_", Color.White, false ); chatCaretTexture = Utils2D.MakeTextTexture( boldFont, 0, 0, ref caretArgs ); - string value = chatInputText.UpdateCachedString(); + string value = chatInputText.GetString(); if( chatInputText.Empty ) { caretPos = -1; @@ -50,27 +50,32 @@ namespace ClassicalSharp { if( caretPos == -1 ) { chatCaretTexture.X1 = 10 + size.Width; size.Width += chatCaretTexture.Width; + DrawString( size, value, true ); } else { string subString = chatInputText.GetSubstring( caretPos ); Size trimmedSize = Utils2D.MeasureSize( subString, font, false ); - chatInputText.RestoreLength(); chatCaretTexture.X1 = 10 + trimmedSize.Width; Size charSize = Utils2D.MeasureSize( new String( value[caretPos], 1 ), font, false ); chatCaretTexture.Width = charSize.Width; + DrawString( size, value, false ); } + } + + void DrawString( Size size, string value, bool skipCheck ) { size.Height = Math.Max( size.Height, chatCaretTexture.Height ); - int y = game.Height - ChatInputYOffset - size.Height / 2; + using( Bitmap bmp = Utils2D.CreatePow2Bitmap( size ) ) { using( Graphics g = Graphics.FromImage( bmp ) ) { Utils2D.DrawRect( g, backColour, 0, 0, bmp.Width, bmp.Height ); DrawTextArgs args = new DrawTextArgs( graphicsApi, value, Color.White, false ); - args.SkipPartsCheck = true; + args.SkipPartsCheck = skipCheck; Utils2D.DrawText( g, font, ref args, 0, 0 ); } chatInputTexture = Utils2D.Make2DTexture( graphicsApi, bmp, size, 10, y ); } + chatCaretTexture.Y1 = chatInputTexture.Y1; Y = y; Width = size.Width; diff --git a/ClassicalSharp/Network/NetworkProcessor.cs b/ClassicalSharp/Network/NetworkProcessor.cs index ad1dda4d0..4c6fbef12 100644 --- a/ClassicalSharp/Network/NetworkProcessor.cs +++ b/ClassicalSharp/Network/NetworkProcessor.cs @@ -341,7 +341,7 @@ namespace ClassicalSharp { sentWomId = true; } gzipStream = null; - GC.Collect(); + GC.Collect( 0 ); } break; case PacketId.SetBlock: diff --git a/ClassicalSharp/Utils/StringBuffer.cs b/ClassicalSharp/Utils/StringBuffer.cs index 13b3076bd..fee39b6ef 100644 --- a/ClassicalSharp/Utils/StringBuffer.cs +++ b/ClassicalSharp/Utils/StringBuffer.cs @@ -3,34 +3,11 @@ using System.Reflection; namespace ClassicalSharp { - // Class used to minimise memory allocations of strings. - // Really, only useful for FpsScreen and TextInputWidget as they allocate lots of very small strings. - // Seriously, you should *not* use this anywhere else, as Empty and Length are O(N). internal sealed unsafe class StringBuffer { internal string value; internal int capacity; - static readonly FieldInfo arrayField, lengthField; - static bool supportsLengthSetting; - - static StringBuffer() { - if( OpenTK.Configuration.RunningOnMono ) - return; - - arrayField = typeof( String ).GetField( "m_arrayLength", BindingFlags.NonPublic | BindingFlags.Instance ); - lengthField = typeof( String ).GetField( "m_stringLength", BindingFlags.NonPublic | BindingFlags.Instance ); - - // Make sure we are running on a framework that has both methods - - // otherwise we play it safe and just use TrimEnd(). - if( arrayField != null && lengthField != null ) { - supportsLengthSetting = true; - } else { - arrayField = null; - lengthField = null; - } - } - public StringBuffer( int capacity ) { this.capacity = capacity; value = new String( '\0', capacity ); @@ -140,11 +117,8 @@ namespace ClassicalSharp { } } - /// Hack that modifies the underlying string's length to avoid memory allocations. - /// The underlying string - ***do not*** store this because it is mutable! - /// You should only use this string for temporary measuring and drawing. - public string UpdateCachedString() { - return supportsLengthSetting ? SetLength( Length ) : value.TrimEnd( trimEnd ); + public string GetString() { + return value.TrimEnd( trimEnd ); } static char[] trimEnd = { '\0' }; @@ -153,18 +127,7 @@ namespace ClassicalSharp { } public string GetSubstring( int length ) { - return supportsLengthSetting ? SetLength( length ) : GetCopy( length ); - } - - public void RestoreLength() { - if( supportsLengthSetting ) - SetLength( Length ); - } - - string SetLength( int len ) { - arrayField.SetValue( value, len + 1 ); - lengthField.SetValue( value, len ); - return value; + return GetCopy( length ); } string GetCopy( int len ) {