diff --git a/ClassicalSharp/2D/Drawing/IDrawer2D.cs b/ClassicalSharp/2D/Drawing/IDrawer2D.cs index af517dc9e..d3ab77d34 100644 --- a/ClassicalSharp/2D/Drawing/IDrawer2D.cs +++ b/ClassicalSharp/2D/Drawing/IDrawer2D.cs @@ -146,6 +146,18 @@ namespace ClassicalSharp { return Platform.CreateBmp( Utils.NextPowerOf2( size.Width ), Utils.NextPowerOf2( size.Height ) ); } + public FastColour[] Colours = new FastColour[256]; + + public IDrawer2D() { + for( int i = 0; i <= 9; i++ ) + Colours['0' + i] = FastColour.GetHexEncodedCol( i ); + + for( int i = 10; i <= 15; i++) { + Colours['a' + i - 10] = FastColour.GetHexEncodedCol( i ); + Colours['A' + i - 10] = FastColour.GetHexEncodedCol( i ); + } + } + protected List parts = new List( 64 ); protected struct TextPart { public string Text; @@ -168,25 +180,31 @@ namespace ClassicalSharp { } protected void SplitText( string value ) { - int code = 0xF; + 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; if( partLength > 0 ) { string part = value.Substring( i, partLength ); - FastColour col = FastColour.GetHexEncodedCol( code ); + FastColour col = Colours[code]; parts.Add( new TextPart( part, col ) ); } i += partLength + 1; if( nextAnd >= 0 && nextAnd + 1 < value.Length ) { - if( !Utils.TryParseHex( value[nextAnd + 1], out code ) ) { - code = 0xF; - i--;// include the character that isn't a colour code. + if( !ValidColour( value[nextAnd + 1] ) ) { + code = 'F'; + i--; // include the character that isn't a colour code. + } else { + code = value[nextAnd + 1]; } } } } + + internal bool ValidColour( char c ) { + return Colours[c].A > 0; + } } } diff --git a/ClassicalSharp/2D/Screens/ChatScreen.cs b/ClassicalSharp/2D/Screens/ChatScreen.cs index e1c420e4c..216e960f6 100644 --- a/ClassicalSharp/2D/Screens/ChatScreen.cs +++ b/ClassicalSharp/2D/Screens/ChatScreen.cs @@ -136,7 +136,7 @@ namespace ClassicalSharp { indices[i] = -1; Metadata = indices; - ChatLog chat = game.Chat; + Chat chat = game.Chat; chatIndex = chat.Log.Count - chatLines; ResetChat(); status.SetText( 0, chat.Status1.Text ); diff --git a/ClassicalSharp/2D/Widgets/Chat/TextGroupWidget.Formatter.cs b/ClassicalSharp/2D/Widgets/Chat/TextGroupWidget.Formatter.cs index 670a237ef..ff73ca12c 100644 --- a/ClassicalSharp/2D/Widgets/Chat/TextGroupWidget.Formatter.cs +++ b/ClassicalSharp/2D/Widgets/Chat/TextGroupWidget.Formatter.cs @@ -96,8 +96,7 @@ namespace ClassicalSharp { // url and word both need to have %e at the start. if( colIndex >= 0 && colIndex < line.Length - 1 ) { - int hex; - if( Utils.TryParseHex( line[colIndex + 1], out hex ) ) + if( game.Drawer2D.ValidColour( line[colIndex + 1] ) ) part = "&" + line[colIndex + 1] + part; } return part; diff --git a/ClassicalSharp/2D/Widgets/Chat/TextInputWidget.cs b/ClassicalSharp/2D/Widgets/Chat/TextInputWidget.cs index 895b499d1..238bdc036 100644 --- a/ClassicalSharp/2D/Widgets/Chat/TextInputWidget.cs +++ b/ClassicalSharp/2D/Widgets/Chat/TextInputWidget.cs @@ -69,7 +69,7 @@ namespace ClassicalSharp { public override void Init() { X = 5; - chatInputText.WordWrap( ref parts, ref partLens, 64 ); + chatInputText.WordWrap( game.Drawer2D, ref parts, ref partLens, 64 ); maxWidth = 0; DrawTextArgs args = new DrawTextArgs( null, font, true ); @@ -148,16 +148,15 @@ namespace ClassicalSharp { void CalculateCaretCol() { 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 = parts[y].LastIndexOf( '&', x, x + 1 ); - - int hex; + int start = part.LastIndexOf( '&', x, x + 1 ); bool validIndex = start >= 0 && start < partLens[y] - 1; - if( validIndex && Utils.TryParseHex( parts[y][start + 1], out hex ) ) { - caretCol = FastColour.GetHexEncodedCol( hex ); - return; + if( validIndex && drawer.ValidColour( part[start + 1] ) ) { + caretCol = drawer.Colours[part[start + 1]]; return; } if( y > 0 ) x = partLens[y - 1] - 1; } diff --git a/ClassicalSharp/Game/ChatLog.cs b/ClassicalSharp/Game/ChatLog.cs index 8e26ea48d..47d2bbe75 100644 --- a/ClassicalSharp/Game/ChatLog.cs +++ b/ClassicalSharp/Game/ChatLog.cs @@ -6,14 +6,14 @@ using ClassicalSharp.Commands; namespace ClassicalSharp { - public sealed class ChatLog : IDisposable { + public sealed class Chat : IDisposable { public ChatLine Status1, Status2, Status3, BottomRight1, BottomRight2, BottomRight3, Announcement; public ChatLine[] ClientStatus = new ChatLine[6]; Game game; - public ChatLog( Game game ) { + public Chat( Game game ) { this.game = game; } diff --git a/ClassicalSharp/Game/Game.Properties.cs b/ClassicalSharp/Game/Game.Properties.cs index 4d460970d..fc1460e20 100644 --- a/ClassicalSharp/Game/Game.Properties.cs +++ b/ClassicalSharp/Game/Game.Properties.cs @@ -79,7 +79,7 @@ namespace ClassicalSharp { public EntityEvents EntityEvents = new EntityEvents(); public MapEvents MapEvents = new MapEvents(); public InputHandler InputHandler; - public ChatLog Chat; + public Chat Chat; public BlockHandRenderer BlockHandRenderer; public AudioPlayer AudioPlayer; public AxisLinesRenderer AxisLinesRenderer; diff --git a/ClassicalSharp/Game/Game.cs b/ClassicalSharp/Game/Game.cs index 867a07922..d086b9c26 100644 --- a/ClassicalSharp/Game/Game.cs +++ b/ClassicalSharp/Game/Game.cs @@ -50,7 +50,7 @@ namespace ClassicalSharp { UserViewDistance = ViewDistance; CameraClipping = Options.GetBool( OptionsKey.CameraClipping, true ); InputHandler = new InputHandler( this ); - Chat = new ChatLog( this ); + Chat = new Chat( this ); ParticleManager = new ParticleManager( this ); HudScale = Options.GetFloat( OptionsKey.HudScale, 0.25f, 5f, 1f ); ChatScale = Options.GetFloat( OptionsKey.ChatScale, 0.35f, 5f, 1f ); diff --git a/ClassicalSharp/GraphicsAPI/IGraphicsApi.cs b/ClassicalSharp/GraphicsAPI/IGraphicsApi.cs index 14415d0b5..49c4df128 100644 --- a/ClassicalSharp/GraphicsAPI/IGraphicsApi.cs +++ b/ClassicalSharp/GraphicsAPI/IGraphicsApi.cs @@ -214,7 +214,7 @@ namespace ClassicalSharp.GraphicsAPI { } /// Adds a warning to chat if this graphics API has problems with the current user's GPU. - public virtual void WarnIfNecessary( ChatLog chat ) { + public virtual void WarnIfNecessary( Chat chat ) { } /// Informs the graphic api to update its state in preparation for a new frame. diff --git a/ClassicalSharp/GraphicsAPI/OpenGLApi.cs b/ClassicalSharp/GraphicsAPI/OpenGLApi.cs index ccd33a89d..cf4df8f69 100644 --- a/ClassicalSharp/GraphicsAPI/OpenGLApi.cs +++ b/ClassicalSharp/GraphicsAPI/OpenGLApi.cs @@ -393,7 +393,7 @@ namespace ClassicalSharp.GraphicsAPI { isIntelRenderer = renderer.Contains( "Intel" ); } - public override void WarnIfNecessary( ChatLog chat ) { + public override void WarnIfNecessary( Chat chat ) { if( !isIntelRenderer ) return; chat.Add( "&cIntel graphics cards are known to have issues with the OpenGL build." ); diff --git a/ClassicalSharp/GraphicsAPI/OpenGLESApi.cs b/ClassicalSharp/GraphicsAPI/OpenGLESApi.cs index ed1d7a513..e8b77a57f 100644 --- a/ClassicalSharp/GraphicsAPI/OpenGLESApi.cs +++ b/ClassicalSharp/GraphicsAPI/OpenGLESApi.cs @@ -372,7 +372,7 @@ namespace ClassicalSharp.GraphicsAPI { isIntelRenderer = renderer.Contains( "Intel" ); } - public override void WarnIfNecessary( ChatLog chat ) { + public override void WarnIfNecessary( Chat chat ) { if( !isIntelRenderer ) return; chat.Add( "&cIntel graphics cards are known to have issues with the OpenGL build." ); diff --git a/ClassicalSharp/Network/Enums.cs b/ClassicalSharp/Network/Enums.cs index ccadd8edb..3e9808879 100644 --- a/ClassicalSharp/Network/Enums.cs +++ b/ClassicalSharp/Network/Enums.cs @@ -43,6 +43,7 @@ namespace ClassicalSharp { CpeRemoveBlockDefinition = 36, CpeDefineBlockExt = 37, CpeBulkBlockUpdate = 38, + CpeSetTextColor = 39, } public enum MessageType { diff --git a/ClassicalSharp/Network/NetworkProcessor.CPE.cs b/ClassicalSharp/Network/NetworkProcessor.CPE.cs index 8633f33cd..cec84e7bb 100644 --- a/ClassicalSharp/Network/NetworkProcessor.CPE.cs +++ b/ClassicalSharp/Network/NetworkProcessor.CPE.cs @@ -65,7 +65,7 @@ namespace ClassicalSharp { "HackControl", "MessageTypes", "PlayerClick", "FullCP437", "LongerMessages", // proposals - "BlockDefinitions", "BlockDefinitionsExt", + "BlockDefinitions", "BlockDefinitionsExt", "TextColors", }; void HandleCpeExtInfo() { @@ -513,6 +513,17 @@ namespace ClassicalSharp { | buffer[offset + 2] << 8 | buffer[offset + 3]; } + void HandleSetTextColor() { + FastColour col = new FastColour( reader.ReadUInt8(), reader.ReadUInt8(), + reader.ReadUInt8(), reader.ReadUInt8() ); + byte code = reader.ReadUInt8(); + + if( code <= ' ' || code > '~' ) return; // Control chars, space, extended chars cannot be used + if( (code >= '0' && code <= '9') || (code >= 'a' && code <= 'f') + || (code >= 'A' && code <= 'F') ) return; // Standard chars cannot be used. + game.Drawer2D.Colours[code] = col; + } + static SoundType[] stepSnds, breakSnds; static NetworkProcessor() { stepSnds = new SoundType[10]; diff --git a/ClassicalSharp/Network/NetworkProcessor.cs b/ClassicalSharp/Network/NetworkProcessor.cs index 8d53098d1..39c6e69ea 100644 --- a/ClassicalSharp/Network/NetworkProcessor.cs +++ b/ClassicalSharp/Network/NetworkProcessor.cs @@ -159,7 +159,7 @@ namespace ClassicalSharp { 131, 1, 1, 1028, 7, 9, 8, 74, 10, 7, 5, 4, 2, 66, 65, 2, 67, 69, 3, 2, 3, 134, 196, 130, 3, 8, 86, 2, 4, 66, 69, 2, 8, 138, 0, 80, 2, 85, - 1282, + 1282, 6, }; NetWriter writer; @@ -209,7 +209,7 @@ namespace ClassicalSharp { HandleCpeSetBlockPermission, HandleCpeChangeModel, HandleCpeEnvSetMapApperance, HandleCpeEnvWeatherType, HandleCpeHackControl, HandleCpeExtAddEntity2, null, HandleCpeDefineBlock, HandleCpeRemoveBlockDefinition, HandleCpeDefineBlockExt, - HandleBulkBlockUpdate, + HandleBulkBlockUpdate, HandleSetTextColor, }; maxHandledPacket = handlers.Length; } diff --git a/ClassicalSharp/Utils/WrappableStringBuffer.cs b/ClassicalSharp/Utils/WrappableStringBuffer.cs index 48ae46a53..5d7f4f806 100644 --- a/ClassicalSharp/Utils/WrappableStringBuffer.cs +++ b/ClassicalSharp/Utils/WrappableStringBuffer.cs @@ -10,7 +10,7 @@ namespace ClassicalSharp { wrap = new char[capacity]; } - public void WordWrap( ref string[] lines, ref int[] lineLens, int lineSize ) { + public void WordWrap( IDrawer2D drawer, ref string[] lines, ref int[] lineLens, int lineSize ) { int len = Length; for( int i = 0; i < lines.Length; i++ ) { lines[i] = null; @@ -44,7 +44,7 @@ namespace ClassicalSharp { } // Output the used lines - OutputLines( ref lines, linesCount, lineSize, lineLens ); + OutputLines( drawer, ref lines, linesCount, lineSize, lineLens ); value = realText; } @@ -58,14 +58,13 @@ namespace ClassicalSharp { value = wrap; } - void OutputLines( ref string[] lines, int linesCount, int lineSize, int[] lineLens ) { + void OutputLines( IDrawer2D drawer, ref string[] lines, int linesCount, int lineSize, int[] lineLens ) { for( int i = 0; i < capacity; i++ ) { if( value[i] == '\0' ) value[i] = ' '; } // convert %0-f to &0-f for colour preview. for( int i = 0; i < capacity - 1; i++ ) { - int hex; - if( value[i] == '%' && Utils.TryParseHex( value[i + 1], out hex ) ) + if( value[i] == '%' && drawer.ValidColour( value[i + 1] ) ) value[i] = '&'; }