mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-14 01:55:19 -04:00
Sadly, it turns out that our memory string optimisation procedures corrupted the headp after the GC was run. Turns out because (I might be wrong though) that the GC appears to try to use leftover string space for heap allocations, which sometimes caused random corruptions but mostly crashes as were directly modifying the underlying string length. Fixes #51.
This commit is contained in:
parent
f3306f48fd
commit
0c7dec86e4
@ -130,7 +130,7 @@ namespace ClassicalSharp {
|
|||||||
|
|
||||||
Block block = blocksTable[selectedIndex].BlockId;
|
Block block = blocksTable[selectedIndex].BlockId;
|
||||||
UpdateBlockInfoString( block );
|
UpdateBlockInfoString( block );
|
||||||
string value = buffer.UpdateCachedString();
|
string value = buffer.GetString();
|
||||||
|
|
||||||
Size size = Utils2D.MeasureSize( value, font, true );
|
Size size = Utils2D.MeasureSize( value, font, true );
|
||||||
int x = startX + ( blockSize * blocksPerRow ) / 2 - size.Width / 2;
|
int x = startX + ( blockSize * blocksPerRow ) / 2 - size.Width / 2;
|
||||||
|
@ -38,7 +38,7 @@ namespace ClassicalSharp {
|
|||||||
.Append( ref ptr2, ", vertices: " ).AppendNum( ref ptr2, game.Vertices );
|
.Append( ref ptr2, ", vertices: " ).AppendNum( ref ptr2, game.Vertices );
|
||||||
}
|
}
|
||||||
|
|
||||||
string textString = text.UpdateCachedString();
|
string textString = text.GetString();
|
||||||
fpsTextWidget.SetText( textString );
|
fpsTextWidget.SetText( textString );
|
||||||
maxDelta = 0;
|
maxDelta = 0;
|
||||||
accumulator = 0;
|
accumulator = 0;
|
||||||
|
@ -40,7 +40,7 @@ namespace ClassicalSharp {
|
|||||||
X = 10;
|
X = 10;
|
||||||
DrawTextArgs caretArgs = new DrawTextArgs( graphicsApi, "_", Color.White, false );
|
DrawTextArgs caretArgs = new DrawTextArgs( graphicsApi, "_", Color.White, false );
|
||||||
chatCaretTexture = Utils2D.MakeTextTexture( boldFont, 0, 0, ref caretArgs );
|
chatCaretTexture = Utils2D.MakeTextTexture( boldFont, 0, 0, ref caretArgs );
|
||||||
string value = chatInputText.UpdateCachedString();
|
string value = chatInputText.GetString();
|
||||||
|
|
||||||
if( chatInputText.Empty ) {
|
if( chatInputText.Empty ) {
|
||||||
caretPos = -1;
|
caretPos = -1;
|
||||||
@ -50,27 +50,32 @@ namespace ClassicalSharp {
|
|||||||
if( caretPos == -1 ) {
|
if( caretPos == -1 ) {
|
||||||
chatCaretTexture.X1 = 10 + size.Width;
|
chatCaretTexture.X1 = 10 + size.Width;
|
||||||
size.Width += chatCaretTexture.Width;
|
size.Width += chatCaretTexture.Width;
|
||||||
|
DrawString( size, value, true );
|
||||||
} else {
|
} else {
|
||||||
string subString = chatInputText.GetSubstring( caretPos );
|
string subString = chatInputText.GetSubstring( caretPos );
|
||||||
Size trimmedSize = Utils2D.MeasureSize( subString, font, false );
|
Size trimmedSize = Utils2D.MeasureSize( subString, font, false );
|
||||||
chatInputText.RestoreLength();
|
|
||||||
|
|
||||||
chatCaretTexture.X1 = 10 + trimmedSize.Width;
|
chatCaretTexture.X1 = 10 + trimmedSize.Width;
|
||||||
Size charSize = Utils2D.MeasureSize( new String( value[caretPos], 1 ), font, false );
|
Size charSize = Utils2D.MeasureSize( new String( value[caretPos], 1 ), font, false );
|
||||||
chatCaretTexture.Width = charSize.Width;
|
chatCaretTexture.Width = charSize.Width;
|
||||||
|
DrawString( size, value, false );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawString( Size size, string value, bool skipCheck ) {
|
||||||
size.Height = Math.Max( size.Height, chatCaretTexture.Height );
|
size.Height = Math.Max( size.Height, chatCaretTexture.Height );
|
||||||
|
|
||||||
int y = game.Height - ChatInputYOffset - size.Height / 2;
|
int y = game.Height - ChatInputYOffset - size.Height / 2;
|
||||||
|
|
||||||
using( Bitmap bmp = Utils2D.CreatePow2Bitmap( size ) ) {
|
using( Bitmap bmp = Utils2D.CreatePow2Bitmap( size ) ) {
|
||||||
using( Graphics g = Graphics.FromImage( bmp ) ) {
|
using( Graphics g = Graphics.FromImage( bmp ) ) {
|
||||||
Utils2D.DrawRect( g, backColour, 0, 0, bmp.Width, bmp.Height );
|
Utils2D.DrawRect( g, backColour, 0, 0, bmp.Width, bmp.Height );
|
||||||
DrawTextArgs args = new DrawTextArgs( graphicsApi, value, Color.White, false );
|
DrawTextArgs args = new DrawTextArgs( graphicsApi, value, Color.White, false );
|
||||||
args.SkipPartsCheck = true;
|
args.SkipPartsCheck = skipCheck;
|
||||||
Utils2D.DrawText( g, font, ref args, 0, 0 );
|
Utils2D.DrawText( g, font, ref args, 0, 0 );
|
||||||
}
|
}
|
||||||
chatInputTexture = Utils2D.Make2DTexture( graphicsApi, bmp, size, 10, y );
|
chatInputTexture = Utils2D.Make2DTexture( graphicsApi, bmp, size, 10, y );
|
||||||
}
|
}
|
||||||
|
|
||||||
chatCaretTexture.Y1 = chatInputTexture.Y1;
|
chatCaretTexture.Y1 = chatInputTexture.Y1;
|
||||||
Y = y;
|
Y = y;
|
||||||
Width = size.Width;
|
Width = size.Width;
|
||||||
|
@ -341,7 +341,7 @@ namespace ClassicalSharp {
|
|||||||
sentWomId = true;
|
sentWomId = true;
|
||||||
}
|
}
|
||||||
gzipStream = null;
|
gzipStream = null;
|
||||||
GC.Collect();
|
GC.Collect( 0 );
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case PacketId.SetBlock:
|
case PacketId.SetBlock:
|
||||||
|
@ -3,34 +3,11 @@ using System.Reflection;
|
|||||||
|
|
||||||
namespace ClassicalSharp {
|
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 sealed unsafe class StringBuffer {
|
||||||
|
|
||||||
internal string value;
|
internal string value;
|
||||||
internal int capacity;
|
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 ) {
|
public StringBuffer( int capacity ) {
|
||||||
this.capacity = capacity;
|
this.capacity = capacity;
|
||||||
value = new String( '\0', capacity );
|
value = new String( '\0', capacity );
|
||||||
@ -140,11 +117,8 @@ namespace ClassicalSharp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Hack that modifies the underlying string's length to avoid memory allocations. </summary>
|
public string GetString() {
|
||||||
/// <returns> The underlying string - ***do not*** store this because it is mutable!
|
return value.TrimEnd( trimEnd );
|
||||||
/// You should only use this string for temporary measuring and drawing. </returns>
|
|
||||||
public string UpdateCachedString() {
|
|
||||||
return supportsLengthSetting ? SetLength( Length ) : value.TrimEnd( trimEnd );
|
|
||||||
}
|
}
|
||||||
static char[] trimEnd = { '\0' };
|
static char[] trimEnd = { '\0' };
|
||||||
|
|
||||||
@ -153,18 +127,7 @@ namespace ClassicalSharp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public string GetSubstring( int length ) {
|
public string GetSubstring( int length ) {
|
||||||
return supportsLengthSetting ? SetLength( length ) : GetCopy( length );
|
return GetCopy( length );
|
||||||
}
|
|
||||||
|
|
||||||
public void RestoreLength() {
|
|
||||||
if( supportsLengthSetting )
|
|
||||||
SetLength( Length );
|
|
||||||
}
|
|
||||||
|
|
||||||
string SetLength( int len ) {
|
|
||||||
arrayField.SetValue( value, len + 1 );
|
|
||||||
lengthField.SetValue( value, len );
|
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string GetCopy( int len ) {
|
string GetCopy( int len ) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user