diff --git a/ClassicalSharp/2D/Screens/ChatScreen.cs b/ClassicalSharp/2D/Screens/ChatScreen.cs index 90c0ea1f1..2d11be7e7 100644 --- a/ClassicalSharp/2D/Screens/ChatScreen.cs +++ b/ClassicalSharp/2D/Screens/ChatScreen.cs @@ -15,7 +15,7 @@ namespace ClassicalSharp { int chatLines; Texture announcementTex; TextInputWidget textInput; - TextGroupWidget status, bottomRight, normalChat; + TextGroupWidget status, bottomRight, normalChat, clientStatus; bool suppressNextPress = true; int chatIndex; int blockSize; @@ -25,6 +25,7 @@ namespace ClassicalSharp { bottomRight.Render( delta ); UpdateChatYOffset( false ); + RenderClientStatus(); DateTime now = DateTime.UtcNow; if( HandlesAllInput ) normalChat.Render( delta ); @@ -54,24 +55,40 @@ namespace ClassicalSharp { } } + void RenderClientStatus() { + int y = clientStatus.Y + clientStatus.Height; + for( int i = 0; i < clientStatus.Textures.Length; i++ ) { + Texture texture = clientStatus.Textures[i]; + if( !texture.IsValid ) continue; + + y -= texture.Height; + texture.Y1 = y; + texture.Render( graphicsApi ); + } + } + static FastColour backColour = new FastColour( 60, 60, 60, 180 ); public void RenderBackground() { int height = normalChat.GetUsedHeight(); int y = normalChat.Y + normalChat.Height - height - 5; int x = normalChat.X - 5; - int width = normalChat.Width + 10; + int width = Math.Max( clientStatus.Width, normalChat.Width ) + 10; - if( height > 0 ) - graphicsApi.Draw2DQuad( x, y, width, height + 10, backColour ); + int boxHeight = height + clientStatus.GetUsedHeight(); + if( boxHeight > 0 ) + graphicsApi.Draw2DQuad( x, y, width, boxHeight + 10, backColour ); } int inputOldHeight = -1; void UpdateChatYOffset( bool force ) { int height = textInput.RealHeight; if( force || height != inputOldHeight ) { - normalChat.YOffset = height + blockSize + 15; - int y = game.Height - normalChat.Height - normalChat.YOffset; + clientStatus.YOffset = height + blockSize + 15; + int y = game.Height - clientStatus.Height - clientStatus.YOffset; + clientStatus.MoveTo( clientStatus.X, y ); + normalChat.YOffset = height + blockSize + 15; + y = game.Height - normalChat.Height - clientStatus.GetUsedHeight() - normalChat.YOffset; normalChat.MoveTo( normalChat.X, y ); inputOldHeight = height; } @@ -107,6 +124,13 @@ namespace ClassicalSharp { normalChat.HorizontalAnchor = Anchor.LeftOrTop; normalChat.VerticalAnchor = Anchor.BottomOrRight; normalChat.Init(); + clientStatus = new TextGroupWidget( game, chatLines, chatFont, chatUnderlineFont ); + clientStatus.XOffset = 10; + clientStatus.YOffset = blockSize * 2 + 15; + clientStatus.HorizontalAnchor = Anchor.LeftOrTop; + clientStatus.VerticalAnchor = Anchor.BottomOrRight; + clientStatus.Init(); + int[] indices = new int[chatLines]; for( int i = 0; i < indices.Length; i++ ) indices[i] = -1; @@ -120,8 +144,10 @@ namespace ClassicalSharp { status.SetText( 2, chat.Status3.Text ); bottomRight.SetText( 2, chat.BottomRight1.Text ); bottomRight.SetText( 1, chat.BottomRight2.Text ); - bottomRight.SetText( 0,chat.BottomRight3.Text ); + bottomRight.SetText( 0, chat.BottomRight3.Text ); UpdateAnnouncement( chat.Announcement.Text ); + for( int i = 0; i < chat.ClientStatus.Length; i++ ) + clientStatus.SetText( i, chat.ClientStatus[i].Text ); if( game.chatInInputBuffer != null ) { OpenTextInputBar( game.chatInInputBuffer ); @@ -132,8 +158,8 @@ namespace ClassicalSharp { } void ChatReceived( object sender, ChatEventArgs e ) { - CpeMessage type = e.Type; - if( type == CpeMessage.Normal ) { + MessageType type = e.Type; + if( type == MessageType.Normal ) { chatIndex++; List chat = game.Chat.Log; normalChat.PushUpAndReplaceLast( chat[chatIndex + chatLines - 1].Text ); @@ -142,12 +168,15 @@ namespace ClassicalSharp { for( int i = 0; i < chatLines - 1; i++ ) metadata[i] = metadata[i + 1]; metadata[chatLines - 1] = chatIndex + chatLines - 1; - } else if( type >= CpeMessage.Status1 && type <= CpeMessage.Status3 ) { - status.SetText( (int)( type - CpeMessage.Status1 ), e.Text ); - } else if( type >= CpeMessage.BottomRight1 && type <= CpeMessage.BottomRight3 ) { - bottomRight.SetText( 2 - (int)( type - CpeMessage.BottomRight1 ), e.Text ); - } else if( type == CpeMessage.Announcement ) { + } else if( type >= MessageType.Status1 && type <= MessageType.Status3 ) { + status.SetText( (int)(type - MessageType.Status1), e.Text ); + } else if( type >= MessageType.BottomRight1 && type <= MessageType.BottomRight3 ) { + bottomRight.SetText( 2 - (int)(type - MessageType.BottomRight1), e.Text ); + } else if( type == MessageType.Announcement ) { UpdateAnnouncement( e.Text ); + } else if( type >= MessageType.ClientStatus1 && type <= MessageType.ClientStatus6 ) { + clientStatus.SetText( (int)(type - MessageType.ClientStatus1), e.Text ); + UpdateChatYOffset( true ); } } @@ -168,6 +197,8 @@ namespace ClassicalSharp { textInput.DisposeFully(); status.Dispose(); bottomRight.Dispose(); + clientStatus.Dispose(); + graphicsApi.DeleteTexture( ref announcementTex ); game.Events.ChatReceived -= ChatReceived; game.Events.ChatFontChanged -= ChatFontChanged; @@ -195,7 +226,7 @@ namespace ClassicalSharp { void UpdateAnnouncement( string text ) { DrawTextArgs args = new DrawTextArgs( text, announcementFont, true ); - announcementTex = game.Drawer2D.MakeTextTexture( ref args, 0, 0 ); + announcementTex = game.Drawer2D.MakeChatTextTexture( ref args, 0, 0 ); announcementTex.X1 = game.Width / 2 - announcementTex.Width / 2; announcementTex.Y1 = game.Height / 4 - announcementTex.Height / 2; } @@ -307,7 +338,6 @@ namespace ClassicalSharp { } else if( game.ClickableChat ) { for( int i = 0; i < text.Length; i++ ) { if( !IsValidInputChar( text[i] ) ) { - Console.WriteLine( i + "," + text[i] ); game.Chat.Add( "&eChatline contained characters that can't be sent on this server." ); return true; } diff --git a/ClassicalSharp/2D/Widgets/Chat/TextInputWidget.Handlers.cs b/ClassicalSharp/2D/Widgets/Chat/TextInputWidget.Handlers.cs index f1bf4763f..b70e70d67 100644 --- a/ClassicalSharp/2D/Widgets/Chat/TextInputWidget.Handlers.cs +++ b/ClassicalSharp/2D/Widgets/Chat/TextInputWidget.Handlers.cs @@ -39,8 +39,8 @@ namespace ClassicalSharp { else if( key == Key.End ) EndKey(); else if( game.Network.ServerSupportsFullCP437 && key == game.InputHandler.Keys[KeyBinding.ExtendedInput] ) - altText.SetActive( !altText.Active ); - else if( controlDown && !OtherKey( key ) ) return false; + altText.SetActive( !altText.Active ); + else if( controlDown && !OtherKey( key ) ) return false; return true; } @@ -107,12 +107,6 @@ namespace ClassicalSharp { return; } - if( controlDown ) { - caretPos += chatInputText.GetForwardLength( caretPos ); - CalculateCaretData(); - return; - } - if( !chatInputText.Empty && caretPos != -1 ) { caretPos++; if( caretPos >= chatInputText.Length ) caretPos = -1; diff --git a/ClassicalSharp/2D/Widgets/Chat/TextInputWidget.cs b/ClassicalSharp/2D/Widgets/Chat/TextInputWidget.cs index 59cb74a9d..596997248 100644 --- a/ClassicalSharp/2D/Widgets/Chat/TextInputWidget.cs +++ b/ClassicalSharp/2D/Widgets/Chat/TextInputWidget.cs @@ -65,6 +65,7 @@ namespace ClassicalSharp { Size[] sizes = new Size[lines]; int maxWidth = 0; int indexX, indexY; + bool shownWarning; public override void Init() { X = 5; @@ -78,6 +79,15 @@ namespace ClassicalSharp { maxWidth = Math.Max( maxWidth, sizes[i].Width ); } + bool supports = game.Network.ServerSupportsPartialMessages; + if( chatInputText.Length > 64 && !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 ) { + game.Chat.Add( null, MessageType.ClientStatus6 ); + shownWarning = false; + } + DrawString(); altText.texture.Y1 = game.Height - (YOffset + Height + altText.texture.Height); altText.Y = altText.texture.Y1; @@ -91,9 +101,6 @@ namespace ClassicalSharp { if( indexX == 64 ) { caretTex.X1 = 10 + sizes[indexY].Width; - sizes[indexY].Width += caretTex.Width; - - maxWidth = Math.Max( maxWidth, sizes[indexY].Width ); caretCol = FastColour.Yellow; } else { args.Text = parts[indexY].Substring( 0, indexX ); @@ -184,6 +191,7 @@ namespace ClassicalSharp { Height = defaultHeight; originalText = null; altText.SetActive( false ); + game.Chat.Add( null, MessageType.ClientStatus6 ); } void SendInBuffer() { @@ -191,7 +199,7 @@ namespace ClassicalSharp { string allText = chatInputText.GetString(); game.Chat.InputLog.Add( allText ); - if( game.Network.ServerSupportsPatialMessages ) { + if( game.Network.ServerSupportsPartialMessages ) { // don't automatically word wrap the message. while( allText.Length > 64 ) { game.Chat.Send( allText.Substring( 0, 64 ), true ); diff --git a/ClassicalSharp/ClassicalSharp.csproj b/ClassicalSharp/ClassicalSharp.csproj index 0e9d7e2c8..02ea28d94 100644 --- a/ClassicalSharp/ClassicalSharp.csproj +++ b/ClassicalSharp/ClassicalSharp.csproj @@ -4,7 +4,7 @@ {BEB1C785-5CAD-48FF-A886-876BF0A318D4} Debug AnyCPU - WinExe + Exe ClassicalSharp ClassicalSharp v2.0 @@ -55,7 +55,6 @@ False DEBUG;TRACE;USE_DX Project - wwwf null 127.0.0.1 25566 obj\ diff --git a/ClassicalSharp/Events/Events.cs b/ClassicalSharp/Events/Events.cs index c1d2ed3a8..1330145ca 100644 --- a/ClassicalSharp/Events/Events.cs +++ b/ClassicalSharp/Events/Events.cs @@ -26,7 +26,7 @@ namespace ClassicalSharp { /// Raised when the server or a client-side command sends a message. public event EventHandler ChatReceived; - internal void RaiseChatReceived( string text, CpeMessage type ) { + internal void RaiseChatReceived( string text, MessageType type ) { chatArgs.Type = type; chatArgs.Text = text; Raise( ChatReceived, chatArgs ); } /// Raised when the user changes chat font to arial or back to bitmapped font, @@ -54,7 +54,7 @@ namespace ClassicalSharp { public sealed class ChatEventArgs : EventArgs { /// Where this chat message should appear on the screen. - public CpeMessage Type; + public MessageType Type; /// Raw text of the message (including colour codes), /// with code page 437 indices converted to their unicode representations. diff --git a/ClassicalSharp/Game/ChatLog.cs b/ClassicalSharp/Game/ChatLog.cs index fa0292372..8e26ea48d 100644 --- a/ClassicalSharp/Game/ChatLog.cs +++ b/ClassicalSharp/Game/ChatLog.cs @@ -10,6 +10,7 @@ namespace ClassicalSharp { public ChatLine Status1, Status2, Status3, BottomRight1, BottomRight2, BottomRight3, Announcement; + public ChatLine[] ClientStatus = new ChatLine[6]; Game game; public ChatLog( Game game ) { @@ -38,27 +39,29 @@ namespace ClassicalSharp { public void Add( string text ) { Log.Add( text ); LogChatToFile( text ); - game.Events.RaiseChatReceived( text, CpeMessage.Normal ); + game.Events.RaiseChatReceived( text, MessageType.Normal ); } - public void Add( string text, CpeMessage type ) { - if( type == CpeMessage.Normal ) { + public void Add( string text, MessageType type ) { + if( type == MessageType.Normal ) { Log.Add( text ); LogChatToFile( text ); - } else if( type == CpeMessage.Status1 ) { + } else if( type == MessageType.Status1 ) { Status1 = text; - } else if( type == CpeMessage.Status2 ) { + } else if( type == MessageType.Status2 ) { Status2 = text; - } else if( type == CpeMessage.Status3 ) { + } else if( type == MessageType.Status3 ) { Status3 = text; - } else if( type == CpeMessage.BottomRight1 ) { + } else if( type == MessageType.BottomRight1 ) { BottomRight1 = text; - } else if( type == CpeMessage.BottomRight2 ) { + } else if( type == MessageType.BottomRight2 ) { BottomRight2 = text; - } else if( type == CpeMessage.BottomRight3 ) { + } else if( type == MessageType.BottomRight3 ) { BottomRight3 = text; - } else if( type == CpeMessage.Announcement ) { + } else if( type == MessageType.Announcement ) { Announcement = text; + } else if( type >= MessageType.ClientStatus1 && type <= MessageType.ClientStatus6 ) { + ClientStatus[(int)(type - MessageType.ClientStatus1)] = text; } game.Events.RaiseChatReceived( text, type ); } diff --git a/ClassicalSharp/Network/Enums.cs b/ClassicalSharp/Network/Enums.cs index 4f2202730..ccadd8edb 100644 --- a/ClassicalSharp/Network/Enums.cs +++ b/ClassicalSharp/Network/Enums.cs @@ -45,7 +45,7 @@ namespace ClassicalSharp { CpeBulkBlockUpdate = 38, } - public enum CpeMessage { + public enum MessageType { Normal = 0, Status1 = 1, Status2 = 2, @@ -54,6 +54,14 @@ namespace ClassicalSharp { BottomRight2 = 12, BottomRight3 = 13, Announcement = 100, + + // client defined message ids + ClientStatus1 = 256, + ClientStatus2 = 257, + ClientStatus3 = 258, + ClientStatus4 = 259, + ClientStatus5 = 260, + ClientStatus6 = 261, // no LongerMessages warning } public enum CpeBlockFace { diff --git a/ClassicalSharp/Network/INetworkProcessor.cs b/ClassicalSharp/Network/INetworkProcessor.cs index 4ab339b2b..56baa3a12 100644 --- a/ClassicalSharp/Network/INetworkProcessor.cs +++ b/ClassicalSharp/Network/INetworkProcessor.cs @@ -42,7 +42,7 @@ namespace ClassicalSharp { public bool UsingPlayerClick; /// Whether the server can handle partial message packets or not. - public bool ServerSupportsPatialMessages; + public bool ServerSupportsPartialMessages; /// Whether the server supports receiving all code page 437 characters from this client. public bool ServerSupportsFullCP437; diff --git a/ClassicalSharp/Network/NetworkProcessor.CPE.cs b/ClassicalSharp/Network/NetworkProcessor.CPE.cs index 9a8ac3542..8633f33cd 100644 --- a/ClassicalSharp/Network/NetworkProcessor.CPE.cs +++ b/ClassicalSharp/Network/NetworkProcessor.CPE.cs @@ -98,7 +98,7 @@ namespace ClassicalSharp { packetSizes[(int)PacketId.CpeEnvSetMapApperance] += 4; } } else if( extName == "LongerMessages" ) { - ServerSupportsPatialMessages = true; + ServerSupportsPartialMessages = true; } else if( extName == "FullCP437" ) { ServerSupportsFullCP437 = true; } diff --git a/ClassicalSharp/Network/NetworkProcessor.Original.cs b/ClassicalSharp/Network/NetworkProcessor.Original.cs index 25232a9d9..0a8a75b7d 100644 --- a/ClassicalSharp/Network/NetworkProcessor.Original.cs +++ b/ClassicalSharp/Network/NetworkProcessor.Original.cs @@ -14,7 +14,7 @@ namespace ClassicalSharp { public override void SendChat( string text, bool partial ) { if( String.IsNullOrEmpty( text ) ) return; - byte payload = !ServerSupportsPatialMessages ? (byte)0xFF: + byte payload = !ServerSupportsPartialMessages ? (byte)0xFF: partial ? (byte)1 : (byte)0; writer.WriteUInt8( (byte)PacketId.Message ); @@ -249,7 +249,7 @@ namespace ClassicalSharp { byte messageType = reader.ReadUInt8(); string text = reader.ReadChatString( ref messageType, useMessageTypes ); if( !text.StartsWith("^detail.user", StringComparison.OrdinalIgnoreCase ) ) - game.Chat.Add( text, (CpeMessage)messageType ); + game.Chat.Add( text, (MessageType)messageType ); } void HandleKick() { diff --git a/ClassicalSharp/Network/NetworkProcessor.WoM.cs b/ClassicalSharp/Network/NetworkProcessor.WoM.cs index f8daebae8..28c64b035 100644 --- a/ClassicalSharp/Network/NetworkProcessor.WoM.cs +++ b/ClassicalSharp/Network/NetworkProcessor.WoM.cs @@ -45,7 +45,7 @@ namespace ClassicalSharp { if( Int32.TryParse( value, out waterLevel ) ) game.Map.SetEdgeLevel( waterLevel ); } else if( key == "user.detail" && !useMessageTypes ) { - game.Chat.Add( value, CpeMessage.Status2 ); + game.Chat.Add( value, MessageType.Status2 ); } } } diff --git a/ClassicalSharp/Network/Utils/NetReader.cs b/ClassicalSharp/Network/Utils/NetReader.cs index c4c3d080d..374235e35 100644 --- a/ClassicalSharp/Network/Utils/NetReader.cs +++ b/ClassicalSharp/Network/Utils/NetReader.cs @@ -74,7 +74,7 @@ namespace ClassicalSharp { if( useMessageTypes ) return ReadCp437String(); - messageType = (byte)CpeMessage.Normal; + messageType = (byte)MessageType.Normal; int length = GetString( buffer, false ); Remove( 64 ); @@ -82,7 +82,7 @@ namespace ClassicalSharp { if( length >= womDetail.Length && IsWomDetailString() ) { length -= womDetail.Length; offset = womDetail.Length; - messageType = (byte)CpeMessage.Status3; + messageType = (byte)MessageType.Status3; } return new String( characters, offset, length ); } diff --git a/ClassicalSharp/Singleplayer/Server.cs b/ClassicalSharp/Singleplayer/Server.cs index f05eac4fe..970c16150 100644 --- a/ClassicalSharp/Singleplayer/Server.cs +++ b/ClassicalSharp/Singleplayer/Server.cs @@ -39,7 +39,7 @@ namespace ClassicalSharp.Singleplayer { public override void SendChat( string text, bool partial ) { if( !String.IsNullOrEmpty( text ) ) { text = text.TrimEnd(); - game.Chat.Add( text, CpeMessage.Normal ); + game.Chat.Add( text, MessageType.Normal ); } } @@ -94,7 +94,7 @@ namespace ClassicalSharp.Singleplayer { } generator = null; - game.Chat.Add( "&ePlaying single player", CpeMessage.Status1 ); + game.Chat.Add( "&ePlaying single player", MessageType.Status1 ); GC.Collect(); }