From 5218124c6c500151c3838a7820279cf16dc09314 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Thu, 5 Nov 2015 18:43:16 +1100 Subject: [PATCH] Separate writing methods, allow entering CP437 directly into chat via clipboard if server supports FullCP437. --- .../2D/Widgets/Chat/TextInputWidget.cs | 14 +- ClassicalSharp/ClassicalSharp.csproj | 3 +- ClassicalSharp/Model/TestModel.cs | 84 ++++++++++++ ClassicalSharp/Network/INetworkProcessor.cs | 1 + .../Network/NetworkProcessor.CPE.cs | 48 +++---- ClassicalSharp/Network/NetworkProcessor.cs | 123 ++++++------------ .../Utils/{FastNetReader.cs => NetReader.cs} | 12 +- ClassicalSharp/Network/Utils/NetWriter.cs | 60 +++++++++ ClassicalSharp/Singleplayer/Server.cs | 1 + 9 files changed, 228 insertions(+), 118 deletions(-) create mode 100644 ClassicalSharp/Model/TestModel.cs rename ClassicalSharp/Network/Utils/{FastNetReader.cs => NetReader.cs} (95%) create mode 100644 ClassicalSharp/Network/Utils/NetWriter.cs diff --git a/ClassicalSharp/2D/Widgets/Chat/TextInputWidget.cs b/ClassicalSharp/2D/Widgets/Chat/TextInputWidget.cs index 043c3dba3..c88e11e26 100644 --- a/ClassicalSharp/2D/Widgets/Chat/TextInputWidget.cs +++ b/ClassicalSharp/2D/Widgets/Chat/TextInputWidget.cs @@ -140,14 +140,16 @@ namespace ClassicalSharp { chatInputTexture.Y1 += deltaY; } - static bool IsInvalidChar( char c ) { + bool IsValidChar( char c ) { + if( c == '&' ) return false; + if( c >= ' ' && c <= '~' ) return true; // ascii + bool isCP437 = Utils.ControlCharReplacements.IndexOf( c ) >= 0 || Utils.ExtendedCharReplacements.IndexOf( c ) >= 0; - // Make sure we're in the printable text range from 0x20 to 0x7E - return c < ' ' || c == '&' || c > '~'; + bool supportsCP437 = game.Network.ServerSupportsFullCP437; + return supportsCP437 && isCP437; } - static char[] trimChars = { ' ' }; public void SendTextInBufferAndReset() { SendInBuffer(); typingLogPos = game.Chat.InputLog.Count; // Index of newest entry + 1. @@ -209,7 +211,7 @@ namespace ClassicalSharp { #region Input handling public override bool HandlesKeyPress( char key ) { - if( chatInputText.Length < len && !IsInvalidChar( key ) ) { + if( chatInputText.Length < len && IsValidChar( key ) ) { if( caretPos == -1 ) { chatInputText.Append( chatInputText.Length, key ); } else { @@ -326,7 +328,7 @@ namespace ClassicalSharp { if( String.IsNullOrEmpty( text ) ) return true; for( int i = 0; i < text.Length; i++ ) { - if( IsInvalidChar( text[i] ) ) { + if( !IsValidChar( text[i] ) ) { game.Chat.Add( "&eClipboard contained characters that can't be sent." ); return true; } diff --git a/ClassicalSharp/ClassicalSharp.csproj b/ClassicalSharp/ClassicalSharp.csproj index be59f4a8d..ad4403835 100644 --- a/ClassicalSharp/ClassicalSharp.csproj +++ b/ClassicalSharp/ClassicalSharp.csproj @@ -176,12 +176,13 @@ - + + diff --git a/ClassicalSharp/Model/TestModel.cs b/ClassicalSharp/Model/TestModel.cs new file mode 100644 index 000000000..a15177dfa --- /dev/null +++ b/ClassicalSharp/Model/TestModel.cs @@ -0,0 +1,84 @@ +using System; +using System.Drawing; +using ClassicalSharp.GraphicsAPI; +using OpenTK; + +namespace ClassicalSharp.Model { + + public class TestModel : IModel { + + ModelSet Set, SetSlim; + public TestModel( Game window ) : base( window ) { + vertices = new ModelVertex[boxVertices * ( 7 + 2 )]; + Set = new ModelSet(); + + Set.Head = BuildBox( MakeBoxBounds( -0, 0, -0, 8, 8, 8 ) + .SetTexOrigin( 0, 0 ) ); + Set.Torso = BuildBox( MakeBoxBounds( -4, 12, -2, 4, 24, 2 ) + .SetTexOrigin( 16, 16 ) ); + Set.LeftLeg = BuildBox( MakeBoxBounds( 0, 0, -2, -4, 12, 2 ) + .SetTexOrigin( 0, 16 ) ); + Set.RightLeg = BuildBox( MakeBoxBounds( 0, 0, -2, 4, 12, 2 ). + SetTexOrigin( 0, 16 ) ); + Set.Hat = BuildBox( MakeBoxBounds( -4, 24, -4, 4, 32, 4 ) + .SetTexOrigin( 32, 0 ) + .SetModelBounds( -4.5f, 23.5f, -4.5f, 4.5f, 32.5f, 4.5f ) ); + Set.LeftArm = BuildBox( MakeBoxBounds( -4, 12, -2, -8, 24, 2 ) + .SetTexOrigin( 40, 16 ) ); + Set.RightArm = BuildBox( MakeBoxBounds( 4, 12, -2, 8, 24, 2 ) + .SetTexOrigin( 40, 16 ) ); + + SetSlim = new ModelSet(); + SetSlim.Head = Set.Head; + SetSlim.Torso = Set.Torso; + SetSlim.LeftLeg = Set.LeftLeg; + SetSlim.RightLeg = Set.RightLeg; + SetSlim.LeftArm = BuildBox( MakeBoxBounds( -7, 12, -2, -4, 24, 2 ) + .SetTexOrigin( 32, 48 ) ); + SetSlim.RightArm = BuildBox( MakeBoxBounds( 4, 12, -2, 7, 24, 2 ) + .SetTexOrigin( 40, 16 ) ); + SetSlim.Hat = Set.Hat; + } + + public override float NameYOffset { + get { return 2.1375f; } + } + + public override float GetEyeY( Player player ) { + return 27/16f; + } + + public override Vector3 CollisionSize { + get { return new Vector3( 8/16f, 28.5f/16f, 8/16f ); } + } + + public override BoundingBox PickingBounds { + get { return new BoundingBox( -8/16f, 0, -4/16f, 8/16f, 32/16f, 4/16f ); } + } + + protected override void DrawPlayerModel( Player p ) { + graphics.Texturing = true; + int texId = p.MobTextureId <= 0 ? cache.TestTexId : p.MobTextureId; + graphics.BindTexture( texId ); + + SkinType skinType = p.SkinType; + _64x64 = skinType != SkinType.Type64x32; + ModelSet model = skinType == SkinType.Type64x64Slim ? SetSlim : Set; + + DrawRotate( 0, 24/16f, 0, -p.PitchRadians, 0, 0, model.Head ); + DrawPart( model.Torso ); + DrawRotate( 0, 12/16f, 0, p.leftLegXRot, 0, 0, model.LeftLeg ); + DrawRotate( 0, 12/16f, 0, p.rightLegXRot, 0, 0, model.RightLeg ); + DrawRotate( -6/16f, 22/16f, 0, p.leftArmXRot, 0, p.leftArmZRot, model.LeftArm ); + DrawRotate( 6/16f, 22/16f, 0, p.rightArmXRot, 0, p.rightArmZRot, model.RightArm ); + + graphics.AlphaTest = true; + if( p.RenderHat ) + DrawRotate( 0, 24f/16f, 0, -p.PitchRadians, 0, 0, model.Hat ); + } + + class ModelSet { + public ModelPart Head, Torso, LeftLeg, RightLeg, LeftArm, RightArm, Hat; + } + } +} \ No newline at end of file diff --git a/ClassicalSharp/Network/INetworkProcessor.cs b/ClassicalSharp/Network/INetworkProcessor.cs index 813925f5d..e6f449b6e 100644 --- a/ClassicalSharp/Network/INetworkProcessor.cs +++ b/ClassicalSharp/Network/INetworkProcessor.cs @@ -28,5 +28,6 @@ namespace ClassicalSharp { public bool Disconnected; public bool UsingExtPlayerList, UsingPlayerClick; public bool ServerSupportsPatialMessages; + public bool ServerSupportsFullCP437; } } \ No newline at end of file diff --git a/ClassicalSharp/Network/NetworkProcessor.CPE.cs b/ClassicalSharp/Network/NetworkProcessor.CPE.cs index b5563335a..1b76b5f65 100644 --- a/ClassicalSharp/Network/NetworkProcessor.CPE.cs +++ b/ClassicalSharp/Network/NetworkProcessor.CPE.cs @@ -16,35 +16,35 @@ namespace ClassicalSharp { SendPacket(); } - private static void MakeExtInfo( string appName, int extensionsCount ) { - WriteUInt8( (byte)PacketId.CpeExtInfo ); - WriteString( appName ); - WriteInt16( (short)extensionsCount ); + void MakeExtInfo( string appName, int extensionsCount ) { + writer.WriteUInt8( (byte)PacketId.CpeExtInfo ); + writer.WriteString( appName ); + writer.WriteInt16( (short)extensionsCount ); } - private static void MakeExtEntry( string extensionName, int extensionVersion ) { - WriteUInt8( (byte)PacketId.CpeExtEntry ); - WriteString( extensionName ); - WriteInt32( extensionVersion ); + void MakeExtEntry( string extensionName, int extensionVersion ) { + writer.WriteUInt8( (byte)PacketId.CpeExtEntry ); + writer.WriteString( extensionName ); + writer.WriteInt32( extensionVersion ); } - private static void MakeCustomBlockSupportLevel( byte version ) { - WriteUInt8( (byte)PacketId.CpeCustomBlockSupportLevel ); - WriteUInt8( version ); + void MakeCustomBlockSupportLevel( byte version ) { + writer.WriteUInt8( (byte)PacketId.CpeCustomBlockSupportLevel ); + writer.WriteUInt8( version ); } - private static void MakePlayerClick( byte button, bool buttonDown, float yaw, float pitch, byte targetEntity, - Vector3I targetPos, CpeBlockFace targetFace ) { - WriteUInt8( (byte)PacketId.CpePlayerClick ); - WriteUInt8( button ); - WriteUInt8( buttonDown ? (byte)0 : (byte)1 ); - WriteInt16( (short)Utils.DegreesToPacked( yaw, 65536 ) ); - WriteInt16( (short)Utils.DegreesToPacked( pitch, 65536 ) ); - WriteUInt8( targetEntity ); - WriteInt16( (short)targetPos.X ); - WriteInt16( (short)targetPos.Y ); - WriteInt16( (short)targetPos.Z ); - WriteUInt8( (byte)targetFace ); + void MakePlayerClick( byte button, bool buttonDown, float yaw, float pitch, byte targetEntity, + Vector3I targetPos, CpeBlockFace targetFace ) { + writer.WriteUInt8( (byte)PacketId.CpePlayerClick ); + writer.WriteUInt8( button ); + writer.WriteUInt8( buttonDown ? (byte)0 : (byte)1 ); + writer.WriteInt16( (short)Utils.DegreesToPacked( yaw, 65536 ) ); + writer.WriteInt16( (short)Utils.DegreesToPacked( pitch, 65536 ) ); + writer.WriteUInt8( targetEntity ); + writer.WriteInt16( (short)targetPos.X ); + writer.WriteInt16( (short)targetPos.Y ); + writer.WriteInt16( (short)targetPos.Z ); + writer.WriteUInt8( (byte)targetFace ); } #endregion @@ -88,6 +88,8 @@ namespace ClassicalSharp { packetSizes[(int)PacketId.CpeEnvSetMapApperance] += 4; } else if( extName == "LongerMessages" ) { ServerSupportsPatialMessages = true; + } else if( extName == "FullCP437" ) { + ServerSupportsFullCP437 = true; } cpeServerExtensionsCount--; diff --git a/ClassicalSharp/Network/NetworkProcessor.cs b/ClassicalSharp/Network/NetworkProcessor.cs index 80bc1d2a6..a93a5cc07 100644 --- a/ClassicalSharp/Network/NetworkProcessor.cs +++ b/ClassicalSharp/Network/NetworkProcessor.cs @@ -26,7 +26,6 @@ namespace ClassicalSharp { } Socket socket; - NetworkStream stream; Game game; bool receivedFirstPosition; @@ -42,32 +41,14 @@ namespace ClassicalSharp { return; } - stream = new NetworkStream( socket, true ); - reader = new FastNetReader( stream ); + NetworkStream stream = new NetworkStream( socket, true ); + reader = new NetReader( stream ); + writer = new NetWriter( stream ); gzippedMap = new FixedBufferStream( reader.buffer ); MakeLoginPacket( game.Username, game.Mppass ); SendPacket(); } - public override void SendChat( string text, bool partial ) { - if( String.IsNullOrEmpty( text ) ) return; - - byte payload = !ServerSupportsPatialMessages ? (byte)0xFF: - partial ? (byte)1 : (byte)0; - MakeMessagePacket( text, payload ); - SendPacket(); - } - - public override void SendPosition( Vector3 pos, float yaw, float pitch ) { - byte payload = sendHeldBlock ? (byte)game.Inventory.HeldBlock : (byte)0xFF; - MakePositionPacket( pos, yaw, pitch, payload ); - SendPacket(); - } - - public override void SendSetBlock( int x, int y, int z, bool place, byte block ) { - MakeSetBlockPacket( (short)x, (short)y, (short)z, place, block ); - SendPacket(); - } public override void Dispose() { socket.Close(); @@ -133,79 +114,57 @@ namespace ClassicalSharp { 8, 86, 2, 4, 66, 69, 2, 8, 138, 0, 80, 2, }; - #region Writing + NetWriter writer; - static byte[] outBuffer = new byte[131]; - static int outIndex; - private static void MakeLoginPacket( string username, string verKey ) { - WriteUInt8( (byte)PacketId.Handshake ); - WriteUInt8( 7 ); // protocol version - WriteString( username ); - WriteString( verKey ); - WriteUInt8( 0x42 ); + public override void SendChat( string text, bool partial ) { + if( String.IsNullOrEmpty( text ) ) return; + byte payload = !ServerSupportsPatialMessages ? (byte)0xFF: + partial ? (byte)1 : (byte)0; + + writer.WriteUInt8( (byte)PacketId.Message ); + writer.WriteUInt8( payload ); + writer.WriteString( text ); + SendPacket(); } - private static void MakeSetBlockPacket( short x, short y, short z, bool place, byte block ) { - WriteUInt8( (byte)PacketId.SetBlockClient ); - WriteInt16( x ); - WriteInt16( y ); - WriteInt16( z ); - WriteUInt8( place ? (byte)1 : (byte)0 ); - WriteUInt8( block ); + public override void SendPosition( Vector3 pos, float yaw, float pitch ) { + byte payload = sendHeldBlock ? (byte)game.Inventory.HeldBlock : (byte)0xFF; + MakePositionPacket( pos, yaw, pitch, payload ); + SendPacket(); } - private static void MakePositionPacket( Vector3 pos, float yaw, float pitch, byte payload ) { - WriteUInt8( (byte)PacketId.EntityTeleport ); - WriteUInt8( payload ); // held block when using HeldBlock, otherwise just 255 - WriteInt16( (short)( pos.X * 32 ) ); - WriteInt16( (short)( (int)( pos.Y * 32 ) + 51 ) ); - WriteInt16( (short)( pos.Z * 32 ) ); - WriteUInt8( (byte)Utils.DegreesToPacked( yaw, 256 ) ); - WriteUInt8( (byte)Utils.DegreesToPacked( pitch, 256 ) ); + public override void SendSetBlock( int x, int y, int z, bool place, byte block ) { + writer.WriteUInt8( (byte)PacketId.SetBlockClient ); + writer.WriteInt16( (short)x ); + writer.WriteInt16( (short)y ); + writer.WriteInt16( (short)z ); + writer.WriteUInt8( place ? (byte)1 : (byte)0 ); + writer.WriteUInt8( block ); + SendPacket(); } - private static void MakeMessagePacket( string text, byte payload ) { - WriteUInt8( (byte)PacketId.Message ); - WriteUInt8( payload ); - WriteString( text ); + void MakeLoginPacket( string username, string verKey ) { + writer.WriteUInt8( (byte)PacketId.Handshake ); + writer.WriteUInt8( 7 ); // protocol version + writer.WriteString( username ); + writer.WriteString( verKey ); + writer.WriteUInt8( 0x42 ); } - static void WriteString( string value ) { - int count = Math.Min( value.Length, 64 ); - for( int i = 0; i < count; i++ ) { - char c = value[i]; - outBuffer[outIndex + i] = (byte)( c >= '\u0080' ? '?' : c ); - } - for( int i = value.Length; i < 64; i++ ) { - outBuffer[outIndex + i] = (byte)' '; - } - outIndex += 64; - } - - static void WriteUInt8( byte value ) { - outBuffer[outIndex++] = value; - } - - static void WriteInt16( short value ) { - outBuffer[outIndex++] = (byte)( value >> 8 ); - outBuffer[outIndex++] = (byte)( value ); - } - - static void WriteInt32( int value ) { - outBuffer[outIndex++] = (byte)( value >> 24 ); - outBuffer[outIndex++] = (byte)( value >> 16 ); - outBuffer[outIndex++] = (byte)( value >> 8 ); - outBuffer[outIndex++] = (byte)( value ); + void MakePositionPacket( Vector3 pos, float yaw, float pitch, byte payload ) { + writer.WriteUInt8( (byte)PacketId.EntityTeleport ); + writer.WriteUInt8( payload ); // held block when using HeldBlock, otherwise just 255 + writer.WriteInt16( (short)(pos.X * 32) ); + writer.WriteInt16( (short)((int)(pos.Y * 32) + 51) ); + writer.WriteInt16( (short)(pos.Z * 32) ); + writer.WriteUInt8( (byte)Utils.DegreesToPacked( yaw, 256 ) ); + writer.WriteUInt8( (byte)Utils.DegreesToPacked( pitch, 256 ) ); } void SendPacket() { - int packetLength = outIndex; - outIndex = 0; - if( Disconnected ) return; - try { - stream.Write( outBuffer, 0, packetLength ); + writer.Send( Disconnected ); } catch( IOException ex ) { ErrorHandler.LogError( "wrting packets", ex ); game.Disconnect( "&eLost connection to the server", "I/O Error while writing packets" ); @@ -218,7 +177,7 @@ namespace ClassicalSharp { #region Reading - FastNetReader reader; + NetReader reader; DateTime receiveStart; DeflateStream gzipStream; GZipHeaderReader gzipHeader; diff --git a/ClassicalSharp/Network/Utils/FastNetReader.cs b/ClassicalSharp/Network/Utils/NetReader.cs similarity index 95% rename from ClassicalSharp/Network/Utils/FastNetReader.cs rename to ClassicalSharp/Network/Utils/NetReader.cs index fa8ea2e8b..a28c61b42 100644 --- a/ClassicalSharp/Network/Utils/FastNetReader.cs +++ b/ClassicalSharp/Network/Utils/NetReader.cs @@ -1,15 +1,15 @@ -using System; -using System.Net.Sockets; +using System; +using System.Net.Sockets; namespace ClassicalSharp { - - // Basically a much faster version of List( capacity ) - internal class FastNetReader { + + internal class NetReader { + public byte[] buffer = new byte[4096 * 4]; public int size = 0; public NetworkStream Stream; - public FastNetReader( NetworkStream stream ) { + public NetReader( NetworkStream stream ) { Stream = stream; } diff --git a/ClassicalSharp/Network/Utils/NetWriter.cs b/ClassicalSharp/Network/Utils/NetWriter.cs new file mode 100644 index 000000000..d0151a5ea --- /dev/null +++ b/ClassicalSharp/Network/Utils/NetWriter.cs @@ -0,0 +1,60 @@ +using System; +using System.Net.Sockets; + +namespace ClassicalSharp { + + internal class NetWriter { + + public byte[] buffer = new byte[131]; + public int index = 0; + public NetworkStream Stream; + + public NetWriter( NetworkStream stream ) { + Stream = stream; + } + + public void WriteString( string value ) { + int count = Math.Min( value.Length, 64 ); + for( int i = 0; i < count; i++ ) { + char c = value[i]; + int cpIndex = 0; + if( c >= ' ' && c <= '~' ) { + buffer[index + i] = (byte)c; + } else if( (cpIndex = Utils.ControlCharReplacements.IndexOf( c ) ) >= 0 ) { + buffer[index + i] = (byte)cpIndex; + } else if( (cpIndex = Utils.ExtendedCharReplacements.IndexOf( c ) ) >= 0 ) { + buffer[index + i] = (byte)(cpIndex + 127); + } else { + buffer[index + i] = (byte)'?'; + } + } + for( int i = value.Length; i < 64; i++ ) { + buffer[index + i] = (byte)' '; + } + index += 64; + } + + public void WriteUInt8( byte value ) { + buffer[index++] = value; + } + + public void WriteInt16( short value ) { + buffer[index++] = (byte)(value >> 8); + buffer[index++] = (byte)(value ); + } + + public void WriteInt32( int value ) { + buffer[index++] = (byte)(value >> 24); + buffer[index++] = (byte)(value >> 16); + buffer[index++] = (byte)(value >> 8); + buffer[index++] = (byte)(value); + } + + public void Send( bool disconnected ) { + int packetLength = index; + index = 0; + if( !disconnected ) + Stream.Write( buffer, 0, packetLength ); + } + } +} \ No newline at end of file diff --git a/ClassicalSharp/Singleplayer/Server.cs b/ClassicalSharp/Singleplayer/Server.cs index 06b42aa8d..cb19f5201 100644 --- a/ClassicalSharp/Singleplayer/Server.cs +++ b/ClassicalSharp/Singleplayer/Server.cs @@ -12,6 +12,7 @@ namespace ClassicalSharp.Singleplayer { public SinglePlayerServer( Game window ) { game = window; physics = new Physics( game ); + ServerSupportsFullCP437 = true; } public override bool IsSinglePlayer {