From 52d471b4fdb7dc2246aac627dc9923418a453ce4 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Fri, 25 Mar 2016 22:58:51 +1100 Subject: [PATCH 1/3] More work on custom models. --- ClassicalSharp/ClassicalSharp.csproj | 1 + ClassicalSharp/Model/CustomModel.cs | 16 +- ClassicalSharp/Model/ModelCache.cs | 1 + .../Network/NetworkProcessor.CPE.cs | 153 +--------------- .../Network/NetworkProcessor.CPECustom.cs | 172 ++++++++++++++++++ ClassicalSharp/Network/Utils/NetReader.cs | 15 +- 6 files changed, 194 insertions(+), 164 deletions(-) create mode 100644 ClassicalSharp/Network/NetworkProcessor.CPECustom.cs diff --git a/ClassicalSharp/ClassicalSharp.csproj b/ClassicalSharp/ClassicalSharp.csproj index adbbdae1f..ae60df91a 100644 --- a/ClassicalSharp/ClassicalSharp.csproj +++ b/ClassicalSharp/ClassicalSharp.csproj @@ -171,6 +171,7 @@ + diff --git a/ClassicalSharp/Model/CustomModel.cs b/ClassicalSharp/Model/CustomModel.cs index 0ad23c120..04cc97180 100644 --- a/ClassicalSharp/Model/CustomModel.cs +++ b/ClassicalSharp/Model/CustomModel.cs @@ -29,10 +29,14 @@ namespace ClassicalSharp.Model { int texId = p.PlayerTextureId <= 0 ? cache.HumanoidTexId : p.PlayerTextureId; } + internal void ReadSetupPacket( NetReader reader ) { + + } + internal void ReadMetadataPacket( NetReader reader ) { - collisonSize = ReadVector( reader ); - pickingBounds.Min = ReadVector( reader ); - pickingBounds.Max = ReadVector( reader ); + collisonSize = ReadS16Vec3( reader ); + pickingBounds.Min = ReadS16Vec3( reader ); + pickingBounds.Max = ReadS16Vec3( reader ); nameYOffset = reader.ReadInt16() / 256f; eyeY = reader.ReadInt16() / 256f; bobbing = reader.ReadUInt8() != 0; @@ -41,8 +45,8 @@ namespace ClassicalSharp.Model { internal void ReadDefinePartPacket( NetReader reader ) { ushort partId = reader.ReadUInt16(); byte type = reader.ReadUInt8(); - Vector3 min = ReadVector( reader ); - Vector3 max = ReadVector( reader ); + Vector3 min = ReadS16Vec3( reader ); + Vector3 max = ReadS16Vec3( reader ); } internal void ReadRotationPacket( NetReader reader ) { @@ -54,7 +58,7 @@ namespace ClassicalSharp.Model { } CustomModelPart[] parts; - Vector3 ReadVector( NetReader reader ) { + Vector3 ReadS16Vec3( NetReader reader ) { return new Vector3( reader.ReadInt16() / 256f, reader.ReadInt16() / 256f, reader.ReadInt16() / 256f ); } diff --git a/ClassicalSharp/Model/ModelCache.cs b/ClassicalSharp/Model/ModelCache.cs index 89d24623f..2a7e6e371 100644 --- a/ClassicalSharp/Model/ModelCache.cs +++ b/ClassicalSharp/Model/ModelCache.cs @@ -13,6 +13,7 @@ namespace ClassicalSharp.Model { this.game = window; api = game.Graphics; } + public CustomModel[] CustomModels = new CustomModel[256]; public void InitCache() { vertices = new VertexPos3fTex2fCol4b[24 * 12]; diff --git a/ClassicalSharp/Network/NetworkProcessor.CPE.cs b/ClassicalSharp/Network/NetworkProcessor.CPE.cs index 8af52303d..5c9a589ef 100644 --- a/ClassicalSharp/Network/NetworkProcessor.CPE.cs +++ b/ClassicalSharp/Network/NetworkProcessor.CPE.cs @@ -360,108 +360,6 @@ namespace ClassicalSharp { AddEntity( entityId, displayName, skinName, true ); } - void HandleCpeDefineBlock() { - if( !game.AllowCustomBlocks ) { - SkipPacketData( PacketId.CpeDefineBlock ); return; - } - byte id = HandleCpeDefineBlockCommonStart( false ); - BlockInfo info = game.BlockInfo; - byte shape = reader.ReadUInt8(); - if( shape == 0 ) { - info.IsSprite[id] = true; - info.IsOpaque[id] = false; - info.IsTransparent[id] = true; - } else if( shape <= 16 ) { - info.MaxBB[id].Y = shape / 16f; - } - - HandleCpeDefineBlockCommonEnd( id ); - // Update sprite BoundingBox if necessary - if( info.IsSprite[id] ) { - using( FastBitmap dst = new FastBitmap( game.TerrainAtlas.AtlasBitmap, true, true ) ) - info.RecalculateBB( id, dst ); - } - info.DefinedCustomBlocks[id >> 5] |= (1u << (id & 0x1F)); - } - - void HandleCpeRemoveBlockDefinition() { - if( !game.AllowCustomBlocks ) { - SkipPacketData( PacketId.CpeRemoveBlockDefinition ); return; - } - game.BlockInfo.ResetBlockInfo( reader.ReadUInt8(), true ); - game.BlockInfo.InitLightOffsets(); - game.Events.RaiseBlockDefinitionChanged(); - } - - void HandleCpeDefineBlockExt() { - if( !game.AllowCustomBlocks ) { - SkipPacketData( PacketId.CpeDefineBlockExt ); return; - } - byte id = HandleCpeDefineBlockCommonStart( blockDefinitionsExtVer >= 2 ); - BlockInfo info = game.BlockInfo; - Vector3 min, max; - - min.X = reader.ReadUInt8() / 16f; Utils.Clamp( ref min.X, 0, 15/16f ); - min.Y = reader.ReadUInt8() / 16f; Utils.Clamp( ref min.Y, 0, 15/16f ); - min.Z = reader.ReadUInt8() / 16f; Utils.Clamp( ref min.Z, 0, 15/16f ); - max.X = reader.ReadUInt8() / 16f; Utils.Clamp( ref max.X, 1/16f, 1 ); - max.Y = reader.ReadUInt8() / 16f; Utils.Clamp( ref max.Y, 1/16f, 1 ); - max.Z = reader.ReadUInt8() / 16f; Utils.Clamp( ref max.Z, 1/16f, 1 ); - - info.MinBB[id] = min; - info.MaxBB[id] = max; - HandleCpeDefineBlockCommonEnd( id ); - info.DefinedCustomBlocks[id >> 5] |= (1u << (id & 0x1F)); - } - - byte HandleCpeDefineBlockCommonStart( bool uniqueSideTexs ) { - byte block = reader.ReadUInt8(); - BlockInfo info = game.BlockInfo; - info.ResetBlockInfo( block, false ); - - info.Name[block] = reader.ReadAsciiString(); - info.CollideType[block] = (BlockCollideType)reader.ReadUInt8(); - if( info.CollideType[block] != BlockCollideType.Solid ) { - info.IsTransparent[block] = true; - info.IsOpaque[block] = false; - } - - info.SpeedMultiplier[block] = (float)Math.Pow( 2, (reader.ReadUInt8() - 128) / 64f ); - info.SetTex( reader.ReadUInt8(), TileSide.Top, (Block)block ); - if( uniqueSideTexs ) { - info.SetTex( reader.ReadUInt8(), TileSide.Left, (Block)block ); - info.SetTex( reader.ReadUInt8(), TileSide.Right, (Block)block ); - info.SetTex( reader.ReadUInt8(), TileSide.Front, (Block)block ); - info.SetTex( reader.ReadUInt8(), TileSide.Back, (Block)block ); - } else { - info.SetSide( reader.ReadUInt8(), (Block)block ); - } - info.SetTex( reader.ReadUInt8(), TileSide.Bottom, (Block)block ); - - info.BlocksLight[block] = reader.ReadUInt8() == 0; - byte sound = reader.ReadUInt8(); - if( sound < breakSnds.Length ) { - info.StepSounds[block] = stepSnds[sound]; - info.DigSounds[block] = breakSnds[sound]; - } - info.FullBright[block] = reader.ReadUInt8() != 0; - return block; - } - - void HandleCpeDefineBlockCommonEnd( byte block ) { - BlockInfo info = game.BlockInfo; - byte blockDraw = reader.ReadUInt8(); - SetBlockDraw( info, block, blockDraw ); - - byte fogDensity = reader.ReadUInt8(); - info.FogDensity[block] = fogDensity == 0 ? 0 : (fogDensity + 1) / 128f; - info.FogColour[block] = new FastColour( - reader.ReadUInt8(), reader.ReadUInt8(), reader.ReadUInt8() ); - info.SetupCullingCache( block ); - info.InitLightOffsets(); - game.Events.RaiseBlockDefinitionChanged(); - } - const int bulkCount = 256; unsafe void HandleBulkBlockUpdate() { int count = reader.ReadUInt8() + 1; @@ -500,59 +398,10 @@ namespace ClassicalSharp { 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. + if( code == '%' || code == '&' ) return; // colour code signifiers cannot be used game.Drawer2D.Colours[code] = col; game.Events.RaiseColourCodesChanged(); } - - void HandleDefineModel() { - int start = reader.index - 1; - byte modelId = reader.ReadUInt8(); - switch( reader.ReadUInt8() ) { - case 0: // setup - break; - case 1: // metadata - break; - case 2: // define part - break; - case 3: // rotation - break; - } - int read = reader.index - start; - // TODO: skip remaining data - } - - internal static SoundType[] stepSnds, breakSnds; - static NetworkProcessor() { - stepSnds = new SoundType[10]; - breakSnds = new SoundType[10]; - stepSnds[0] = SoundType.None; breakSnds[0] = SoundType.None; - stepSnds[1] = SoundType.Wood; breakSnds[1] = SoundType.Wood; - stepSnds[2] = SoundType.Gravel; breakSnds[2] = SoundType.Gravel; - stepSnds[3] = SoundType.Grass; breakSnds[3] = SoundType.Grass; - stepSnds[4] = SoundType.Stone; breakSnds[4] = SoundType.Stone; - // TODO: metal sound type, just use stone for now. - stepSnds[5] = SoundType.Stone; breakSnds[5] = SoundType.Stone; - stepSnds[6] = SoundType.Stone; breakSnds[6] = SoundType.Glass; - stepSnds[7] = SoundType.Cloth; breakSnds[7] = SoundType.Cloth; - stepSnds[8] = SoundType.Sand; breakSnds[8] = SoundType.Sand; - stepSnds[9] = SoundType.Snow; breakSnds[9] = SoundType.Snow; - } - - internal static void SetBlockDraw( BlockInfo info, byte block, byte blockDraw ) { - if( blockDraw == 1 ) { - info.IsTransparent[block] = true; - } else if( blockDraw == 2 ) { - info.IsTransparent[block] = true; - info.CullWithNeighbours[block] = false; - } else if( blockDraw == 3 ) { - info.IsTranslucent[block] = true; - } else if( blockDraw == 4 ) { - info.IsTransparent[block] = true; - info.IsAir[block] = true; - } - if( info.IsOpaque[block] ) - info.IsOpaque[block] = blockDraw == 0; - } } #endregion } \ No newline at end of file diff --git a/ClassicalSharp/Network/NetworkProcessor.CPECustom.cs b/ClassicalSharp/Network/NetworkProcessor.CPECustom.cs new file mode 100644 index 000000000..1d753e561 --- /dev/null +++ b/ClassicalSharp/Network/NetworkProcessor.CPECustom.cs @@ -0,0 +1,172 @@ +using System; +using ClassicalSharp.Model; +using OpenTK; + +namespace ClassicalSharp { + + public partial class NetworkProcessor : INetworkProcessor { + + void HandleCpeDefineBlock() { + if( !game.AllowCustomBlocks ) { + SkipPacketData( PacketId.CpeDefineBlock ); return; + } + byte id = HandleCpeDefineBlockCommonStart( false ); + BlockInfo info = game.BlockInfo; + byte shape = reader.ReadUInt8(); + if( shape == 0 ) { + info.IsSprite[id] = true; + info.IsOpaque[id] = false; + info.IsTransparent[id] = true; + } else if( shape <= 16 ) { + info.MaxBB[id].Y = shape / 16f; + } + + HandleCpeDefineBlockCommonEnd( id ); + // Update sprite BoundingBox if necessary + if( info.IsSprite[id] ) { + using( FastBitmap dst = new FastBitmap( game.TerrainAtlas.AtlasBitmap, true, true ) ) + info.RecalculateBB( id, dst ); + } + info.DefinedCustomBlocks[id >> 5] |= (1u << (id & 0x1F)); + } + + void HandleCpeRemoveBlockDefinition() { + if( !game.AllowCustomBlocks ) { + SkipPacketData( PacketId.CpeRemoveBlockDefinition ); return; + } + game.BlockInfo.ResetBlockInfo( reader.ReadUInt8(), true ); + game.BlockInfo.InitLightOffsets(); + game.Events.RaiseBlockDefinitionChanged(); + } + + void HandleCpeDefineBlockExt() { + if( !game.AllowCustomBlocks ) { + SkipPacketData( PacketId.CpeDefineBlockExt ); return; + } + byte id = HandleCpeDefineBlockCommonStart( blockDefinitionsExtVer >= 2 ); + BlockInfo info = game.BlockInfo; + Vector3 min, max; + + min.X = reader.ReadUInt8() / 16f; Utils.Clamp( ref min.X, 0, 15/16f ); + min.Y = reader.ReadUInt8() / 16f; Utils.Clamp( ref min.Y, 0, 15/16f ); + min.Z = reader.ReadUInt8() / 16f; Utils.Clamp( ref min.Z, 0, 15/16f ); + max.X = reader.ReadUInt8() / 16f; Utils.Clamp( ref max.X, 1/16f, 1 ); + max.Y = reader.ReadUInt8() / 16f; Utils.Clamp( ref max.Y, 1/16f, 1 ); + max.Z = reader.ReadUInt8() / 16f; Utils.Clamp( ref max.Z, 1/16f, 1 ); + + info.MinBB[id] = min; + info.MaxBB[id] = max; + HandleCpeDefineBlockCommonEnd( id ); + info.DefinedCustomBlocks[id >> 5] |= (1u << (id & 0x1F)); + } + + byte HandleCpeDefineBlockCommonStart( bool uniqueSideTexs ) { + byte block = reader.ReadUInt8(); + BlockInfo info = game.BlockInfo; + info.ResetBlockInfo( block, false ); + + info.Name[block] = reader.ReadAsciiString(); + info.CollideType[block] = (BlockCollideType)reader.ReadUInt8(); + if( info.CollideType[block] != BlockCollideType.Solid ) { + info.IsTransparent[block] = true; + info.IsOpaque[block] = false; + } + + info.SpeedMultiplier[block] = (float)Math.Pow( 2, (reader.ReadUInt8() - 128) / 64f ); + info.SetTex( reader.ReadUInt8(), TileSide.Top, (Block)block ); + if( uniqueSideTexs ) { + info.SetTex( reader.ReadUInt8(), TileSide.Left, (Block)block ); + info.SetTex( reader.ReadUInt8(), TileSide.Right, (Block)block ); + info.SetTex( reader.ReadUInt8(), TileSide.Front, (Block)block ); + info.SetTex( reader.ReadUInt8(), TileSide.Back, (Block)block ); + } else { + info.SetSide( reader.ReadUInt8(), (Block)block ); + } + info.SetTex( reader.ReadUInt8(), TileSide.Bottom, (Block)block ); + + info.BlocksLight[block] = reader.ReadUInt8() == 0; + byte sound = reader.ReadUInt8(); + if( sound < breakSnds.Length ) { + info.StepSounds[block] = stepSnds[sound]; + info.DigSounds[block] = breakSnds[sound]; + } + info.FullBright[block] = reader.ReadUInt8() != 0; + return block; + } + + void HandleCpeDefineBlockCommonEnd( byte block ) { + BlockInfo info = game.BlockInfo; + byte blockDraw = reader.ReadUInt8(); + SetBlockDraw( info, block, blockDraw ); + + byte fogDensity = reader.ReadUInt8(); + info.FogDensity[block] = fogDensity == 0 ? 0 : (fogDensity + 1) / 128f; + info.FogColour[block] = new FastColour( + reader.ReadUInt8(), reader.ReadUInt8(), reader.ReadUInt8() ); + info.SetupCullingCache( block ); + info.InitLightOffsets(); + game.Events.RaiseBlockDefinitionChanged(); + } + + void HandleDefineModel() { + int start = reader.index - 1; + byte id = reader.ReadUInt8(); + CustomModel model = null; + + switch( reader.ReadUInt8() ) { + case 0: + model = new CustomModel( game ); + model.ReadSetupPacket( reader ); + game.ModelCache.CustomModels[id] = model; + break; + case 1: + model = game.ModelCache.CustomModels[id]; + if( model != null ) model.ReadMetadataPacket( reader ); + break; + case 2: + model = game.ModelCache.CustomModels[id]; + if( model != null ) model.ReadDefinePartPacket( reader ); + break; + case 3: + model = game.ModelCache.CustomModels[id]; + if( model != null ) model.ReadRotationPacket( reader ); + break; + } + int total = packetSizes[(byte)PacketId.CpeDefineModel]; + reader.Skip( total - (reader.index - start) ); + } + + internal static SoundType[] stepSnds, breakSnds; + static NetworkProcessor() { + stepSnds = new SoundType[10]; + breakSnds = new SoundType[10]; + stepSnds[0] = SoundType.None; breakSnds[0] = SoundType.None; + stepSnds[1] = SoundType.Wood; breakSnds[1] = SoundType.Wood; + stepSnds[2] = SoundType.Gravel; breakSnds[2] = SoundType.Gravel; + stepSnds[3] = SoundType.Grass; breakSnds[3] = SoundType.Grass; + stepSnds[4] = SoundType.Stone; breakSnds[4] = SoundType.Stone; + // TODO: metal sound type, just use stone for now. + stepSnds[5] = SoundType.Stone; breakSnds[5] = SoundType.Stone; + stepSnds[6] = SoundType.Stone; breakSnds[6] = SoundType.Glass; + stepSnds[7] = SoundType.Cloth; breakSnds[7] = SoundType.Cloth; + stepSnds[8] = SoundType.Sand; breakSnds[8] = SoundType.Sand; + stepSnds[9] = SoundType.Snow; breakSnds[9] = SoundType.Snow; + } + + internal static void SetBlockDraw( BlockInfo info, byte block, byte blockDraw ) { + if( blockDraw == 1 ) { + info.IsTransparent[block] = true; + } else if( blockDraw == 2 ) { + info.IsTransparent[block] = true; + info.CullWithNeighbours[block] = false; + } else if( blockDraw == 3 ) { + info.IsTranslucent[block] = true; + } else if( blockDraw == 4 ) { + info.IsTransparent[block] = true; + info.IsAir[block] = true; + } + if( info.IsOpaque[block] ) + info.IsOpaque[block] = blockDraw == 0; + } + } +} \ No newline at end of file diff --git a/ClassicalSharp/Network/Utils/NetReader.cs b/ClassicalSharp/Network/Utils/NetReader.cs index bee777994..840d91275 100644 --- a/ClassicalSharp/Network/Utils/NetReader.cs +++ b/ClassicalSharp/Network/Utils/NetReader.cs @@ -73,20 +73,22 @@ namespace ClassicalSharp { public string ReadCp437String() { int length = GetString( false, 64 ); - index += 64; return new String( characters, 0, length ); } public string ReadAsciiString() { int length = GetString( true, 64 ); - index += 64; + return new String( characters, 0, length ); + } + + public string ReadAsciiString( int maxLength ) { + int length = GetString( true, maxLength ); return new String( characters, 0, length ); } internal string ReadChatString( ref byte messageType, bool useMessageTypes ) { if( !useMessageTypes ) messageType = (byte)MessageType.Normal; - int length = GetString( false, 64 ); - index += 64; + int length = GetString( false, 64 ); int offset = 0; if( length >= womDetail.Length && IsWomDetailString() ) { @@ -107,9 +109,10 @@ namespace ClassicalSharp { return true; } - int GetString( bool ascii, int bufferSize ) { + int GetString( bool ascii, int maxLength ) { int length = 0; - for( int i = bufferSize - 1; i >= 0; i-- ) { + index += maxLength; + for( int i = maxLength - 1; i >= 0; i-- ) { byte code = buffer[index + i]; if( length == 0 && !( code == 0 || code == 0x20 ) ) length = i + 1; From bb2f4a92711fd483b85c8a7d39fcb91205fc0961 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sat, 26 Mar 2016 00:15:29 +1100 Subject: [PATCH 2/3] More robustly handle audio device creation errors. Fixes #136. --- ClassicalSharp/Audio/AudioPlayer.Sounds.cs | 22 +++++++++++++++++---- ClassicalSharp/Audio/AudioPlayer.cs | 19 +++++++++++++++++- ClassicalSharp/Audio/Soundboard.cs | 2 +- ClassicalSharp/SharpWave.dll | Bin 81920 -> 81920 bytes 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/ClassicalSharp/Audio/AudioPlayer.Sounds.cs b/ClassicalSharp/Audio/AudioPlayer.Sounds.cs index 56263af3f..3b04601f7 100644 --- a/ClassicalSharp/Audio/AudioPlayer.Sounds.cs +++ b/ClassicalSharp/Audio/AudioPlayer.Sounds.cs @@ -46,7 +46,7 @@ namespace ClassicalSharp.Audio { void PlaySound( SoundType type, Soundboard board ) { if( type == SoundType.None || monoOutputs == null ) return; - Sound snd = board.PlayRandomSound( type ); + Sound snd = board.PickRandomSound( type ); snd.Metadata = board == digBoard ? (byte)1 : (byte)2; chunk.Channels = snd.Channels; chunk.Frequency = snd.SampleRate; @@ -72,14 +72,28 @@ namespace ClassicalSharp.Audio { firstSoundOut = output; outputs[i] = output; } + if( !output.DoneRawAsync() ) continue; - if( output.DoneRawAsync() ) { + try { output.PlayRawAsync( chunk ); - return; + } catch( InvalidOperationException ex ) { + HandleSoundError( ex ); } + return; } } + void HandleSoundError( InvalidOperationException ex ) { + ErrorHandler.LogError( "AudioPlayer.PlayCurrentSound()", ex ); + if( ex.Message == "No audio devices found" ) + game.Chat.Add( "&cNo audio devices found, disabling sounds." ); + else + game.Chat.Add( "&cAn error occured when trying to play sounds, disabling sounds." ); + + SetSound( false ); + game.UseSound = false; + } + void DisposeSound() { DisposeOutputs( ref monoOutputs ); DisposeOutputs( ref stereoOutputs ); @@ -108,6 +122,6 @@ namespace ClassicalSharp.Audio { outputs[i].Dispose(); } outputs = null; - } + } } } \ No newline at end of file diff --git a/ClassicalSharp/Audio/AudioPlayer.cs b/ClassicalSharp/Audio/AudioPlayer.cs index 4f2a7ef64..0aabb4849 100644 --- a/ClassicalSharp/Audio/AudioPlayer.cs +++ b/ClassicalSharp/Audio/AudioPlayer.cs @@ -12,8 +12,10 @@ namespace ClassicalSharp.Audio { IAudioOutput[] monoOutputs, stereoOutputs; string[] musicFiles; Thread musicThread; + Game game; public AudioPlayer( Game game ) { + this.game = game; game.UseMusic = Options.GetBool( OptionsKey.UseMusic, false ); SetMusic( game.UseMusic ); game.UseSound = Options.GetBool( OptionsKey.UseSound, false ); @@ -45,7 +47,11 @@ namespace ClassicalSharp.Audio { using( FileStream fs = File.OpenRead( path ) ) { OggContainer container = new OggContainer( fs ); - musicOut.PlayStreaming( container ); + try { + musicOut.PlayStreaming( container ); + } catch( InvalidOperationException ex) { + HandleMusicError( ex ); + } } if( disposingMusic ) break; @@ -54,6 +60,17 @@ namespace ClassicalSharp.Audio { } } + void HandleMusicError( InvalidOperationException ex ) { + ErrorHandler.LogError( "AudioPlayer.DoMusicThread()", ex ); + if( ex.Message == "No audio devices found" ) + game.Chat.Add( "&cNo audio devices found, disabling music." ); + else + game.Chat.Add( "&cAn error occured when trying to play music, disabling music." ); + + SetMusic( false ); + game.UseMusic = false; + } + bool disposingMusic; public void Dispose() { DisposeMusic(); diff --git a/ClassicalSharp/Audio/Soundboard.cs b/ClassicalSharp/Audio/Soundboard.cs index 0731f5f96..0dad729aa 100644 --- a/ClassicalSharp/Audio/Soundboard.cs +++ b/ClassicalSharp/Audio/Soundboard.cs @@ -29,7 +29,7 @@ namespace ClassicalSharp.Audio { GetGroups(); } - public Sound PlayRandomSound( SoundType type ) { + public Sound PickRandomSound( SoundType type ) { if( type == SoundType.None ) return null; string name = soundNames[(int)type]; diff --git a/ClassicalSharp/SharpWave.dll b/ClassicalSharp/SharpWave.dll index c567e2cee1c9ba12e30d46d68650cdd62f170cd2..eacd96ff1c0ad9da0156955fffb4e64d410e9c0e 100644 GIT binary patch delta 7003 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 delta 6895 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 Date: Sat, 26 Mar 2016 00:26:59 +1100 Subject: [PATCH 3/3] Quick fix for last commit borking chat. --- ClassicalSharp/Audio/AudioPlayer.cs | 1 + ClassicalSharp/Network/Utils/NetReader.cs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/ClassicalSharp/Audio/AudioPlayer.cs b/ClassicalSharp/Audio/AudioPlayer.cs index 0aabb4849..031fc5b5d 100644 --- a/ClassicalSharp/Audio/AudioPlayer.cs +++ b/ClassicalSharp/Audio/AudioPlayer.cs @@ -51,6 +51,7 @@ namespace ClassicalSharp.Audio { musicOut.PlayStreaming( container ); } catch( InvalidOperationException ex) { HandleMusicError( ex ); + return; } } if( disposingMusic ) break; diff --git a/ClassicalSharp/Network/Utils/NetReader.cs b/ClassicalSharp/Network/Utils/NetReader.cs index 840d91275..aeb08ec67 100644 --- a/ClassicalSharp/Network/Utils/NetReader.cs +++ b/ClassicalSharp/Network/Utils/NetReader.cs @@ -111,7 +111,7 @@ namespace ClassicalSharp { int GetString( bool ascii, int maxLength ) { int length = 0; - index += maxLength; + for( int i = maxLength - 1; i >= 0; i-- ) { byte code = buffer[index + i]; if( length == 0 && !( code == 0 || code == 0x20 ) ) @@ -131,6 +131,7 @@ namespace ClassicalSharp { characters[i] = Utils.ExtendedCharReplacements[code - 0x7F]; } } + index += maxLength; return length; } }