From 7af045f9a9d1333c3a0952d779d0d90f03a3b94c Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Thu, 24 Mar 2016 13:11:26 +1100 Subject: [PATCH] Text input now properly wraps colour codes across multiple lines. (Thanks xnotx123) --- ClassicalSharp/2D/Drawing/IDrawer2D.cs | 28 ++++++- .../Widgets/Chat/TextInputWidget.Handlers.cs | 12 +-- .../2D/Widgets/Chat/TextInputWidget.cs | 80 ++++++++++++------- ClassicalSharp/ClassicalSharp.csproj | 2 +- ClassicalSharp/Network/NetworkProcessor.cs | 1 - ClassicalSharp/Singleplayer/Server.cs | 13 ++- ClassicalSharp/Utils/WrappableStringBuffer.cs | 3 +- 7 files changed, 95 insertions(+), 44 deletions(-) diff --git a/ClassicalSharp/2D/Drawing/IDrawer2D.cs b/ClassicalSharp/2D/Drawing/IDrawer2D.cs index 82abb87fa..9a196e304 100644 --- a/ClassicalSharp/2D/Drawing/IDrawer2D.cs +++ b/ClassicalSharp/2D/Drawing/IDrawer2D.cs @@ -184,8 +184,9 @@ namespace ClassicalSharp { } } + /// Splits the input string by recognised colour codes. (e.g &f) protected void SplitText( string value ) { - char code = 'F'; + char code = 'f'; for( int i = 0; i < value.Length; i++ ) { int nextAnd = value.IndexOf( '&', i ); int partLength = nextAnd == -1 ? value.Length - i : nextAnd - i; @@ -199,8 +200,8 @@ namespace ClassicalSharp { if( nextAnd >= 0 && nextAnd + 1 < value.Length ) { if( !ValidColour( value[nextAnd + 1] ) ) { - code = 'F'; - i--; // include the character that isn't a colour code. + code = 'f'; + i--; // include character that isn't a valid colour code. } else { code = value[nextAnd + 1]; } @@ -208,8 +209,27 @@ namespace ClassicalSharp { } } - internal bool ValidColour( char c ) { + /// Returns whenever the given character is a valid colour code. + public bool ValidColour( char c ) { return (int)c < 256 && Colours[c].A > 0; } + + /// Returns the last valid colour code in the given input, + /// or \0 if no valid colour code was found. + public char LastColour( string input, int start ) { + if( start >= input.Length ) + start = input.Length - 1; + + for( int i = start; i >= 0; i--) { + if( input[i] != '&' ) continue; + if( i < input.Length - 1 && ValidColour( input[i + 1] ) ) + return input[i + 1]; + } + return '\0'; + } + + public static bool IsWhiteColour( char c ) { + return c == '\0' || c == 'f' || c == 'F'; + } } } diff --git a/ClassicalSharp/2D/Widgets/Chat/TextInputWidget.Handlers.cs b/ClassicalSharp/2D/Widgets/Chat/TextInputWidget.Handlers.cs index 1ad4286b1..c046082b5 100644 --- a/ClassicalSharp/2D/Widgets/Chat/TextInputWidget.Handlers.cs +++ b/ClassicalSharp/2D/Widgets/Chat/TextInputWidget.Handlers.cs @@ -81,7 +81,7 @@ namespace ClassicalSharp { buffer.Append( ref index, " matching names: " ); foreach( string match in matches ) { - if( (match.Length + 1 + buffer.Length) > 64 ) break; + if( (match.Length + 1 + buffer.Length) > LineLength ) break; buffer.Append( ref index, match ); buffer.Append( ref index, ' ' ); } @@ -163,9 +163,9 @@ namespace ClassicalSharp { void UpKey( bool controlDown ) { if( controlDown ) { int pos = caretPos == -1 ? chatInputText.Length : caretPos; - if( pos < 64 ) return; + if( pos < LineLength ) return; - caretPos = pos - 64; + caretPos = pos - LineLength; CalculateCaretData(); return; } @@ -185,8 +185,8 @@ namespace ClassicalSharp { void DownKey( bool controlDown ) { if( controlDown ) { - if( caretPos == -1 || caretPos >= (lines - 1) * 64 ) return; - caretPos += 64; + if( caretPos == -1 || caretPos >= (lines - 1) * LineLength ) return; + caretPos += LineLength; CalculateCaretData(); return; } @@ -290,7 +290,7 @@ namespace ClassicalSharp { CalculateCaretData(); return; } } - offset += partLens[y]; + offset += line.Length; } caretPos = -1; CalculateCaretData(); diff --git a/ClassicalSharp/2D/Widgets/Chat/TextInputWidget.cs b/ClassicalSharp/2D/Widgets/Chat/TextInputWidget.cs index 91c6b54fb..778c7d8b4 100644 --- a/ClassicalSharp/2D/Widgets/Chat/TextInputWidget.cs +++ b/ClassicalSharp/2D/Widgets/Chat/TextInputWidget.cs @@ -42,7 +42,7 @@ namespace ClassicalSharp { graphicsApi.Texturing = false; int y = Y, x = X; for( int i = 0; i < sizes.Length; i++ ) { - bool caretAtEnd = caretTex.Y1 == y && (indexX == 64 || caretPos == -1); + bool caretAtEnd = caretTex.Y1 == y && (indexX == LineLength || caretPos == -1); int offset = caretAtEnd ? defaultWidth : 0; graphicsApi.Draw2DQuad( x + 5, y, sizes[i].Width + offset, sizes[i].Height, backColour ); y += sizes[i].Height; @@ -64,9 +64,11 @@ namespace ClassicalSharp { int indexX, indexY; bool shownWarning; + int LineLength { get { return game.Network.ServerSupportsPartialMessages ? 64 : 62; } } + public override void Init() { X = 5; - chatInputText.WordWrap( game.Drawer2D, ref parts, ref partLens, 64 ); + chatInputText.WordWrap( game.Drawer2D, ref parts, ref partLens, LineLength ); maxWidth = 0; DrawTextArgs args = new DrawTextArgs( null, font, true ); @@ -77,10 +79,10 @@ namespace ClassicalSharp { } bool supports = game.Network.ServerSupportsPartialMessages; - if( chatInputText.Length > 64 && !shownWarning && !supports ) { + if( chatInputText.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 <= 64 && shownWarning ) { + } else if( chatInputText.Length <= LineLength && shownWarning ) { game.Chat.Add( null, MessageType.ClientStatus6 ); shownWarning = false; } @@ -89,14 +91,14 @@ namespace ClassicalSharp { altText.texture.Y1 = game.Height - (YOffset + Height + altText.texture.Height); altText.Y = altText.texture.Y1; CalculateCaretData(); - } + } void CalculateCaretData() { if( caretPos >= chatInputText.Length ) caretPos = -1; chatInputText.MakeCoords( caretPos, partLens, out indexX, out indexY ); DrawTextArgs args = new DrawTextArgs( null, font, true ); - if( indexX == 64 ) { + if( indexX == LineLength ) { caretTex.X1 = 10 + sizes[indexY].Width; caretCol = FastColour.Yellow; } else { @@ -111,7 +113,7 @@ namespace ClassicalSharp { caretCol = FastColour.Scale( FastColour.White, 0.8f ); } caretTex.Y1 = sizes[0].Height * indexY + Y; - CalculateCaretCol(); + CalcCaretColour(); } void DrawString() { @@ -130,6 +132,9 @@ namespace ClassicalSharp { for( int i = 0; i < parts.Length; i++ ) { if( parts[i] == null ) break; args.Text = parts[i]; + char lastCol = GetLastColour( 0, i ); + if( !IDrawer2D.IsWhiteColour( lastCol ) ) + args.Text = "&" + lastCol + args.Text; drawer.DrawChatText( ref args, 0, realHeight ); realHeight += sizes[i].Height; @@ -143,20 +148,23 @@ namespace ClassicalSharp { Width = size.Width; } - void CalculateCaretCol() { + void CalcCaretColour() { + IDrawer2D drawer = game.Drawer2D; + char code = GetLastColour( indexX, indexY ); + if( code != '\0' ) + caretCol = drawer.Colours[code]; + } + + char GetLastColour( int indexX, int indexY ) { int x = indexX; IDrawer2D drawer = game.Drawer2D; for( int y = indexY; y >= 0; y-- ) { string part = parts[y]; - if( x == partLens[y] ) x = partLens[y] - 1; - int start = part.LastIndexOf( '&', x, x + 1 ); - bool validIndex = start >= 0 && start < partLens[y] - 1; - - if( validIndex && drawer.ValidColour( part[start + 1] ) ) { - caretCol = drawer.Colours[part[start + 1]]; return; - } - if( y > 0 ) x = partLens[y - 1] - 1; + char code = drawer.LastColour( part, x ); + if( code != '\0' ) return code; + if( y > 0 ) x = parts[y - 1].Length; } + return '\0'; } public override void Dispose() { @@ -197,26 +205,40 @@ namespace ClassicalSharp { string allText = chatInputText.GetString(); game.Chat.InputLog.Add( allText ); - if( game.Network.ServerSupportsPartialMessages ) { - // don't automatically word wrap the message. - while( allText.Length > 64 ) { - game.Chat.Send( allText.Substring( 0, 64 ), true ); - allText = allText.Substring( 64 ); - } - game.Chat.Send( allText, false ); - return; + if( game.Network.ServerSupportsPartialMessages ) + SendWithPartial( allText ); + else + SendNormal(); + } + + void SendWithPartial( string allText ) { + // don't automatically word wrap the message. + while( allText.Length > 64 ) { + game.Chat.Send( allText.Substring( 0, 64 ), true ); + allText = allText.Substring( 64 ); } - + game.Chat.Send( allText, false ); + } + + void SendNormal() { int packetsCount = 0; for( int i = 0; i < parts.Length; i++ ) { if( parts[i] == null ) break; packetsCount++; } + // split up into both partial and final packet. - for( int i = 0; i < packetsCount - 1; i++ ) { - game.Chat.Send( parts[i], true ); - } - game.Chat.Send( parts[packetsCount - 1], false ); + for( int i = 0; i < packetsCount - 1; i++ ) + SendNormalText( i, true ); + SendNormalText( packetsCount - 1, false ); + } + + void SendNormalText( int i, bool partial ) { + string text = parts[i]; + char lastCol = GetLastColour( 0, i ); + if( !IDrawer2D.IsWhiteColour( lastCol ) ) + text = "&" + lastCol + text; + game.Chat.Send( text, partial ); } public void Clear() { diff --git a/ClassicalSharp/ClassicalSharp.csproj b/ClassicalSharp/ClassicalSharp.csproj index fc7401889..adbbdae1f 100644 --- a/ClassicalSharp/ClassicalSharp.csproj +++ b/ClassicalSharp/ClassicalSharp.csproj @@ -4,7 +4,7 @@ {BEB1C785-5CAD-48FF-A886-876BF0A318D4} Debug AnyCPU - Exe + WinExe ClassicalSharp ClassicalSharp v2.0 diff --git a/ClassicalSharp/Network/NetworkProcessor.cs b/ClassicalSharp/Network/NetworkProcessor.cs index 8798c25d7..7690696a2 100644 --- a/ClassicalSharp/Network/NetworkProcessor.cs +++ b/ClassicalSharp/Network/NetworkProcessor.cs @@ -137,7 +137,6 @@ namespace ClassicalSharp { lastOpcode = (PacketId)opcode; Action handler = handlers[opcode]; lastPacket = DateTime.UtcNow; - Console.WriteLine( "IN " + lastOpcode ); if( handler == null ) throw new NotImplementedException( "Unsupported packet:" + (PacketId)opcode ); diff --git a/ClassicalSharp/Singleplayer/Server.cs b/ClassicalSharp/Singleplayer/Server.cs index a855e4dc2..c612ca4b9 100644 --- a/ClassicalSharp/Singleplayer/Server.cs +++ b/ClassicalSharp/Singleplayer/Server.cs @@ -37,9 +37,20 @@ namespace ClassicalSharp.Singleplayer { GenMap( 128, 64, 128, seed, new NotchyGenerator() ); } + char lastCol = '\0'; public override void SendChat( string text, bool partial ) { - if( String.IsNullOrEmpty( text ) ) return; + if( !String.IsNullOrEmpty( text ) ) + AddChat( text ); + if( !partial ) lastCol = '\0'; + } + + void AddChat( string text ) { text = text.TrimEnd().Replace( '%', '&' ); + if( !IDrawer2D.IsWhiteColour( lastCol ) ) + text = "&" + lastCol + text; + + char col = game.Drawer2D.LastColour( text, text.Length ); + if( col != '\0' ) lastCol = col; game.Chat.Add( text, MessageType.Normal ); } diff --git a/ClassicalSharp/Utils/WrappableStringBuffer.cs b/ClassicalSharp/Utils/WrappableStringBuffer.cs index 5d7f4f806..30ba6f1bd 100644 --- a/ClassicalSharp/Utils/WrappableStringBuffer.cs +++ b/ClassicalSharp/Utils/WrappableStringBuffer.cs @@ -68,9 +68,8 @@ namespace ClassicalSharp { value[i] = '&'; } - for( int i = 0; i < Math.Max( 1, linesCount ); i++ ) { + for( int i = 0; i < Math.Max( 1, linesCount ); i++ ) lines[i] = new String( value, i * lineSize, lineLens[i] ); - } } int WrapLine( int index, int lineSize ) {