From faa8165b63f6477a5f58321332770a1149284359 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sat, 7 May 2016 07:26:01 +1000 Subject: [PATCH 01/19] Fix client crashing when a LevelInit packet is received, but a Handshake packet was not received beforehand. (Thanks Lemmmy) --- ClassicalSharp/Network/NetworkProcessor.Original.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/ClassicalSharp/Network/NetworkProcessor.Original.cs b/ClassicalSharp/Network/NetworkProcessor.Original.cs index 1ea55a902..7a54b2b77 100644 --- a/ClassicalSharp/Network/NetworkProcessor.Original.cs +++ b/ClassicalSharp/Network/NetworkProcessor.Original.cs @@ -172,8 +172,6 @@ namespace ClassicalSharp.Net { sentWomId = true; } gzipStream = null; - ServerName = null; - ServerMotd = null; GC.Collect(); } From 579357c081f0d75b1ba277354639712b6cbeb5fc Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sun, 8 May 2016 00:20:28 +1000 Subject: [PATCH 02/19] Reset all blocks on disconnection from server. --- ClassicalSharp/2D/Screens/ErrorScreen.cs | 1 + ClassicalSharp/Blocks/BlockInfo.cs | 36 +++++++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/ClassicalSharp/2D/Screens/ErrorScreen.cs b/ClassicalSharp/2D/Screens/ErrorScreen.cs index c6cb2145e..8a1414737 100644 --- a/ClassicalSharp/2D/Screens/ErrorScreen.cs +++ b/ClassicalSharp/2D/Screens/ErrorScreen.cs @@ -58,6 +58,7 @@ namespace ClassicalSharp.Gui { string connectString = "Connecting to " + game.IPAddress + ":" + game.Port + ".."; foreach( IGameComponent comp in game.Components ) comp.Reset( game ); + game.BlockInfo.Reset( game ); game.SetNewScreen( new LoadingMapScreen( game, connectString, "Waiting for handshake" ) ); game.Network.Connect( game.IPAddress, game.Port ); diff --git a/ClassicalSharp/Blocks/BlockInfo.cs b/ClassicalSharp/Blocks/BlockInfo.cs index 20409da2c..4eb683154 100644 --- a/ClassicalSharp/Blocks/BlockInfo.cs +++ b/ClassicalSharp/Blocks/BlockInfo.cs @@ -58,6 +58,40 @@ namespace ClassicalSharp { public const byte MaxDefinedBlock = byte.MaxValue; public const int BlocksCount = MaxDefinedBlock + 1; + public void Reset( Game game ) { + // Reset properties + for( int i = 0; i < IsTransparent.Length; i++ ) IsTransparent[i] = false; + for( int i = 0; i < IsTranslucent.Length; i++ ) IsTranslucent[i] = false; + for( int i = 0; i < IsOpaque.Length; i++ ) IsOpaque[i] = false; + for( int i = 0; i < IsOpaqueY.Length; i++ ) IsOpaqueY[i] = false; + for( int i = 0; i < IsSprite.Length; i++ ) IsSprite[i] = false; + for( int i = 0; i < IsLiquid.Length; i++ ) IsLiquid[i] = false; + for( int i = 0; i < BlocksLight.Length; i++ ) BlocksLight[i] = false; + for( int i = 0; i < FullBright.Length; i++ ) FullBright[i] = false; + for( int i = 0; i < Name.Length; i++ ) Name[i] = "Invalid"; + for( int i = 0; i < FogColour.Length; i++ ) FogColour[i] = default(FastColour); + for( int i = 0; i < FogDensity.Length; i++ ) FogDensity[i] = 0; + for( int i = 0; i < Collide.Length; i++ ) Collide[i] = CollideType.WalkThrough; + for( int i = 0; i < SpeedMultiplier.Length; i++ ) SpeedMultiplier[i] = 0; + for( int i = 0; i < CullWithNeighbours.Length; i++ ) CullWithNeighbours[i] = false; + for( int i = 0; i < LightOffset.Length; i++ ) LightOffset[i] = 0; + for( int i = 0; i < DefinedCustomBlocks.Length; i++ ) DefinedCustomBlocks[i] = 0; + // Reset textures + texId = 0; + for( int i = 0; i < textures.Length; i++ ) textures[i] = 0; + // Reset culling + for( int i = 0; i < hidden.Length; i++ ) hidden[i] = 0; + for( int i = 0; i < CanStretch.Length; i++ ) CanStretch[i] = false; + for( int i = 0; i < IsAir.Length; i++ ) IsAir[i] = false; + // Reset bounds + for( int i = 0; i < MinBB.Length; i++ ) MinBB[i] = Vector3.Zero; + for( int i = 0; i < MaxBB.Length; i++ ) MaxBB[i] = Vector3.One; + // Reset sounds + for( int i = 0; i < DigSounds.Length; i++ ) DigSounds[i] = SoundType.None; + for( int i = 0; i < StepSounds.Length; i++ ) StepSounds[i] = SoundType.None; + Init(); + } + public void Init() { for( int tile = 1; tile < BlocksCount; tile++ ) { MaxBB[tile].Y = 1; @@ -106,7 +140,7 @@ namespace ClassicalSharp { IsOpaqueY[(byte)Block.Snow] = true; InitBoundingBoxes(); - InitSounds(); + InitSounds(); SetupCullingCache(); InitLightOffsets(); } From 3aca306645f7c2ca8121fdddff1d164c5f663122 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sun, 8 May 2016 13:18:11 +1000 Subject: [PATCH 03/19] Fix pressing tab then escape clearing the items in the tab list but still showing its box. (Thanks JplaysClassic) --- ClassicalSharp/2D/Screens/HudScreen.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ClassicalSharp/2D/Screens/HudScreen.cs b/ClassicalSharp/2D/Screens/HudScreen.cs index 23d45b613..fdf2540df 100644 --- a/ClassicalSharp/2D/Screens/HudScreen.cs +++ b/ClassicalSharp/2D/Screens/HudScreen.cs @@ -35,7 +35,7 @@ namespace ClassicalSharp.Gui { //graphicsApi.BindTexture( game.TerrainAtlas.TexId ); //IsometricBlockDrawer.Draw( game, (byte)Block.Brick, 30, game.Width - 50, game.Height - 20 ); - if( playerList != null ) { + if( playerList != null && game.ActiveScreen == this ) { playerList.Render( delta ); // NOTE: Should usually be caught by KeyUp, but just in case. if( !game.IsKeyDown( KeyBinding.PlayerList ) ) { @@ -76,8 +76,6 @@ namespace ClassicalSharp.Gui { } public void LoseFocus() { - if( playerList != null ) - playerList.Dispose(); game.CursorVisible = true; } From b352f1c7c9ccf1fc0aa13139079af2aaa1c5b28e Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sun, 8 May 2016 13:31:31 +1000 Subject: [PATCH 04/19] Fog calculation should use camera position instead of entity's head position, fixes #191. (Thanks goodlyay) --- ClassicalSharp/GraphicsAPI/Direct3D9Api.cs | 2 -- ClassicalSharp/GraphicsAPI/OpenGLApi.cs | 11 +++---- ClassicalSharp/Math/BoundingBox.cs | 7 ++++ .../Rendering/StandardEnvRenderer.cs | 32 +++++++++---------- 4 files changed, 27 insertions(+), 25 deletions(-) diff --git a/ClassicalSharp/GraphicsAPI/Direct3D9Api.cs b/ClassicalSharp/GraphicsAPI/Direct3D9Api.cs index 7941dad44..c393c030f 100644 --- a/ClassicalSharp/GraphicsAPI/Direct3D9Api.cs +++ b/ClassicalSharp/GraphicsAPI/Direct3D9Api.cs @@ -131,8 +131,6 @@ namespace ClassicalSharp.GraphicsAPI { } public override void SetFogStart( float value ) { - if( value == fogStart ) return; - fogStart = value; device.SetRenderState( RenderState.FogStart, value ); } diff --git a/ClassicalSharp/GraphicsAPI/OpenGLApi.cs b/ClassicalSharp/GraphicsAPI/OpenGLApi.cs index 2fc04e668..2aba75875 100644 --- a/ClassicalSharp/GraphicsAPI/OpenGLApi.cs +++ b/ClassicalSharp/GraphicsAPI/OpenGLApi.cs @@ -81,13 +81,13 @@ namespace ClassicalSharp.GraphicsAPI { } } - float lastFogStart = -1, lastFogEnd = -1, lastFogDensity = -1; + float lastFogEnd = -1, lastFogDensity = -1; public override void SetFogDensity( float value ) { FogParam( FogParameter.FogDensity, value, ref lastFogDensity ); } public override void SetFogStart( float value ) { - FogParam( FogParameter.FogStart, value, ref lastFogStart ); + GL.Fogf( FogParameter.FogStart, value ); } public override void SetFogEnd( float value ) { @@ -95,10 +95,9 @@ namespace ClassicalSharp.GraphicsAPI { } static void FogParam( FogParameter param, float value, ref float last ) { - if( value != last ) { - GL.Fogf( param, value ); - last = value; - } + if( value == last ) return; + GL.Fogf( param, value ); + last = value; } Fog lastFogMode = (Fog)999; diff --git a/ClassicalSharp/Math/BoundingBox.cs b/ClassicalSharp/Math/BoundingBox.cs index b20680815..08d077a08 100644 --- a/ClassicalSharp/Math/BoundingBox.cs +++ b/ClassicalSharp/Math/BoundingBox.cs @@ -56,6 +56,13 @@ namespace ClassicalSharp { other.Max.X <= Max.X && other.Max.Y <= Max.Y && other.Max.Z <= Max.Z; } + /// Determines whether this bounding box entirely contains + /// the coordinates on all axes. + public bool Contains( Vector3 P ) { + return P.X >= Min.X && P.Y >= Min.Y && P.Z >= Min.Z && + P.X <= Max.X && P.Y <= Max.Y && P.Z <= Max.Z; + } + /// Determines whether this bounding box intersects /// the given bounding box on the X axis. public bool XIntersects( BoundingBox box ) { diff --git a/ClassicalSharp/Rendering/StandardEnvRenderer.cs b/ClassicalSharp/Rendering/StandardEnvRenderer.cs index 37a3a49fb..adaaa285f 100644 --- a/ClassicalSharp/Rendering/StandardEnvRenderer.cs +++ b/ClassicalSharp/Rendering/StandardEnvRenderer.cs @@ -37,14 +37,14 @@ namespace ClassicalSharp.Renderers { } RenderClouds( deltaTime ); - ResetFog(); + UpdateFog(); } protected override void EnvVariableChanged( object sender, EnvVarEventArgs e ) { if( e.Var == EnvVar.SkyColour ) { ResetSky(); } else if( e.Var == EnvVar.FogColour ) { - ResetFog(); + UpdateFog(); } else if( e.Var == EnvVar.CloudsColour ) { ResetClouds(); } else if( e.Var == EnvVar.CloudsLevel ) { @@ -55,6 +55,7 @@ namespace ClassicalSharp.Renderers { public override void Init( Game game ) { base.Init( game ); + graphics.SetFogStart( 0 ); graphics.Fog = true; ResetAllEnv( null, null ); game.Events.ViewDistanceChanged += ResetAllEnv; @@ -73,7 +74,7 @@ namespace ClassicalSharp.Renderers { } void ResetAllEnv( object sender, EventArgs e ) { - ResetFog(); + UpdateFog(); ResetSky(); ResetClouds(); } @@ -116,30 +117,27 @@ namespace ClassicalSharp.Renderers { return blend; } - void ResetFog() { + void UpdateFog() { if( map.IsNotLoaded ) return; FastColour adjFogCol = FastColour.White; BlockInfo info = game.BlockInfo; - BoundingBox pBounds = game.LocalPlayer.CollisionBounds; - Vector3I headCoords = Vector3I.Floor( game.LocalPlayer.EyePosition ); - Vector3 pos = (Vector3)headCoords; - byte headBlock = game.World.SafeGetBlock( headCoords ); - BoundingBox blockBB = new BoundingBox( pos + game.BlockInfo.MinBB[headBlock], - pos + game.BlockInfo.MaxBB[headBlock] ); - BoundingBox localBB = game.LocalPlayer.CollisionBounds; - bool intersecting = blockBB.Intersects( localBB ); + Vector3 pos = game.CurrentCameraPos; + Vector3I coords = Vector3I.Floor( pos ); + byte block = game.World.SafeGetBlock( coords ); + BoundingBox blockBB = new BoundingBox( + (Vector3)coords + info.MinBB[block], + (Vector3)coords + info.MaxBB[block] ); - if( intersecting && info.FogDensity[headBlock] != 0 ) { + if( blockBB.Contains( pos ) && info.FogDensity[block] != 0 ) { graphics.SetFogMode( Fog.Exp ); - graphics.SetFogDensity( info.FogDensity[headBlock] ); - adjFogCol = info.FogColour[headBlock]; + graphics.SetFogDensity( info.FogDensity[block] ); + adjFogCol = info.FogColour[block]; } else { // Blend fog and sky together float blend = (float)BlendFactor( game.ViewDistance ); adjFogCol = FastColour.Lerp( map.FogCol, map.SkyCol, blend ); graphics.SetFogMode( Fog.Linear ); - graphics.SetFogStart( 0 ); graphics.SetFogEnd( game.ViewDistance ); } graphics.ClearColour( adjFogCol ); @@ -173,7 +171,7 @@ namespace ClassicalSharp.Renderers { extent = Utils.AdjViewDist( extent ); int x1 = -extent, x2 = map.Width + extent; int z1 = -extent, z2 = map.Length + extent; - skyVertices = Utils.CountVertices( x2 - x1, z2 - z1, axisSize ); + skyVertices = Utils.CountVertices( x2 - x1, z2 - z1, axisSize ); VertexP3fC4b[] vertices = new VertexP3fC4b[skyVertices]; int height = Math.Max( map.Height + 2 + 6, map.CloudHeight + 6); From 27f329ac156891b4db15ee99ebed0c718a3b0fc2 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sun, 8 May 2016 14:10:24 +1000 Subject: [PATCH 05/19] Fix 'speed on' being in HUD even when on -hax maps. (Thanks 123DMWM) --- ClassicalSharp/2D/Screens/FpsScreen.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ClassicalSharp/2D/Screens/FpsScreen.cs b/ClassicalSharp/2D/Screens/FpsScreen.cs index 6b9c047d8..cb41f50ab 100644 --- a/ClassicalSharp/2D/Screens/FpsScreen.cs +++ b/ClassicalSharp/2D/Screens/FpsScreen.cs @@ -158,7 +158,9 @@ namespace ClassicalSharp.Gui { if( game.Fov != game.DefaultFov ) text.Append( ref index, "Zoom fov " ) .AppendNum( ref index, lastFov ).Append( ref index, " " ); if( fly ) text.Append( ref index, "Fly ON " ); - if( speeding || halfSpeeding ) text.Append( ref index, "Speed ON " ); + + bool showSpeedMsg = (speeding || halfSpeeding) && hacks.MaxSpeedMultiplier > 1; + if( showSpeedMsg ) text.Append( ref index, "Speed ON " ); if( noclip ) text.Append( ref index, "Noclip ON " ); hackStates.SetText( text.GetString() ); } From dfde526675cdb44124adf7b2a75b141fb5192dee Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sun, 8 May 2016 14:21:11 +1000 Subject: [PATCH 06/19] Fix single frame of lava fog in singleplayer. --- ClassicalSharp/Singleplayer/Server.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ClassicalSharp/Singleplayer/Server.cs b/ClassicalSharp/Singleplayer/Server.cs index aa7274d3d..e515ee1fb 100644 --- a/ClassicalSharp/Singleplayer/Server.cs +++ b/ClassicalSharp/Singleplayer/Server.cs @@ -36,8 +36,8 @@ namespace ClassicalSharp.Singleplayer { game.LocalPlayer.SkinName ); game.Events.RaiseBlockPermissionsChanged(); - int seed = 500;//new Random().Next(); - GenMap( 256, 256, 256, seed, new NotchyGenerator() ); + int seed = new Random().Next(); + GenMap( 128, 64, 128, seed, new NotchyGenerator() ); } char lastCol = '\0'; @@ -102,9 +102,8 @@ namespace ClassicalSharp.Singleplayer { IMapGenerator gen = generator; game.World.SetData( generatedMap, gen.Width, gen.Height, gen.Length ); generatedMap = null; - - game.WorldEvents.RaiseOnNewMapLoaded(); ResetPlayerPosition(); + game.WorldEvents.RaiseOnNewMapLoaded(); } generator = null; @@ -133,6 +132,7 @@ namespace ClassicalSharp.Singleplayer { LocationUpdate update = LocationUpdate.MakePosAndOri( x, y, z, 0, 0, false ); game.LocalPlayer.SetLocation( update, false ); game.LocalPlayer.Spawn = new Vector3( x, y, z ); + game.CurrentCameraPos = game.Camera.GetCameraPos( game.LocalPlayer.EyePosition ); } } } \ No newline at end of file From d74dc198e914bb22cbabd558b8df2cf0b1586d5f Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sun, 8 May 2016 14:39:53 +1000 Subject: [PATCH 07/19] Reorganise save level screen. --- ClassicalSharp/2D/Screens/Menu/SaveLevelScreen.cs | 8 +++++--- ClassicalSharp/2D/Widgets/Menu/MenuInputValidator.cs | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/ClassicalSharp/2D/Screens/Menu/SaveLevelScreen.cs b/ClassicalSharp/2D/Screens/Menu/SaveLevelScreen.cs index 61f37756e..d53f91221 100644 --- a/ClassicalSharp/2D/Screens/Menu/SaveLevelScreen.cs +++ b/ClassicalSharp/2D/Screens/Menu/SaveLevelScreen.cs @@ -54,11 +54,13 @@ namespace ClassicalSharp.Gui { regularFont = new Font( game.FontName, 16, FontStyle.Regular ); inputWidget = MenuInputWidget.Create( - game, -30, 50, 500, 30, "", Anchor.Centre, Anchor.Centre, + game, 0, 0, 500, 30, "", Anchor.Centre, Anchor.Centre, regularFont, titleFont, new PathValidator() ); - widgets = new [] { - ButtonWidget.Create( game, 260, 50, 60, 30, "Save", Anchor.Centre, + widgets = new Widget[] { + ChatTextWidget.Create( game, 0, -70, "Save level", + Anchor.Centre, Anchor.Centre, titleFont ), + ButtonWidget.Create( game, 0, 50, 201, 40, "Save", Anchor.Centre, Anchor.Centre, titleFont, OkButtonClick ), null, MakeBack( false, titleFont, diff --git a/ClassicalSharp/2D/Widgets/Menu/MenuInputValidator.cs b/ClassicalSharp/2D/Widgets/Menu/MenuInputValidator.cs index c6b0c903d..c2412caf2 100644 --- a/ClassicalSharp/2D/Widgets/Menu/MenuInputValidator.cs +++ b/ClassicalSharp/2D/Widgets/Menu/MenuInputValidator.cs @@ -109,7 +109,7 @@ namespace ClassicalSharp.Gui { public sealed class PathValidator : MenuInputValidator { public PathValidator() { - Range = "&7(Enter filename)"; + Range = "&7(Enter name)"; } public override bool IsValidChar( char c ) { From f5878f70a3d8efaa01c7c0fea60f5f080dcae1b7 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sun, 8 May 2016 15:39:49 +1000 Subject: [PATCH 08/19] Create .lvl and .fcm level exporter. --- ClassicalSharp/ClassicalSharp.csproj | 4 +- .../{IMapFileFormat.cs => IMapFormat.cs} | 0 ClassicalSharp/Map/Formats/MapCw.Exporter.cs | 4 +- .../Map/Formats/MapFcm3.Exporter.cs | 69 ++++++++++++++++++ ClassicalSharp/Map/Formats/MapLvl.Exporter.cs | 72 +++++++++++++++++++ ClassicalSharp/Map/Formats/MapLvl.Importer.cs | 8 ++- .../Network/NetworkProcessor.Original.cs | 4 +- ClassicalSharp/Utils/Utils.cs | 4 ++ 8 files changed, 157 insertions(+), 8 deletions(-) rename ClassicalSharp/Map/Formats/{IMapFileFormat.cs => IMapFormat.cs} (100%) create mode 100644 ClassicalSharp/Map/Formats/MapFcm3.Exporter.cs create mode 100644 ClassicalSharp/Map/Formats/MapLvl.Exporter.cs diff --git a/ClassicalSharp/ClassicalSharp.csproj b/ClassicalSharp/ClassicalSharp.csproj index 37a11630f..0b9eec11d 100644 --- a/ClassicalSharp/ClassicalSharp.csproj +++ b/ClassicalSharp/ClassicalSharp.csproj @@ -174,6 +174,8 @@ + + @@ -208,7 +210,7 @@ - + diff --git a/ClassicalSharp/Map/Formats/IMapFileFormat.cs b/ClassicalSharp/Map/Formats/IMapFormat.cs similarity index 100% rename from ClassicalSharp/Map/Formats/IMapFileFormat.cs rename to ClassicalSharp/Map/Formats/IMapFormat.cs diff --git a/ClassicalSharp/Map/Formats/MapCw.Exporter.cs b/ClassicalSharp/Map/Formats/MapCw.Exporter.cs index 95ec32aeb..5cd5db625 100644 --- a/ClassicalSharp/Map/Formats/MapCw.Exporter.cs +++ b/ClassicalSharp/Map/Formats/MapCw.Exporter.cs @@ -67,11 +67,11 @@ namespace ClassicalSharp.Map { nbt.Write( NbtTagType.Int8 ); nbt.Write( "H" ); - nbt.WriteUInt8( (byte)Utils.DegreesToPacked( p.SpawnYaw, 256 ) ); + nbt.WriteUInt8( (byte)Utils.DegreesToPacked( p.SpawnYaw ) ); nbt.Write( NbtTagType.Int8 ); nbt.Write( "P" ); - nbt.WriteUInt8( (byte)Utils.DegreesToPacked( p.SpawnPitch, 256 ) ); + nbt.WriteUInt8( (byte)Utils.DegreesToPacked( p.SpawnPitch ) ); nbt.Write( NbtTagType.End ); } diff --git a/ClassicalSharp/Map/Formats/MapFcm3.Exporter.cs b/ClassicalSharp/Map/Formats/MapFcm3.Exporter.cs new file mode 100644 index 000000000..f6ff7509a --- /dev/null +++ b/ClassicalSharp/Map/Formats/MapFcm3.Exporter.cs @@ -0,0 +1,69 @@ +// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT +// Part of fCraft | Copyright (c) 2009-2014 Matvei Stefarov | BSD-3 | See LICENSE.txt +using System; +using System.IO; +using System.IO.Compression; +using System.Text; +using ClassicalSharp.Entities; + +namespace ClassicalSharp.Map { + + /// Exports a world to a FCMv3 map file (fCraft server map) + public sealed class MapFcm3Exporter : IMapFormatExporter { + + const uint Identifier = 0x0FC2AF40; + const byte Revision = 13; + const int chunkSize = 128 * 128 * 128; + + public void Save( Stream stream, Game game ) { + World map = game.World; + LocalPlayer p = game.LocalPlayer; + BinaryWriter writer = new BinaryWriter( stream ); + writer.Write( Identifier ); + writer.Write( Revision ); + + writer.Write( (short)map.Width ); + writer.Write( (short)map.Height ); + writer.Write( (short)map.Length ); + + writer.Write( (int)(p.Spawn.X * 32) ); + writer.Write( (int)(p.Spawn.Y * 32) ); + writer.Write( (int)(p.Spawn.Z * 32) ); + + writer.Write( Utils.DegreesToPacked( p.SpawnYaw ) ); + writer.Write( Utils.DegreesToPacked( p.SpawnPitch ) ); + + writer.Write( 0 ); // Date modified + writer.Write( 0 ); // Date created + + writer.Write( map.Uuid.ToByteArray() ); + writer.Write( (byte)1 ); // layer count + + // skip over index and metacount + long indexOffset = stream.Position; + writer.Seek( 29, SeekOrigin.Current ); + long offset = stream.Position; + byte[] blocks = map.mapData; + + using( DeflateStream ds = new DeflateStream( stream, CompressionMode.Compress, true ) ) { + for( int i = 0; i < blocks.Length; i += chunkSize ) { + int len = Math.Min( chunkSize, blocks.Length - i ); + ds.Write( blocks, i, len ); + } + } + int compressedLength = (int)(stream.Position - offset); + + // come back to write the index + writer.BaseStream.Seek( indexOffset, SeekOrigin.Begin ); + + writer.Write( (byte)0 ); // data layer type (Blocks) + writer.Write( offset ); // offset, in bytes, from start of stream + writer.Write( compressedLength ); // compressed length, in bytes + writer.Write( 0 ); // general purpose field + writer.Write( 1 ); // element size + writer.Write( map.mapData.Length ); // element count + + writer.Write( 0 ); // No metadata + } + } +} \ No newline at end of file diff --git a/ClassicalSharp/Map/Formats/MapLvl.Exporter.cs b/ClassicalSharp/Map/Formats/MapLvl.Exporter.cs new file mode 100644 index 000000000..c60a37999 --- /dev/null +++ b/ClassicalSharp/Map/Formats/MapLvl.Exporter.cs @@ -0,0 +1,72 @@ +// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT +using System; +using System.IO; +using System.IO.Compression; +using System.Text; +using ClassicalSharp.Entities; +using ClassicalSharp.Net; + +namespace ClassicalSharp.Map { + + /// Exports a world to a LVL map file (MCLawl server map) + public sealed class MapLvlExporter : IMapFormatExporter { + + const int Version = 1874; + const byte customTile = 163; + + public void Save( Stream stream, Game game ) { + World map = game.World; + LocalPlayer p = game.LocalPlayer; + const int chunkSize = 128 * 128 * 128; + + using( DeflateStream gs = new DeflateStream( stream, CompressionMode.Compress ) ) { + BinaryWriter writer = new BinaryWriter( gs ); + + writer.Write( (ushort)Version ); + writer.Write( (ushort)map.Width ); + writer.Write( (ushort)map.Length ); + writer.Write( (ushort)map.Height ); + + writer.Write( (ushort)p.Spawn.X ); + writer.Write( (ushort)p.Spawn.Z ); + writer.Write( (ushort)p.Spawn.Y ); + writer.Write( Utils.DegreesToPacked( p.SpawnYaw ) ); + writer.Write( Utils.DegreesToPacked( p.SpawnPitch ) ); + + writer.Write( (ushort)0 ); // pervisit and perbuild perms + WriteBlocks( map.mapData, writer ); + + writer.Write( (byte)0xBD ); + WriteCustomBlocks( map, writer ); + } + } + + void WriteBlocks( byte[] blocks, BinaryWriter writer ) { + const int bufferSize = 64 * 1024; + byte[] buffer = new byte[bufferSize]; + int bIndex = 0; + + for( int i = 0; i < blocks.Length; i++ ) { + byte block = blocks[i]; + buffer[bIndex] = block >= BlockInfo.CpeBlocksCount ? customTile : block; + + bIndex++; + if( bIndex == bufferSize ) { + writer.Write( buffer, 0, bufferSize ); bIndex = 0; + } + } + if( bIndex > 0 ) writer.Write( buffer, 0, bIndex ); + } + + void WriteCustomBlocks( World map, BinaryWriter writer ) { + byte[] chunk = new byte[16 * 16 * 16]; + + for( int y = 0; y < map.Height; y += 16 ) + for( int z = 0; z < map.Length; z += 16 ) + for( int x = 0; x < map.Width; x += 16 ) + { + writer.Write( (byte)0 ); + } + } + } +} \ No newline at end of file diff --git a/ClassicalSharp/Map/Formats/MapLvl.Importer.cs b/ClassicalSharp/Map/Formats/MapLvl.Importer.cs index bff92d4ec..fb33c8687 100644 --- a/ClassicalSharp/Map/Formats/MapLvl.Importer.cs +++ b/ClassicalSharp/Map/Formats/MapLvl.Importer.cs @@ -13,6 +13,8 @@ namespace ClassicalSharp.Map { public sealed class MapLvlImporter : IMapFormatImporter { const int Version = 1874; + const byte customTile = 163; + public byte[] Load( Stream stream, Game game, out int width, out int height, out int length ) { GZipHeaderReader gsHeader = new GZipHeaderReader(); while( !gsHeader.ReadHeader( stream ) ) { } @@ -59,7 +61,7 @@ namespace ClassicalSharp.Map { int bx = i & 0xF, by = (i >> 8) & 0xF, bz = (i >> 4) & 0xF; int index = baseIndex + (by * length + bz) * width + bx; - if( blocks[index] == 163 ) // custom block id + if( blocks[index] == customTile ) blocks[index] = chunk[i]; } } @@ -82,8 +84,8 @@ namespace ClassicalSharp.Map { 34, 35, 36, 22, 20, 49, 45, 1, 4, 0, 9, 11, 4, 19, 5, 17, 10, 49, 20, 1, 18, 12, 5, 25, 46, 44, 17, 49, 20, 1, 18, 12, 5, 25, 36, 34, 0, 9, 11, 46, 44, 0, 9, 11, 8, 10, 22, 27, 22, 8, 10, 28, 17, 49, 20, 1, 18, 12, 5, 25, 46, - 44, 11, 9, 0, 9, 11, 163, 0, 0, 9, 11, 0, 0, 0, 0, 0, 0, 0, 28, 22, 21, 11, - 0, 0, 0, 46, 46, 10, 10, 46, 20, 41, 42, 11, 9, 0, 8, 10, 10, 8, 0, 22, 22, + 44, 11, 9, 0, 9, 11, customTile, 0, 0, 9, 11, 0, 0, 0, 0, 0, 0, 0, 28, 22, 21, + 11, 0, 0, 0, 46, 46, 10, 10, 46, 20, 41, 42, 11, 9, 0, 8, 10, 10, 8, 0, 22, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 10, 0, 0, 0, 0, 0, 22, 22, 42, 3, 2, 29, 47, 0, 0, 0, 0, 0, 27, 46, 48, 24, 22, 36, 34, 8, 10, 21, 29, 22, 10, 22, 22, 41, 19, 35, 21, 29, 49, 34, 16, 41, 0, 22 }; diff --git a/ClassicalSharp/Network/NetworkProcessor.Original.cs b/ClassicalSharp/Network/NetworkProcessor.Original.cs index 7a54b2b77..8863657cf 100644 --- a/ClassicalSharp/Network/NetworkProcessor.Original.cs +++ b/ClassicalSharp/Network/NetworkProcessor.Original.cs @@ -57,8 +57,8 @@ namespace ClassicalSharp.Net { 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 ) ); + writer.WriteUInt8( (byte)Utils.DegreesToPacked( yaw ) ); + writer.WriteUInt8( (byte)Utils.DegreesToPacked( pitch ) ); } #endregion diff --git a/ClassicalSharp/Utils/Utils.cs b/ClassicalSharp/Utils/Utils.cs index 0ed3bf870..c69df0ca9 100644 --- a/ClassicalSharp/Utils/Utils.cs +++ b/ClassicalSharp/Utils/Utils.cs @@ -150,6 +150,10 @@ namespace ClassicalSharp { return (int)(degrees * period / 360.0) % period; } + public static int DegreesToPacked( double degrees ) { + return (int)(degrees * 256 / 360.0) & 0xFF; + } + public static double PackedToDegrees( byte packed ) { return packed * 360.0 / 256.0; } From 442d72bd6baf12c037f1783689efb73752f4d05f Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sun, 8 May 2016 18:53:52 +1000 Subject: [PATCH 09/19] More usage of IGameComponent --- ClassicalSharp/2D/Screens/FpsScreen.cs | 10 +++- ClassicalSharp/2D/Screens/HudScreen.cs | 3 +- ClassicalSharp/Audio/AudioPlayer.cs | 3 +- ClassicalSharp/Commands/CommandManager.cs | 3 +- ClassicalSharp/Entities/LocalPlayer.cs | 2 - ClassicalSharp/Entities/NetPlayer.cs | 1 - ClassicalSharp/Entities/Player.cs | 6 ++- ClassicalSharp/Game/ChatLog.cs | 3 +- ClassicalSharp/Game/Game.Properties.cs | 5 +- ClassicalSharp/Game/Game.cs | 19 ++++--- ClassicalSharp/Game/Inventory.cs | 3 +- .../Map/Formats/MapFcm3.Exporter.cs | 49 +++++++++---------- .../Map/Formats/MapFcm3.Importer.cs | 39 +++++++-------- ClassicalSharp/Map/Formats/MapLvl.Exporter.cs | 41 +++++++--------- ClassicalSharp/Map/Formats/MapLvl.Importer.cs | 22 ++++----- .../Network/Utils/AsyncDownloader.cs | 3 +- ClassicalSharp/Rendering/BlockHandRenderer.cs | 3 +- ClassicalSharp/Rendering/ChunkUpdater.cs | 25 +++++----- ClassicalSharp/Rendering/EnvRenderer.cs | 1 + .../Rendering/MapBordersRenderer.cs | 7 +-- ClassicalSharp/Rendering/MapRenderer.cs | 2 +- ClassicalSharp/Rendering/WeatherRenderer.cs | 1 + .../Selections/AxisLinesRenderer.cs | 3 +- .../Selections/PickedPosRenderer.cs | 3 +- ClassicalSharp/Selections/SelectionManager.cs | 3 +- 25 files changed, 137 insertions(+), 123 deletions(-) diff --git a/ClassicalSharp/2D/Screens/FpsScreen.cs b/ClassicalSharp/2D/Screens/FpsScreen.cs index cb41f50ab..abf5b15c7 100644 --- a/ClassicalSharp/2D/Screens/FpsScreen.cs +++ b/ClassicalSharp/2D/Screens/FpsScreen.cs @@ -6,7 +6,7 @@ using ClassicalSharp.GraphicsAPI; namespace ClassicalSharp.Gui { - public class FpsScreen : Screen { + public class FpsScreen : Screen, IGameComponent { Font font, posFont; StringBuffer text; @@ -15,6 +15,12 @@ namespace ClassicalSharp.Gui { text = new StringBuffer( 128 ); } + public void Init( Game game ) { } + public void Ready( Game game) { Init(); } + public void Reset( Game game ) { } + public void OnNewMap( Game game ) { } + public void OnNewMapLoaded( Game game ) { } + TextWidget fpsText, hackStates; Texture posTex; public override void Render( double delta ) { @@ -168,7 +174,7 @@ namespace ClassicalSharp.Gui { const string possibleChars = "0123456789-, ()"; int[] widths = new int[possibleChars.Length]; - int baseWidth, curX, posHeight; + int baseWidth, curX; float texWidth; void MakePosTextWidget() { DrawTextArgs args = new DrawTextArgs( "", posFont, true ); diff --git a/ClassicalSharp/2D/Screens/HudScreen.cs b/ClassicalSharp/2D/Screens/HudScreen.cs index fdf2540df..a9abcd923 100644 --- a/ClassicalSharp/2D/Screens/HudScreen.cs +++ b/ClassicalSharp/2D/Screens/HudScreen.cs @@ -15,7 +15,8 @@ namespace ClassicalSharp.Gui { PlayerListWidget playerList; Font playerFont; - public void Init( Game game ) { Init(); } + public void Init( Game game ) { } + public void Ready( Game game) { Init(); } public void Reset( Game game ) { } public void OnNewMap( Game game ) { } public void OnNewMapLoaded( Game game ) { } diff --git a/ClassicalSharp/Audio/AudioPlayer.cs b/ClassicalSharp/Audio/AudioPlayer.cs index a89b9ffd4..d58e49475 100644 --- a/ClassicalSharp/Audio/AudioPlayer.cs +++ b/ClassicalSharp/Audio/AudioPlayer.cs @@ -25,7 +25,8 @@ namespace ClassicalSharp.Audio { game.UseSound = Options.GetBool( OptionsKey.UseSound, false ); SetSound( game.UseSound ); } - + + public void Ready( Game game ) { } public void Reset( Game game ) { } public void OnNewMap( Game game ) { } public void OnNewMapLoaded( Game game ) { } diff --git a/ClassicalSharp/Commands/CommandManager.cs b/ClassicalSharp/Commands/CommandManager.cs index 3d138fe6c..b5e8b2fb4 100644 --- a/ClassicalSharp/Commands/CommandManager.cs +++ b/ClassicalSharp/Commands/CommandManager.cs @@ -24,7 +24,8 @@ namespace ClassicalSharp.Commands { if( game.Network.IsSinglePlayer ) Register( new ModelCommand() ); } - + + public void Ready( Game game ) { } public void Reset( Game game ) { } public void OnNewMap( Game game ) { } public void OnNewMapLoaded( Game game ) { } diff --git a/ClassicalSharp/Entities/LocalPlayer.cs b/ClassicalSharp/Entities/LocalPlayer.cs index 9f61ddcba..6cc179d8d 100644 --- a/ClassicalSharp/Entities/LocalPlayer.cs +++ b/ClassicalSharp/Entities/LocalPlayer.cs @@ -52,8 +52,6 @@ namespace ClassicalSharp.Entities { Hacks.DoubleJump = !game.ClassicMode && Options.GetBool( OptionsKey.DoubleJump, false ); Hacks.Enabled = !game.ClassicMode && Options.GetBool( OptionsKey.HacksEnabled, true ); if( game.ClassicMode && game.ClassicHacks ) Hacks.Enabled = true; - - InitRenderingData(); } Vector3 lastSoundPos = new Vector3( float.PositiveInfinity ); diff --git a/ClassicalSharp/Entities/NetPlayer.cs b/ClassicalSharp/Entities/NetPlayer.cs index 7e8b52504..4b68be60b 100644 --- a/ClassicalSharp/Entities/NetPlayer.cs +++ b/ClassicalSharp/Entities/NetPlayer.cs @@ -13,7 +13,6 @@ namespace ClassicalSharp.Entities { SkinName = skinName; SkinIdentifier = "skin_" + id; interp = new InterpolatedComponent( game, this ); - InitRenderingData(); } public override void SetLocation( LocationUpdate update, bool interpolate ) { diff --git a/ClassicalSharp/Entities/Player.cs b/ClassicalSharp/Entities/Player.cs index 33d80ca29..5d45db43a 100644 --- a/ClassicalSharp/Entities/Player.cs +++ b/ClassicalSharp/Entities/Player.cs @@ -44,7 +44,7 @@ namespace ClassicalSharp.Entities { game.Graphics.DeleteTexture( ref nameTex.ID ); } - protected void InitRenderingData() { + protected void MakeNameTexture() { using( Font font = new Font( game.FontName, 24 ) ) { DrawTextArgs args = new DrawTextArgs( DisplayName, font, true ); nameTex = game.Drawer2D.MakeBitmappedTextTexture( ref args, 0, 0 ); @@ -53,11 +53,13 @@ namespace ClassicalSharp.Entities { public void UpdateName() { game.Graphics.DeleteTexture( ref nameTex ); - InitRenderingData(); + MakeNameTexture(); } protected void DrawName() { + if( nameTex.ID == 0 ) MakeNameTexture(); if( nameTex.ID == -1 ) return; + IGraphicsApi api = game.Graphics; api.BindTexture( nameTex.ID ); Vector3 pos = Position; pos.Y += Model.NameYOffset; diff --git a/ClassicalSharp/Game/ChatLog.cs b/ClassicalSharp/Game/ChatLog.cs index a703b7e99..2d03f80b1 100644 --- a/ClassicalSharp/Game/ChatLog.cs +++ b/ClassicalSharp/Game/ChatLog.cs @@ -17,7 +17,8 @@ namespace ClassicalSharp { public void Init( Game game ) { this.game = game; } - + + public void Ready( Game game ) { } public void Reset( Game game ) { } public void OnNewMap( Game game ) { } public void OnNewMapLoaded( Game game ) { } diff --git a/ClassicalSharp/Game/Game.Properties.cs b/ClassicalSharp/Game/Game.Properties.cs index 1100bac73..f8a699ee2 100644 --- a/ClassicalSharp/Game/Game.Properties.cs +++ b/ClassicalSharp/Game/Game.Properties.cs @@ -25,9 +25,12 @@ namespace ClassicalSharp { /// Represents a game component. public interface IGameComponent : IDisposable { - /// Called when the game has loaded. + /// Called when the game is being loaded. void Init( Game game ); + /// Called when the texture pack has been loaded and all components have been initalised. + void Ready( Game game ); + /// Called to reset the component's state when the user is reconnecting to a server. void Reset( Game game ); diff --git a/ClassicalSharp/Game/Game.cs b/ClassicalSharp/Game/Game.cs index 5d0abacfa..c48d1dc4b 100644 --- a/ClassicalSharp/Game/Game.cs +++ b/ClassicalSharp/Game/Game.cs @@ -85,12 +85,6 @@ namespace ClassicalSharp { TerrainAtlas1D = new TerrainAtlas1D( Graphics ); TerrainAtlas = new TerrainAtlas2D( Graphics, Drawer2D ); Animations = new Animations( this ); - defTexturePack = Options.Get( OptionsKey.DefaultTexturePack ) ?? "default.zip"; - TexturePackExtractor extractor = new TexturePackExtractor(); - extractor.Extract( "default.zip", this ); - // in case the user's default texture pack doesn't have all required textures - if( defTexturePack != "default.zip" ) - extractor.Extract( DefaultTexturePack, this ); Inventory = AddComponent( new Inventory() ); BlockInfo.SetDefaultBlockPermissions( Inventory.CanPlace, Inventory.CanDelete ); @@ -124,8 +118,7 @@ namespace ClassicalSharp { //Graphics.DepthWrite = true; Graphics.AlphaBlendFunc( BlendFunc.SourceAlpha, BlendFunc.InvSourceAlpha ); Graphics.AlphaTestFunc( CompareFunc.Greater, 0.5f ); - fpsScreen = new FpsScreen( this ); - fpsScreen.Init(); + fpsScreen = AddComponent( new FpsScreen( this ) ); hudScreen = AddComponent( new HudScreen( this ) ); Culling = new FrustumCulling(); Picking = AddComponent( new PickedPosRenderer() ); @@ -135,6 +128,16 @@ namespace ClassicalSharp { foreach( IGameComponent comp in Components ) comp.Init( this ); + defTexturePack = Options.Get( OptionsKey.DefaultTexturePack ) ?? "default.zip"; + TexturePackExtractor extractor = new TexturePackExtractor(); + extractor.Extract( "default.zip", this ); + // in case the user's default texture pack doesn't have all required textures + if( defTexturePack != "default.zip" ) + extractor.Extract( DefaultTexturePack, this ); + + foreach( IGameComponent comp in Components ) + comp.Ready( this ); + LoadIcon(); string connectString = "Connecting to " + IPAddress + ":" + Port + ".."; if( Graphics.WarnIfNecessary( Chat ) ) { diff --git a/ClassicalSharp/Game/Inventory.cs b/ClassicalSharp/Game/Inventory.cs index f868c7673..70b8a242a 100644 --- a/ClassicalSharp/Game/Inventory.cs +++ b/ClassicalSharp/Game/Inventory.cs @@ -21,7 +21,8 @@ namespace ClassicalSharp { Hotbar[6] = Block.Leaves; Hotbar[7] = Block.Grass; Hotbar[8] = Block.Slab; } - + + public void Ready( Game game ) { } public void Reset( Game game ) { } public void OnNewMap( Game game ) { } public void OnNewMapLoaded( Game game ) { } diff --git a/ClassicalSharp/Map/Formats/MapFcm3.Exporter.cs b/ClassicalSharp/Map/Formats/MapFcm3.Exporter.cs index f6ff7509a..bef6ab097 100644 --- a/ClassicalSharp/Map/Formats/MapFcm3.Exporter.cs +++ b/ClassicalSharp/Map/Formats/MapFcm3.Exporter.cs @@ -3,7 +3,6 @@ using System; using System.IO; using System.IO.Compression; -using System.Text; using ClassicalSharp.Entities; namespace ClassicalSharp.Map { @@ -18,30 +17,30 @@ namespace ClassicalSharp.Map { public void Save( Stream stream, Game game ) { World map = game.World; LocalPlayer p = game.LocalPlayer; - BinaryWriter writer = new BinaryWriter( stream ); - writer.Write( Identifier ); - writer.Write( Revision ); + BinaryWriter w = new BinaryWriter( stream ); + w.Write( Identifier ); + w.Write( Revision ); - writer.Write( (short)map.Width ); - writer.Write( (short)map.Height ); - writer.Write( (short)map.Length ); + w.Write( (short)map.Width ); + w.Write( (short)map.Height ); + w.Write( (short)map.Length ); - writer.Write( (int)(p.Spawn.X * 32) ); - writer.Write( (int)(p.Spawn.Y * 32) ); - writer.Write( (int)(p.Spawn.Z * 32) ); + w.Write( (int)(p.Spawn.X * 32) ); + w.Write( (int)(p.Spawn.Y * 32) ); + w.Write( (int)(p.Spawn.Z * 32) ); - writer.Write( Utils.DegreesToPacked( p.SpawnYaw ) ); - writer.Write( Utils.DegreesToPacked( p.SpawnPitch ) ); + w.Write( Utils.DegreesToPacked( p.SpawnYaw ) ); + w.Write( Utils.DegreesToPacked( p.SpawnPitch ) ); - writer.Write( 0 ); // Date modified - writer.Write( 0 ); // Date created + w.Write( 0 ); // Date modified + w.Write( 0 ); // Date created - writer.Write( map.Uuid.ToByteArray() ); - writer.Write( (byte)1 ); // layer count + w.Write( map.Uuid.ToByteArray() ); + w.Write( (byte)1 ); // layer count // skip over index and metacount long indexOffset = stream.Position; - writer.Seek( 29, SeekOrigin.Current ); + w.Seek( 29, SeekOrigin.Current ); long offset = stream.Position; byte[] blocks = map.mapData; @@ -54,16 +53,16 @@ namespace ClassicalSharp.Map { int compressedLength = (int)(stream.Position - offset); // come back to write the index - writer.BaseStream.Seek( indexOffset, SeekOrigin.Begin ); + w.BaseStream.Seek( indexOffset, SeekOrigin.Begin ); - writer.Write( (byte)0 ); // data layer type (Blocks) - writer.Write( offset ); // offset, in bytes, from start of stream - writer.Write( compressedLength ); // compressed length, in bytes - writer.Write( 0 ); // general purpose field - writer.Write( 1 ); // element size - writer.Write( map.mapData.Length ); // element count + w.Write( (byte)0 ); // data layer type (Blocks) + w.Write( offset ); // offset, in bytes, from start of stream + w.Write( compressedLength ); // compressed length, in bytes + w.Write( 0 ); // general purpose field + w.Write( 1 ); // element size + w.Write( map.mapData.Length ); // element count - writer.Write( 0 ); // No metadata + w.Write( 0 ); // No metadata } } } \ No newline at end of file diff --git a/ClassicalSharp/Map/Formats/MapFcm3.Importer.cs b/ClassicalSharp/Map/Formats/MapFcm3.Importer.cs index a6e8db7d4..9b1bdbb7a 100644 --- a/ClassicalSharp/Map/Formats/MapFcm3.Importer.cs +++ b/ClassicalSharp/Map/Formats/MapFcm3.Importer.cs @@ -15,34 +15,33 @@ namespace ClassicalSharp.Map { const byte Revision = 13; public byte[] Load( Stream stream, Game game, out int width, out int height, out int length ) { - BinaryReader reader = new BinaryReader( stream ); - if( reader.ReadInt32() != Identifier || reader.ReadByte() != Revision ) { + BinaryReader r = new BinaryReader( stream ); + if( r.ReadInt32() != Identifier || r.ReadByte() != Revision ) throw new InvalidDataException( "Unexpected constant in .fcm file" ); - } - width = reader.ReadInt16(); - height = reader.ReadInt16(); - length = reader.ReadInt16(); + width = r.ReadInt16(); + height = r.ReadInt16(); + length = r.ReadInt16(); LocalPlayer p = game.LocalPlayer; - p.Spawn.X = reader.ReadInt32() / 32f; - p.Spawn.Y = reader.ReadInt32() / 32f; - p.Spawn.Z = reader.ReadInt32() / 32f; - p.SpawnYaw = (float)Utils.PackedToDegrees( reader.ReadByte() ); - p.SpawnPitch = (float)Utils.PackedToDegrees( reader.ReadByte() ); + p.Spawn.X = r.ReadInt32() / 32f; + p.Spawn.Y = r.ReadInt32() / 32f; + p.Spawn.Z = r.ReadInt32() / 32f; + p.SpawnYaw = (float)Utils.PackedToDegrees( r.ReadByte() ); + p.SpawnPitch = (float)Utils.PackedToDegrees( r.ReadByte() ); - reader.ReadUInt32(); // date modified - reader.ReadUInt32(); // date created - game.World.Uuid = new Guid( reader.ReadBytes( 16 ) ); - reader.ReadBytes( 26 ); // layer index - int metaSize = reader.ReadInt32(); + r.ReadUInt32(); // date modified + r.ReadUInt32(); // date created + game.World.Uuid = new Guid( r.ReadBytes( 16 ) ); + r.ReadBytes( 26 ); // layer index + int metaSize = r.ReadInt32(); using( DeflateStream ds = new DeflateStream( stream, CompressionMode.Decompress ) ) { - reader = new BinaryReader( ds ); + r = new BinaryReader( ds ); for( int i = 0; i < metaSize; i++ ) { - string group = ReadString( reader ); - string key = ReadString( reader ); - string value = ReadString( reader ); + string group = ReadString( r ); + string key = ReadString( r ); + string value = ReadString( r ); } byte[] blocks = new byte[width * height * length]; diff --git a/ClassicalSharp/Map/Formats/MapLvl.Exporter.cs b/ClassicalSharp/Map/Formats/MapLvl.Exporter.cs index c60a37999..3d8861405 100644 --- a/ClassicalSharp/Map/Formats/MapLvl.Exporter.cs +++ b/ClassicalSharp/Map/Formats/MapLvl.Exporter.cs @@ -2,9 +2,7 @@ using System; using System.IO; using System.IO.Compression; -using System.Text; using ClassicalSharp.Entities; -using ClassicalSharp.Net; namespace ClassicalSharp.Map { @@ -17,31 +15,30 @@ namespace ClassicalSharp.Map { public void Save( Stream stream, Game game ) { World map = game.World; LocalPlayer p = game.LocalPlayer; - const int chunkSize = 128 * 128 * 128; using( DeflateStream gs = new DeflateStream( stream, CompressionMode.Compress ) ) { - BinaryWriter writer = new BinaryWriter( gs ); + BinaryWriter w = new BinaryWriter( gs ); - writer.Write( (ushort)Version ); - writer.Write( (ushort)map.Width ); - writer.Write( (ushort)map.Length ); - writer.Write( (ushort)map.Height ); + w.Write( (ushort)Version ); + w.Write( (ushort)map.Width ); + w.Write( (ushort)map.Length ); + w.Write( (ushort)map.Height ); - writer.Write( (ushort)p.Spawn.X ); - writer.Write( (ushort)p.Spawn.Z ); - writer.Write( (ushort)p.Spawn.Y ); - writer.Write( Utils.DegreesToPacked( p.SpawnYaw ) ); - writer.Write( Utils.DegreesToPacked( p.SpawnPitch ) ); + w.Write( (ushort)p.Spawn.X ); + w.Write( (ushort)p.Spawn.Z ); + w.Write( (ushort)p.Spawn.Y ); + w.Write( Utils.DegreesToPacked( p.SpawnYaw ) ); + w.Write( Utils.DegreesToPacked( p.SpawnPitch ) ); - writer.Write( (ushort)0 ); // pervisit and perbuild perms - WriteBlocks( map.mapData, writer ); + w.Write( (ushort)0 ); // pervisit and perbuild perms + WriteBlocks( map.mapData, w ); - writer.Write( (byte)0xBD ); - WriteCustomBlocks( map, writer ); + w.Write( (byte)0xBD ); + WriteCustomBlocks( map, w ); } } - void WriteBlocks( byte[] blocks, BinaryWriter writer ) { + void WriteBlocks( byte[] blocks, BinaryWriter w ) { const int bufferSize = 64 * 1024; byte[] buffer = new byte[bufferSize]; int bIndex = 0; @@ -52,20 +49,20 @@ namespace ClassicalSharp.Map { bIndex++; if( bIndex == bufferSize ) { - writer.Write( buffer, 0, bufferSize ); bIndex = 0; + w.Write( buffer, 0, bufferSize ); bIndex = 0; } } - if( bIndex > 0 ) writer.Write( buffer, 0, bIndex ); + if( bIndex > 0 ) w.Write( buffer, 0, bIndex ); } - void WriteCustomBlocks( World map, BinaryWriter writer ) { + void WriteCustomBlocks( World map, BinaryWriter w ) { byte[] chunk = new byte[16 * 16 * 16]; for( int y = 0; y < map.Height; y += 16 ) for( int z = 0; z < map.Length; z += 16 ) for( int x = 0; x < map.Width; x += 16 ) { - writer.Write( (byte)0 ); + w.Write( (byte)0 ); } } } diff --git a/ClassicalSharp/Map/Formats/MapLvl.Importer.cs b/ClassicalSharp/Map/Formats/MapLvl.Importer.cs index fb33c8687..e2c0cd97e 100644 --- a/ClassicalSharp/Map/Formats/MapLvl.Importer.cs +++ b/ClassicalSharp/Map/Formats/MapLvl.Importer.cs @@ -20,22 +20,22 @@ namespace ClassicalSharp.Map { while( !gsHeader.ReadHeader( stream ) ) { } using( DeflateStream gs = new DeflateStream( stream, CompressionMode.Decompress ) ) { - BinaryReader reader = new BinaryReader( gs ); - ushort header = reader.ReadUInt16(); + BinaryReader r = new BinaryReader( gs ); + ushort header = r.ReadUInt16(); - width = header == Version ? reader.ReadUInt16() : header; - length = reader.ReadUInt16(); - height = reader.ReadUInt16(); + width = header == Version ? r.ReadUInt16() : header; + length = r.ReadUInt16(); + height = r.ReadUInt16(); LocalPlayer p = game.LocalPlayer; - p.Spawn.X = reader.ReadUInt16(); - p.Spawn.Z = reader.ReadUInt16(); - p.Spawn.Y = reader.ReadUInt16(); - p.SpawnYaw = (float)Utils.PackedToDegrees( reader.ReadByte() ); - p.SpawnPitch = (float)Utils.PackedToDegrees( reader.ReadByte() ); + p.Spawn.X = r.ReadUInt16(); + p.Spawn.Z = r.ReadUInt16(); + p.Spawn.Y = r.ReadUInt16(); + p.SpawnYaw = (float)Utils.PackedToDegrees( r.ReadByte() ); + p.SpawnPitch = (float)Utils.PackedToDegrees( r.ReadByte() ); if( header == Version ) - reader.ReadUInt16(); // pervisit and perbuild perms + r.ReadUInt16(); // pervisit and perbuild perms byte[] blocks = new byte[width * height * length]; int read = gs.Read( blocks, 0, blocks.Length ); ConvertPhysicsBlocks( blocks ); diff --git a/ClassicalSharp/Network/Utils/AsyncDownloader.cs b/ClassicalSharp/Network/Utils/AsyncDownloader.cs index dd30f5aef..1e0ccca72 100644 --- a/ClassicalSharp/Network/Utils/AsyncDownloader.cs +++ b/ClassicalSharp/Network/Utils/AsyncDownloader.cs @@ -36,7 +36,8 @@ namespace ClassicalSharp.Network { worker.IsBackground = true; worker.Start(); } - + + public void Ready( Game game ) { } public void Reset( Game game ) { lock( requestLocker ) requests.Clear(); diff --git a/ClassicalSharp/Rendering/BlockHandRenderer.cs b/ClassicalSharp/Rendering/BlockHandRenderer.cs index 12a011cf2..2628db92f 100644 --- a/ClassicalSharp/Rendering/BlockHandRenderer.cs +++ b/ClassicalSharp/Rendering/BlockHandRenderer.cs @@ -29,7 +29,8 @@ namespace ClassicalSharp.Renderers { lastType = (byte)game.Inventory.HeldBlock; game.Events.HeldBlockChanged += HeldBlockChanged; } - + + public void Ready( Game game ) { } public void Reset( Game game ) { } public void OnNewMap( Game game ) { } public void OnNewMapLoaded( Game game ) { } diff --git a/ClassicalSharp/Rendering/ChunkUpdater.cs b/ClassicalSharp/Rendering/ChunkUpdater.cs index 2418491d7..e8726f24a 100644 --- a/ClassicalSharp/Rendering/ChunkUpdater.cs +++ b/ClassicalSharp/Rendering/ChunkUpdater.cs @@ -27,13 +27,8 @@ namespace ClassicalSharp.Renderers { this.renderer = renderer; info = game.BlockInfo; - renderer._1DUsed = game.TerrainAtlas1D.CalcMaxUsedRow( game.TerrainAtlas, info ); - renderer.totalUsed = new int[game.TerrainAtlas1D.TexIds.Length]; - RecalcBooleans( true ); - builder = new ChunkMeshBuilder( game ); api = game.Graphics; - elementsPerBitmap = game.TerrainAtlas1D.elementsPerBitmap; game.Events.TerrainAtlasChanged += TerrainAtlasChanged; game.WorldEvents.OnNewMap += OnNewMap; @@ -60,8 +55,8 @@ namespace ClassicalSharp.Renderers { public void Refresh() { chunkPos = new Vector3I( int.MaxValue ); - renderer.totalUsed = new int[game.TerrainAtlas1D.TexIds.Length]; - if( renderer.chunks == null || game.World.IsNotLoaded ) return; + renderer.totalUsed = new int[game.TerrainAtlas1D.TexIds.Length]; + if( renderer.chunks == null || game.World.IsNotLoaded ) return; ClearChunkCache(); ResetChunkCache(); } @@ -93,11 +88,15 @@ namespace ClassicalSharp.Renderers { } void TerrainAtlasChanged( object sender, EventArgs e ) { - bool refreshRequired = elementsPerBitmap != game.TerrainAtlas1D.elementsPerBitmap; - elementsPerBitmap = game.TerrainAtlas1D.elementsPerBitmap; - renderer._1DUsed = game.TerrainAtlas1D.CalcMaxUsedRow( game.TerrainAtlas, info ); + if( renderer._1DUsed == -1 ) { + renderer.totalUsed = new int[game.TerrainAtlas1D.TexIds.Length]; + } else { + bool refreshRequired = elementsPerBitmap != game.TerrainAtlas1D.elementsPerBitmap; + if( refreshRequired ) Refresh(); + } - if( refreshRequired ) Refresh(); + renderer._1DUsed = game.TerrainAtlas1D.CalcMaxUsedRow( game.TerrainAtlas, info ); + elementsPerBitmap = game.TerrainAtlas1D.elementsPerBitmap; RecalcBooleans( true ); } @@ -139,9 +138,9 @@ namespace ClassicalSharp.Renderers { } for( int i = 0; i < used; i++ ) { - renderer.pendingTranslucent[i] = true; + renderer.pendingTranslucent[i] = true; renderer.usedTranslucent[i] = false; - renderer.pendingNormal[i] = true; + renderer.pendingNormal[i] = true; renderer.usedNormal[i] = false; } } diff --git a/ClassicalSharp/Rendering/EnvRenderer.cs b/ClassicalSharp/Rendering/EnvRenderer.cs index 2f414ea7f..29a68ed68 100644 --- a/ClassicalSharp/Rendering/EnvRenderer.cs +++ b/ClassicalSharp/Rendering/EnvRenderer.cs @@ -19,6 +19,7 @@ namespace ClassicalSharp.Renderers { game.WorldEvents.EnvVariableChanged += EnvVariableChanged; } + public void Ready( Game game ) { } public virtual void Reset( Game game ) { OnNewMap( game ); } public abstract void OnNewMap( Game game ); diff --git a/ClassicalSharp/Rendering/MapBordersRenderer.cs b/ClassicalSharp/Rendering/MapBordersRenderer.cs index 701926e55..c577a1e19 100644 --- a/ClassicalSharp/Rendering/MapBordersRenderer.cs +++ b/ClassicalSharp/Rendering/MapBordersRenderer.cs @@ -33,10 +33,6 @@ namespace ClassicalSharp.Renderers { game.WorldEvents.EnvVariableChanged += EnvVariableChanged; game.Events.ViewDistanceChanged += ResetSidesAndEdges; game.Events.TerrainAtlasChanged += ResetTextures; - - MakeTexture( ref edgeTexId, ref lastEdgeTexLoc, map.EdgeBlock ); - MakeTexture( ref sideTexId, ref lastSideTexLoc, map.SidesBlock ); - ResetSidesAndEdges( null, null ); } public void Render( double deltaTime ) { @@ -80,7 +76,8 @@ namespace ClassicalSharp.Renderers { graphics.DeleteVb( edgesVb ); sidesVb = edgesVb = -1; } - + + public void Ready( Game game ) { } public void Reset( Game game ) { OnNewMap( game ); } public void OnNewMap( Game game ) { diff --git a/ClassicalSharp/Rendering/MapRenderer.cs b/ClassicalSharp/Rendering/MapRenderer.cs index c45f08409..496c2ea36 100644 --- a/ClassicalSharp/Rendering/MapRenderer.cs +++ b/ClassicalSharp/Rendering/MapRenderer.cs @@ -42,7 +42,7 @@ namespace ClassicalSharp.Renderers { Game game; IGraphicsApi api; - internal int _1DUsed = 1; + internal int _1DUsed = -1; internal ChunkInfo[] chunks, unsortedChunks; internal bool[] usedTranslucent, usedNormal; internal bool[] pendingTranslucent, pendingNormal; diff --git a/ClassicalSharp/Rendering/WeatherRenderer.cs b/ClassicalSharp/Rendering/WeatherRenderer.cs index 53d7cd754..4961a6985 100644 --- a/ClassicalSharp/Rendering/WeatherRenderer.cs +++ b/ClassicalSharp/Rendering/WeatherRenderer.cs @@ -94,6 +94,7 @@ namespace ClassicalSharp.Renderers { } int length, width, maxY, oneY; + public void Ready( Game game ) { } public void Reset( Game game ) { OnNewMap( game ); } public void OnNewMap( Game game ) { diff --git a/ClassicalSharp/Selections/AxisLinesRenderer.cs b/ClassicalSharp/Selections/AxisLinesRenderer.cs index c79be5a5c..6fcfee0ec 100644 --- a/ClassicalSharp/Selections/AxisLinesRenderer.cs +++ b/ClassicalSharp/Selections/AxisLinesRenderer.cs @@ -14,7 +14,8 @@ namespace ClassicalSharp.Selections { public void Init( Game game ) { this.game = game; } - + + public void Ready( Game game ) { } public void Reset( Game game ) { } public void OnNewMap( Game game ) { } public void OnNewMapLoaded( Game game ) { } diff --git a/ClassicalSharp/Selections/PickedPosRenderer.cs b/ClassicalSharp/Selections/PickedPosRenderer.cs index 0e08030c0..caf7b4e85 100644 --- a/ClassicalSharp/Selections/PickedPosRenderer.cs +++ b/ClassicalSharp/Selections/PickedPosRenderer.cs @@ -16,7 +16,8 @@ namespace ClassicalSharp.Renderers { vb = graphics.CreateDynamicVb( VertexFormat.P3fC4b, verticesCount ); this.game = game; } - + + public void Ready( Game game ) { } public void Reset( Game game ) { } public void OnNewMap( Game game ) { } public void OnNewMapLoaded( Game game ) { } diff --git a/ClassicalSharp/Selections/SelectionManager.cs b/ClassicalSharp/Selections/SelectionManager.cs index c08249cc6..9e1723b10 100644 --- a/ClassicalSharp/Selections/SelectionManager.cs +++ b/ClassicalSharp/Selections/SelectionManager.cs @@ -17,7 +17,8 @@ namespace ClassicalSharp.Selections { this.game = game; Graphics = game.Graphics; } - + + public void Ready( Game game ) { } public void Reset( Game game ) { selections.Clear(); } public void OnNewMap( Game game ) { selections.Clear(); } public void OnNewMapLoaded( Game game ) { } From b0f3faa53004ea23389487929c04910820f9754d Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sun, 8 May 2016 19:13:09 +1000 Subject: [PATCH 10/19] Reduce 'popping' effect when leaving the ground and view bobbing is enabled, partially addresses #192. --- ClassicalSharp/Game/Game.cs | 18 +++++----- ClassicalSharp/Particles/ParticleManager.cs | 3 +- ClassicalSharp/Utils/Camera.cs | 39 ++++++++++++++------- 3 files changed, 37 insertions(+), 23 deletions(-) diff --git a/ClassicalSharp/Game/Game.cs b/ClassicalSharp/Game/Game.cs index c48d1dc4b..e24381473 100644 --- a/ClassicalSharp/Game/Game.cs +++ b/ClassicalSharp/Game/Game.cs @@ -127,14 +127,7 @@ namespace ClassicalSharp { foreach( IGameComponent comp in Components ) comp.Init( this ); - - defTexturePack = Options.Get( OptionsKey.DefaultTexturePack ) ?? "default.zip"; - TexturePackExtractor extractor = new TexturePackExtractor(); - extractor.Extract( "default.zip", this ); - // in case the user's default texture pack doesn't have all required textures - if( defTexturePack != "default.zip" ) - extractor.Extract( DefaultTexturePack, this ); - + ExtractInitialTexturePack(); foreach( IGameComponent comp in Components ) comp.Ready( this ); @@ -148,6 +141,15 @@ namespace ClassicalSharp { Network.Connect( IPAddress, Port ); } + void ExtractInitialTexturePack() { + defTexturePack = Options.Get( OptionsKey.DefaultTexturePack ) ?? "default.zip"; + TexturePackExtractor extractor = new TexturePackExtractor(); + extractor.Extract( "default.zip", this ); + // in case the user's default texture pack doesn't have all required textures + if( defTexturePack != "default.zip" ) + extractor.Extract( DefaultTexturePack, this ); + } + void LoadOptions() { ClassicMode = Options.GetBool( "mode-classic", false ); ClassicHacks = Options.GetBool( OptionsKey.AllowClassicHacks, false ); diff --git a/ClassicalSharp/Particles/ParticleManager.cs b/ClassicalSharp/Particles/ParticleManager.cs index be5e23840..2ebf03d9b 100644 --- a/ClassicalSharp/Particles/ParticleManager.cs +++ b/ClassicalSharp/Particles/ParticleManager.cs @@ -13,13 +13,12 @@ namespace ClassicalSharp.Particles { int[] terrain1DCount, terrain1DIndices; Game game; - Random rnd; + Random rnd = new Random(); int vb; const int maxParticles = 600; public ParticleManager( Game game ) { this.game = game; - rnd = new Random(); vb = game.Graphics.CreateDynamicVb( VertexFormat.P3fT2fC4b, maxParticles * 4 ); game.Events.TerrainAtlasChanged += TerrainAtlasChanged; } diff --git a/ClassicalSharp/Utils/Camera.cs b/ClassicalSharp/Utils/Camera.cs index 4a8d12c73..68598c7e2 100644 --- a/ClassicalSharp/Utils/Camera.cs +++ b/ClassicalSharp/Utils/Camera.cs @@ -60,7 +60,7 @@ namespace ClassicalSharp { } public override void GetPickedBlock( PickedPos pos ) { - Vector3 dir = Utils.GetDirVector( player.HeadYawRadians, + Vector3 dir = Utils.GetDirVector( player.HeadYawRadians, AdjustPitch( player.PitchDegrees ) ); Vector3 eyePos = player.EyePosition; float reach = game.LocalPlayer.ReachDistance; @@ -110,15 +110,28 @@ namespace ClassicalSharp { UpdateMouseRotation(); } - protected float bobYOffset = 0; + protected float bobYOffset = 0, tilt = 0; + bool finishedTilt = true; protected void CalcViewBobbing( double delta ) { + LocalPlayer p = game.LocalPlayer; if( !game.ViewBobbing || !game.LocalPlayer.onGround ) { - tiltMatrix = Matrix4.Identity; - bobYOffset = 0; - } else { - tiltMatrix = Matrix4.RotateZ( game.LocalPlayer.anim.tilt ); - bobYOffset = game.LocalPlayer.anim.bobYOffset * (2.0f/2.5f); + // When player leaves the ground, still want to finish the current bob cycle. + if( finishedTilt || FinishTilt() ) return; } + + tilt = p.anim.tilt; + tiltMatrix = Matrix4.RotateZ( tilt ); + bobYOffset = p.anim.bobYOffset * (2.0f/2.5f); + finishedTilt = false; + } + + bool FinishTilt() { + LocalPlayer p = game.LocalPlayer; + if( Math.Sign( tilt ) == Math.Sign( p.anim.tilt ) ) return false; + tiltMatrix = Matrix4.Identity; + bobYOffset = 0; + finishedTilt = true; + return true; } } @@ -138,7 +151,7 @@ namespace ClassicalSharp { Vector3 eyePos = player.EyePosition; eyePos.Y += bobYOffset; - Vector3 dir = -Utils.GetDirVector( player.HeadYawRadians, + Vector3 dir = -Utils.GetDirVector( player.HeadYawRadians, AdjustPitch( player.PitchDegrees ) ); Picking.ClipCameraPos( game, eyePos, dir, dist, game.CameraClipPos ); Vector3 cameraPos = game.CameraClipPos.IntersectPoint; @@ -148,7 +161,7 @@ namespace ClassicalSharp { public override bool IsThirdPerson { get { return true; } } public override Vector3 GetCameraPos( Vector3 eyePos ) { - Vector3 dir = -Utils.GetDirVector( player.HeadYawRadians, + Vector3 dir = -Utils.GetDirVector( player.HeadYawRadians, AdjustPitch( player.PitchDegrees ) ); Picking.ClipCameraPos( game, eyePos, dir, dist, game.CameraClipPos ); return game.CameraClipPos.IntersectPoint; @@ -171,7 +184,7 @@ namespace ClassicalSharp { Vector3 eyePos = player.EyePosition; eyePos.Y += bobYOffset; - Vector3 dir = Utils.GetDirVector( player.HeadYawRadians, + Vector3 dir = Utils.GetDirVector( player.HeadYawRadians, AdjustPitch( player.PitchDegrees ) ); Picking.ClipCameraPos( game, eyePos, dir, dist, game.CameraClipPos ); Vector3 cameraPos = game.CameraClipPos.IntersectPoint; @@ -181,7 +194,7 @@ namespace ClassicalSharp { public override bool IsThirdPerson { get { return true; } } public override Vector3 GetCameraPos( Vector3 eyePos ) { - Vector3 dir = Utils.GetDirVector( player.HeadYawRadians, + Vector3 dir = Utils.GetDirVector( player.HeadYawRadians, AdjustPitch( player.PitchDegrees ) ); Picking.ClipCameraPos( game, eyePos, dir, dist, game.CameraClipPos ); return game.CameraClipPos.IntersectPoint; @@ -191,13 +204,13 @@ namespace ClassicalSharp { public class FirstPersonCamera : PerspectiveCamera { public FirstPersonCamera( Game window ) : base( window ) { - } + } public override Matrix4 GetView( double delta ) { CalcViewBobbing( delta ); Vector3 eyePos = player.EyePosition; eyePos.Y += bobYOffset; - Vector3 cameraDir = Utils.GetDirVector( player.HeadYawRadians, + Vector3 cameraDir = Utils.GetDirVector( player.HeadYawRadians, AdjustPitch( player.PitchDegrees ) ); return Matrix4.LookAt( eyePos, eyePos + cameraDir, Vector3.UnitY ) * tiltMatrix; } From 9c432833decf4f4d3e6cc6c9061199652062521f Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sun, 8 May 2016 20:37:41 +1000 Subject: [PATCH 11/19] Remove .lcl and .fcm exporter, use .schematic exporter which actually works in recent MCEdit. (Thanks goodlyay) --- .../2D/Screens/Menu/SaveLevelScreen.cs | 80 ++++++++++--------- .../2D/Widgets/Menu/MenuInputValidator.cs | 2 +- ClassicalSharp/ClassicalSharp.csproj | 3 +- .../Map/Formats/MapFcm3.Exporter.cs | 68 ---------------- ClassicalSharp/Map/Formats/MapLvl.Exporter.cs | 69 ---------------- .../Map/Formats/MapSchematic.Exporter.cs | 77 ++++++++++++++++++ ClassicalSharp/Map/Formats/NbtFile.cs | 2 + 7 files changed, 124 insertions(+), 177 deletions(-) delete mode 100644 ClassicalSharp/Map/Formats/MapFcm3.Exporter.cs delete mode 100644 ClassicalSharp/Map/Formats/MapLvl.Exporter.cs create mode 100644 ClassicalSharp/Map/Formats/MapSchematic.Exporter.cs diff --git a/ClassicalSharp/2D/Screens/Menu/SaveLevelScreen.cs b/ClassicalSharp/2D/Screens/Menu/SaveLevelScreen.cs index d53f91221..1ae22879a 100644 --- a/ClassicalSharp/2D/Screens/Menu/SaveLevelScreen.cs +++ b/ClassicalSharp/2D/Screens/Menu/SaveLevelScreen.cs @@ -14,29 +14,31 @@ namespace ClassicalSharp.Gui { MenuInputWidget inputWidget; TextWidget descWidget; + const int overwriteIndex = 2; + FastColour grey = new FastColour( 150, 150, 150 ); public override void Render( double delta ) { RenderMenuBounds(); api.Texturing = true; RenderMenuWidgets( delta ); inputWidget.Render( delta ); - if( descWidget != null ) - descWidget.Render( delta ); + if( descWidget != null ) descWidget.Render( delta ); api.Texturing = false; - if( textPath != null ) { - SaveMap( textPath ); - textPath = null; - } + float cX = game.Width / 2, cY = game.Height / 2; + api.Draw2DQuad( cX - 300, cY + 90, 600, 2, grey ); + if( textPath == null ) return; + SaveMap( textPath ); + textPath = null; } public override bool HandlesKeyPress( char key ) { - RemoveOverwriteButton(); + RemoveOverwrites(); return inputWidget.HandlesKeyPress( key ); } public override bool HandlesKeyDown( Key key ) { - RemoveOverwriteButton(); + RemoveOverwrites(); if( key == Key.Escape ) { game.SetNewScreen( null ); return true; @@ -54,14 +56,14 @@ namespace ClassicalSharp.Gui { regularFont = new Font( game.FontName, 16, FontStyle.Regular ); inputWidget = MenuInputWidget.Create( - game, 0, 0, 500, 30, "", Anchor.Centre, Anchor.Centre, + game, 0, -30, 500, 30, "", Anchor.Centre, Anchor.Centre, regularFont, titleFont, new PathValidator() ); widgets = new Widget[] { - ChatTextWidget.Create( game, 0, -70, "Save level", - Anchor.Centre, Anchor.Centre, titleFont ), - ButtonWidget.Create( game, 0, 50, 201, 40, "Save", Anchor.Centre, - Anchor.Centre, titleFont, OkButtonClick ), + ButtonWidget.Create( game, 0, 20, 301, 40, "Save", Anchor.Centre, + Anchor.Centre, titleFont, SaveClassic ), + ButtonWidget.Create( game, 0, 120, 201, 40, "Save schematic", Anchor.Centre, + Anchor.Centre, titleFont, SaveSchematic ), null, MakeBack( false, titleFont, (g, w) => g.SetNewScreen( new PauseScreen( g ) ) ), @@ -81,54 +83,58 @@ namespace ClassicalSharp.Gui { base.Dispose(); } - void OkButtonClick( Game game, Widget widget, MouseButton mouseBtn ) { + void SaveClassic( Game game, Widget widget, MouseButton mouseBtn ) { + DoSave( widget, mouseBtn, ".cw" ); + } + + void SaveSchematic( Game game, Widget widget, MouseButton mouseBtn ) { + DoSave( widget, mouseBtn, ".schematic" ); + } + + void DoSave( Widget widget, MouseButton mouseBtn, string ext ) { if( mouseBtn != MouseButton.Left ) return; + string text = inputWidget.GetText(); if( text.Length == 0 ) { - MakeDescWidget( "Please enter a filename" ); - return; + MakeDescWidget( "&ePlease enter a filename" ); return; } - string file = Path.ChangeExtension( text, ".cw" ); + string file = Path.ChangeExtension( text, ext ); text = Path.Combine( Program.AppDirectory, "maps" ); text = Path.Combine( text, file ); - if( File.Exists( text ) ) { - widgets[1] = ButtonWidget.Create( game, 0, 90, 260, 30, "Overwrite existing?", - Anchor.Centre, Anchor.Centre, titleFont, OverwriteButtonClick ); + if( File.Exists( text ) && widget.Metadata == null ) { + ((ButtonWidget)widget).SetText( "&cOverwrite existing?" ); + ((ButtonWidget)widget).Metadata = true; } else { // NOTE: We don't immediately save here, because otherwise the 'saving...' // will not be rendered in time because saving is done on the main thread. MakeDescWidget( "Saving.." ); textPath = text; - RemoveOverwriteButton(); + RemoveOverwrites(); } } - void OverwriteButtonClick( Game game, Widget widget, MouseButton mouseBtn ) { - if( mouseBtn != MouseButton.Left ) return; - string text = inputWidget.GetText(); - string file = Path.ChangeExtension( text, ".cw" ); - text = Path.Combine( Program.AppDirectory, "maps" ); - text = Path.Combine( text, file ); - - MakeDescWidget( "Saving.." ); - textPath = text; - RemoveOverwriteButton(); + void RemoveOverwrites() { + RemoveOverwrite( widgets[0] ); RemoveOverwrite( widgets[1] ); } - void RemoveOverwriteButton() { - if( widgets[1] == null ) return; - widgets[1].Dispose(); - widgets[1] = null; + void RemoveOverwrite( Widget widget ) { + ButtonWidget button = (ButtonWidget)widget; + if( button.Metadata == null ) return; + button.Metadata = null; + button.SetText( "Save" ); } string textPath; void SaveMap( string path ) { + bool classic = path.EndsWith( ".cw" ); try { if( File.Exists( path ) ) File.Delete( path ); using( FileStream fs = new FileStream( path, FileMode.CreateNew, FileAccess.Write ) ) { - IMapFormatExporter exporter = new MapCwExporter(); + IMapFormatExporter exporter = null; + if( classic ) exporter = new MapCwExporter(); + else exporter = new MapSchematicExporter(); exporter.Save( fs, game ); } } catch( Exception ex ) { @@ -142,7 +148,7 @@ namespace ClassicalSharp.Gui { void MakeDescWidget( string text ) { DisposeDescWidget(); - descWidget = ChatTextWidget.Create( game, 0, 90, text, + descWidget = ChatTextWidget.Create( game, 0, 65, text, Anchor.Centre, Anchor.Centre, regularFont ); } diff --git a/ClassicalSharp/2D/Widgets/Menu/MenuInputValidator.cs b/ClassicalSharp/2D/Widgets/Menu/MenuInputValidator.cs index c2412caf2..cbc56f986 100644 --- a/ClassicalSharp/2D/Widgets/Menu/MenuInputValidator.cs +++ b/ClassicalSharp/2D/Widgets/Menu/MenuInputValidator.cs @@ -114,7 +114,7 @@ namespace ClassicalSharp.Gui { public override bool IsValidChar( char c ) { return !(c == '/' || c == '\\' || c == '?' || c == '*' || c == ':' - || c == '<' || c == '>' || c == '|' || c == '"'); + || c == '<' || c == '>' || c == '|' || c == '"' || c == '.'); } public override bool IsValidString( string s ) { return true; } diff --git a/ClassicalSharp/ClassicalSharp.csproj b/ClassicalSharp/ClassicalSharp.csproj index 0b9eec11d..f4b59650a 100644 --- a/ClassicalSharp/ClassicalSharp.csproj +++ b/ClassicalSharp/ClassicalSharp.csproj @@ -174,8 +174,7 @@ - - + diff --git a/ClassicalSharp/Map/Formats/MapFcm3.Exporter.cs b/ClassicalSharp/Map/Formats/MapFcm3.Exporter.cs deleted file mode 100644 index bef6ab097..000000000 --- a/ClassicalSharp/Map/Formats/MapFcm3.Exporter.cs +++ /dev/null @@ -1,68 +0,0 @@ -// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT -// Part of fCraft | Copyright (c) 2009-2014 Matvei Stefarov | BSD-3 | See LICENSE.txt -using System; -using System.IO; -using System.IO.Compression; -using ClassicalSharp.Entities; - -namespace ClassicalSharp.Map { - - /// Exports a world to a FCMv3 map file (fCraft server map) - public sealed class MapFcm3Exporter : IMapFormatExporter { - - const uint Identifier = 0x0FC2AF40; - const byte Revision = 13; - const int chunkSize = 128 * 128 * 128; - - public void Save( Stream stream, Game game ) { - World map = game.World; - LocalPlayer p = game.LocalPlayer; - BinaryWriter w = new BinaryWriter( stream ); - w.Write( Identifier ); - w.Write( Revision ); - - w.Write( (short)map.Width ); - w.Write( (short)map.Height ); - w.Write( (short)map.Length ); - - w.Write( (int)(p.Spawn.X * 32) ); - w.Write( (int)(p.Spawn.Y * 32) ); - w.Write( (int)(p.Spawn.Z * 32) ); - - w.Write( Utils.DegreesToPacked( p.SpawnYaw ) ); - w.Write( Utils.DegreesToPacked( p.SpawnPitch ) ); - - w.Write( 0 ); // Date modified - w.Write( 0 ); // Date created - - w.Write( map.Uuid.ToByteArray() ); - w.Write( (byte)1 ); // layer count - - // skip over index and metacount - long indexOffset = stream.Position; - w.Seek( 29, SeekOrigin.Current ); - long offset = stream.Position; - byte[] blocks = map.mapData; - - using( DeflateStream ds = new DeflateStream( stream, CompressionMode.Compress, true ) ) { - for( int i = 0; i < blocks.Length; i += chunkSize ) { - int len = Math.Min( chunkSize, blocks.Length - i ); - ds.Write( blocks, i, len ); - } - } - int compressedLength = (int)(stream.Position - offset); - - // come back to write the index - w.BaseStream.Seek( indexOffset, SeekOrigin.Begin ); - - w.Write( (byte)0 ); // data layer type (Blocks) - w.Write( offset ); // offset, in bytes, from start of stream - w.Write( compressedLength ); // compressed length, in bytes - w.Write( 0 ); // general purpose field - w.Write( 1 ); // element size - w.Write( map.mapData.Length ); // element count - - w.Write( 0 ); // No metadata - } - } -} \ No newline at end of file diff --git a/ClassicalSharp/Map/Formats/MapLvl.Exporter.cs b/ClassicalSharp/Map/Formats/MapLvl.Exporter.cs deleted file mode 100644 index 3d8861405..000000000 --- a/ClassicalSharp/Map/Formats/MapLvl.Exporter.cs +++ /dev/null @@ -1,69 +0,0 @@ -// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT -using System; -using System.IO; -using System.IO.Compression; -using ClassicalSharp.Entities; - -namespace ClassicalSharp.Map { - - /// Exports a world to a LVL map file (MCLawl server map) - public sealed class MapLvlExporter : IMapFormatExporter { - - const int Version = 1874; - const byte customTile = 163; - - public void Save( Stream stream, Game game ) { - World map = game.World; - LocalPlayer p = game.LocalPlayer; - - using( DeflateStream gs = new DeflateStream( stream, CompressionMode.Compress ) ) { - BinaryWriter w = new BinaryWriter( gs ); - - w.Write( (ushort)Version ); - w.Write( (ushort)map.Width ); - w.Write( (ushort)map.Length ); - w.Write( (ushort)map.Height ); - - w.Write( (ushort)p.Spawn.X ); - w.Write( (ushort)p.Spawn.Z ); - w.Write( (ushort)p.Spawn.Y ); - w.Write( Utils.DegreesToPacked( p.SpawnYaw ) ); - w.Write( Utils.DegreesToPacked( p.SpawnPitch ) ); - - w.Write( (ushort)0 ); // pervisit and perbuild perms - WriteBlocks( map.mapData, w ); - - w.Write( (byte)0xBD ); - WriteCustomBlocks( map, w ); - } - } - - void WriteBlocks( byte[] blocks, BinaryWriter w ) { - const int bufferSize = 64 * 1024; - byte[] buffer = new byte[bufferSize]; - int bIndex = 0; - - for( int i = 0; i < blocks.Length; i++ ) { - byte block = blocks[i]; - buffer[bIndex] = block >= BlockInfo.CpeBlocksCount ? customTile : block; - - bIndex++; - if( bIndex == bufferSize ) { - w.Write( buffer, 0, bufferSize ); bIndex = 0; - } - } - if( bIndex > 0 ) w.Write( buffer, 0, bIndex ); - } - - void WriteCustomBlocks( World map, BinaryWriter w ) { - byte[] chunk = new byte[16 * 16 * 16]; - - for( int y = 0; y < map.Height; y += 16 ) - for( int z = 0; z < map.Length; z += 16 ) - for( int x = 0; x < map.Width; x += 16 ) - { - w.Write( (byte)0 ); - } - } - } -} \ No newline at end of file diff --git a/ClassicalSharp/Map/Formats/MapSchematic.Exporter.cs b/ClassicalSharp/Map/Formats/MapSchematic.Exporter.cs new file mode 100644 index 000000000..e4ad70297 --- /dev/null +++ b/ClassicalSharp/Map/Formats/MapSchematic.Exporter.cs @@ -0,0 +1,77 @@ +// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT +using System; +using System.IO; +using System.IO.Compression; + +namespace ClassicalSharp.Map { + + public sealed class MapSchematicExporter : IMapFormatExporter { + + public void Save( Stream stream, Game game ) { + using( GZipStream wrapper = new GZipStream( stream, CompressionMode.Compress ) ) { + BinaryWriter writer = new BinaryWriter( wrapper ); + NbtFile nbt = new NbtFile( writer ); + World map = game.World; + + nbt.Write( NbtTagType.Compound ); nbt.Write( "Schematic" ); + + nbt.Write( NbtTagType.String ); + nbt.Write( "Materials" ); nbt.Write( "Classic" ); + + nbt.Write( NbtTagType.Int16 ); + nbt.Write( "Width" ); nbt.WriteInt16( (short)map.Width ); + + nbt.Write( NbtTagType.Int16 ); + nbt.Write( "Height" ); nbt.WriteInt16( (short)map.Height ); + + nbt.Write( NbtTagType.Int16 ); + nbt.Write( "Length" ); nbt.WriteInt16( (short)map.Length ); + + WriteBlocks( nbt, map.mapData ); + + WriteBlockData( nbt, map.mapData ); + + nbt.Write( NbtTagType.List ); + nbt.Write( "Entities" ); + nbt.Write( NbtTagType.Compound ); nbt.WriteInt32( 0 ); + + nbt.Write( NbtTagType.List ); + nbt.Write( "TileEntities" ); + nbt.Write( NbtTagType.Compound ); nbt.WriteInt32( 0 ); + + nbt.Write( NbtTagType.End ); + } + } + + const int chunkSize = 64 * 1024; + void WriteBlocks( NbtFile nbt, byte[] blocks ) { + byte[] chunk = new byte[chunkSize]; + nbt.Write( NbtTagType.Int8Array ); + nbt.Write( "Blocks" ); + nbt.WriteInt32( blocks.Length ); + + for( int i = 0; i < blocks.Length; i += chunkSize ) { + int count = Math.Min( chunkSize, blocks.Length - i ); + for( int j = 0; j < count; j++ ) { + byte block = blocks[i + j]; + //if( block > BlockInfo.CpeBlocksCount ) block = 0; + chunk[j] = block; + } + nbt.WriteBytes( chunk, count ); + } + } + + void WriteBlockData( NbtFile nbt, byte[] blocks ) { + byte[] chunk = new byte[chunkSize]; + nbt.Write( NbtTagType.Int8Array ); + nbt.Write( "Data" ); + nbt.WriteInt32( blocks.Length ); + + for( int i = 0; i < blocks.Length; i += chunkSize ) { + // All 0 so we can skip this. + int count = Math.Min( chunkSize, blocks.Length - i ); + nbt.WriteBytes( chunk, count ); + } + } + } +} \ No newline at end of file diff --git a/ClassicalSharp/Map/Formats/NbtFile.cs b/ClassicalSharp/Map/Formats/NbtFile.cs index 921c5799a..31f0ec604 100644 --- a/ClassicalSharp/Map/Formats/NbtFile.cs +++ b/ClassicalSharp/Map/Formats/NbtFile.cs @@ -55,6 +55,8 @@ namespace ClassicalSharp.Map { public void WriteBytes( byte[] v ) { writer.Write( v ); } + public void WriteBytes( byte[] v, int count ) { writer.Write( v, 0, count ); } + public void Write( string value ) { ushort len = (ushort)value.Length; byte[] data = Encoding.UTF8.GetBytes( value ); From 36e727beaebea9d9b3c0a34a3b3ce41a0fa3ca55 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sun, 8 May 2016 21:00:29 +1000 Subject: [PATCH 12/19] Fix texture pack not changing in singleplayer, tidy up save level menu. --- ClassicalSharp/2D/Screens/Menu/SaveLevelScreen.cs | 6 ++++-- ClassicalSharp/Map/Formats/MapCw.Importer.cs | 8 ++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/ClassicalSharp/2D/Screens/Menu/SaveLevelScreen.cs b/ClassicalSharp/2D/Screens/Menu/SaveLevelScreen.cs index 1ae22879a..8bd31ac18 100644 --- a/ClassicalSharp/2D/Screens/Menu/SaveLevelScreen.cs +++ b/ClassicalSharp/2D/Screens/Menu/SaveLevelScreen.cs @@ -26,7 +26,7 @@ namespace ClassicalSharp.Gui { api.Texturing = false; float cX = game.Width / 2, cY = game.Height / 2; - api.Draw2DQuad( cX - 300, cY + 90, 600, 2, grey ); + api.Draw2DQuad( cX - 250, cY + 90, 500, 2, grey ); if( textPath == null ) return; SaveMap( textPath ); textPath = null; @@ -62,8 +62,10 @@ namespace ClassicalSharp.Gui { widgets = new Widget[] { ButtonWidget.Create( game, 0, 20, 301, 40, "Save", Anchor.Centre, Anchor.Centre, titleFont, SaveClassic ), - ButtonWidget.Create( game, 0, 120, 201, 40, "Save schematic", Anchor.Centre, + ButtonWidget.Create( game, -150, 120, 201, 40, "Save schematic", Anchor.Centre, Anchor.Centre, titleFont, SaveSchematic ), + ChatTextWidget.Create( game, 120, 110, "&eCan be imported into MCedit", Anchor.Centre, + Anchor.Centre, regularFont ), null, MakeBack( false, titleFont, (g, w) => g.SetNewScreen( new PauseScreen( g ) ) ), diff --git a/ClassicalSharp/Map/Formats/MapCw.Importer.cs b/ClassicalSharp/Map/Formats/MapCw.Importer.cs index 675313b74..50872f31b 100644 --- a/ClassicalSharp/Map/Formats/MapCw.Importer.cs +++ b/ClassicalSharp/Map/Formats/MapCw.Importer.cs @@ -75,9 +75,13 @@ namespace ClassicalSharp.Map { map.SetShadowlight( GetColour( "Ambient", World.DefaultShadowlight ) ); } if( CheckKey( "EnvMapAppearance", 1, metadata ) ) { + string url = null; if( curCpeExt.ContainsKey( "TextureURL" ) ) - map.TextureUrl = (string)curCpeExt["TextureURL"].Value; - if( map.TextureUrl.Length == 0 ) map.TextureUrl = null; + url = (string)curCpeExt["TextureURL"].Value; + if( url.Length == 0 ) url = null; + if( game.AllowServerTextures && url != null ) + game.Network.RetrieveTexturePack( url ); + byte sidesBlock = (byte)curCpeExt["SideBlock"].Value; byte edgeBlock = (byte)curCpeExt["EdgeBlock"].Value; map.SetSidesBlock( (Block)sidesBlock ); From d837b31f84efbb1dbfbbe8b2f6b587c3d37bf4f6 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sun, 8 May 2016 22:06:26 +1000 Subject: [PATCH 13/19] Also backspace in input should backspace colour code before the character. --- ClassicalSharp/2D/Screens/ChatScreen.cs | 6 +- .../Widgets/Chat/TextInputWidget.Handlers.cs | 107 ++++++++++-------- .../2D/Widgets/Chat/TextInputWidget.cs | 40 +++---- ClassicalSharp/ClassicalSharp.csproj | 2 +- ClassicalSharp/Entities/EntityList.cs | 2 +- .../Map/Formats/MapSchematic.Exporter.cs | 16 +-- ClassicalSharp/Map/Formats/NbtFile.cs | 2 +- .../TexturePack/TexturePackExtractor.cs | 4 +- 8 files changed, 93 insertions(+), 86 deletions(-) diff --git a/ClassicalSharp/2D/Screens/ChatScreen.cs b/ClassicalSharp/2D/Screens/ChatScreen.cs index a06df1cb3..3a8abe7a2 100644 --- a/ClassicalSharp/2D/Screens/ChatScreen.cs +++ b/ClassicalSharp/2D/Screens/ChatScreen.cs @@ -246,7 +246,7 @@ namespace ClassicalSharp.Gui { public override void Dispose() { if( HandlesAllInput ) { - game.chatInInputBuffer = textInput.chatInputText.ToString(); + game.chatInInputBuffer = textInput.buffer.ToString(); game.CursorVisible = false; } else { game.chatInInputBuffer = null; @@ -321,8 +321,8 @@ namespace ClassicalSharp.Gui { HandlesAllInput = true; game.Keyboard.KeyRepeat = true; - textInput.chatInputText.Clear(); - textInput.chatInputText.Append( 0, initialText ); + textInput.buffer.Clear(); + textInput.buffer.Append( 0, initialText ); textInput.Init(); } diff --git a/ClassicalSharp/2D/Widgets/Chat/TextInputWidget.Handlers.cs b/ClassicalSharp/2D/Widgets/Chat/TextInputWidget.Handlers.cs index 06f7d5618..0b4d03581 100644 --- a/ClassicalSharp/2D/Widgets/Chat/TextInputWidget.Handlers.cs +++ b/ClassicalSharp/2D/Widgets/Chat/TextInputWidget.Handlers.cs @@ -44,9 +44,9 @@ namespace ClassicalSharp.Gui { } void TabKey() { - int pos = caretPos == -1 ? chatInputText.Length - 1 : caretPos; + int pos = caretPos == -1 ? buffer.Length - 1 : caretPos; int start = pos; - char[] value = chatInputText.value; + char[] value = buffer.value; while( start >= 0 && IsNameChar( value[start] ) ) start--; @@ -74,63 +74,76 @@ namespace ClassicalSharp.Gui { if( caretPos == -1 ) pos++; int len = pos - start; for( int i = 0; i < len; i++ ) - chatInputText.DeleteAt( start ); + buffer.DeleteAt( start ); if( caretPos != -1 ) caretPos -= len; AppendText( matches[0] ); } else if( matches.Count > 1 ) { - StringBuffer buffer = new StringBuffer( 64 ); + StringBuffer sb = new StringBuffer( 64 ); int index = 0; - buffer.Append( ref index, "&e" ); - buffer.AppendNum( ref index, matches.Count ); - buffer.Append( ref index, " matching names: " ); + sb.Append( ref index, "&e" ); + sb.AppendNum( ref index, matches.Count ); + sb.Append( ref index, " matching names: " ); foreach( string match in matches ) { - if( (match.Length + 1 + buffer.Length) > LineLength ) break; - buffer.Append( ref index, match ); - buffer.Append( ref index, ' ' ); + if( (match.Length + 1 + sb.Length) > LineLength ) break; + sb.Append( ref index, match ); + sb.Append( ref index, ' ' ); } - game.Chat.Add( buffer.ToString(), MessageType.ClientStatus5 ); + game.Chat.Add( sb.ToString(), MessageType.ClientStatus5 ); } } bool IsNameChar( char c ) { - return c == '_' || c == '.' || (c >= '0' && c <= '9') + return c == '_' || c == '.' || (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); } void BackspaceKey( bool controlDown ) { if( controlDown ) { if( caretPos == -1 ) - caretPos = chatInputText.Length - 1; - int len = chatInputText.GetBackLength( caretPos ); + caretPos = buffer.Length - 1; + int len = buffer.GetBackLength( caretPos ); caretPos -= len; if( caretPos < 0 ) caretPos = 0; if( caretPos != 0 ) caretPos++; // Don't remove space. for( int i = 0; i <= len; i++ ) - chatInputText.DeleteAt( caretPos ); + buffer.DeleteAt( caretPos ); Dispose(); Init(); - return; - } - - if( !chatInputText.Empty && caretPos != 0 ) { - if( caretPos == -1 ) { - chatInputText.DeleteAt( chatInputText.Length - 1 ); - } else { - caretPos--; - chatInputText.DeleteAt( caretPos ); - } + } else if( !buffer.Empty && caretPos != 0 ) { + DeleteChar(); + BackspaceColourCode(); Dispose(); Init(); } } + void BackspaceColourCode() { + // If text is XYZ%eH, backspaces to XYZ. + int index = caretPos == -1 ? buffer.Length - 1 : caretPos; + if( index <= 0 ) return; + + if( index == 0 || buffer.value[index - 1] != '%' + || !game.Drawer2D.ValidColour( buffer.value[index] ) ) + return; + DeleteChar(); DeleteChar(); + } + + void DeleteChar() { + if( caretPos == -1 ) { + buffer.DeleteAt( buffer.Length - 1 ); + } else { + caretPos--; + buffer.DeleteAt( caretPos ); + } + } + void DeleteKey() { - if( !chatInputText.Empty && caretPos != -1 ) { - chatInputText.DeleteAt( caretPos ); - if( caretPos >= chatInputText.Length ) caretPos = -1; + if( !buffer.Empty && caretPos != -1 ) { + buffer.DeleteAt( caretPos ); + if( caretPos >= buffer.Length ) caretPos = -1; Dispose(); Init(); } @@ -139,14 +152,14 @@ namespace ClassicalSharp.Gui { void LeftKey( bool controlDown ) { if( controlDown ) { if( caretPos == -1 ) - caretPos = chatInputText.Length - 1; - caretPos -= chatInputText.GetBackLength( caretPos ); + caretPos = buffer.Length - 1; + caretPos -= buffer.GetBackLength( caretPos ); CalculateCaretData(); return; } - if( !chatInputText.Empty ) { - if( caretPos == -1 ) caretPos = chatInputText.Length; + if( !buffer.Empty ) { + if( caretPos == -1 ) caretPos = buffer.Length; caretPos--; if( caretPos < 0 ) caretPos = 0; CalculateCaretData(); @@ -155,15 +168,15 @@ namespace ClassicalSharp.Gui { void RightKey( bool controlDown ) { if( controlDown ) { - caretPos += chatInputText.GetForwardLength( caretPos ); - if( caretPos >= chatInputText.Length ) caretPos = -1; + caretPos += buffer.GetForwardLength( caretPos ); + if( caretPos >= buffer.Length ) caretPos = -1; CalculateCaretData(); return; } - if( !chatInputText.Empty && caretPos != -1 ) { + if( !buffer.Empty && caretPos != -1 ) { caretPos++; - if( caretPos >= chatInputText.Length ) caretPos = -1; + if( caretPos >= buffer.Length ) caretPos = -1; CalculateCaretData(); } } @@ -171,7 +184,7 @@ namespace ClassicalSharp.Gui { string originalText; void UpKey( bool controlDown ) { if( controlDown ) { - int pos = caretPos == -1 ? chatInputText.Length : caretPos; + int pos = caretPos == -1 ? buffer.Length : caretPos; if( pos < LineLength ) return; caretPos = pos - LineLength; @@ -180,12 +193,12 @@ namespace ClassicalSharp.Gui { } if( typingLogPos == game.Chat.InputLog.Count ) - originalText = chatInputText.ToString(); + originalText = buffer.ToString(); if( game.Chat.InputLog.Count > 0 ) { typingLogPos--; if( typingLogPos < 0 ) typingLogPos = 0; - chatInputText.Clear(); - chatInputText.Append( 0, game.Chat.InputLog[typingLogPos] ); + buffer.Clear(); + buffer.Append( 0, game.Chat.InputLog[typingLogPos] ); caretPos = -1; Dispose(); Init(); @@ -202,13 +215,13 @@ namespace ClassicalSharp.Gui { if( game.Chat.InputLog.Count > 0 ) { typingLogPos++; - chatInputText.Clear(); + buffer.Clear(); if( typingLogPos >= game.Chat.InputLog.Count ) { typingLogPos = game.Chat.InputLog.Count; if( originalText != null ) - chatInputText.Append( 0, originalText ); + buffer.Append( 0, originalText ); } else { - chatInputText.Append( 0, game.Chat.InputLog[typingLogPos] ); + buffer.Append( 0, game.Chat.InputLog[typingLogPos] ); } caretPos = -1; Dispose(); @@ -217,7 +230,7 @@ namespace ClassicalSharp.Gui { } void HomeKey() { - if( chatInputText.Empty ) return; + if( buffer.Empty ) return; caretPos = 0; CalculateCaretData(); } @@ -228,7 +241,7 @@ namespace ClassicalSharp.Gui { } bool OtherKey( Key key ) { - if( key == Key.V && chatInputText.Length < TotalChars ) { + if( key == Key.V && buffer.Length < TotalChars ) { string text = null; try { text = game.window.ClipboardText; @@ -252,9 +265,9 @@ namespace ClassicalSharp.Gui { AppendText( text ); return true; } else if( key == Key.C ) { - if( chatInputText.Empty ) return true; + if( buffer.Empty ) return true; try { - game.window.ClipboardText = chatInputText.ToString(); + game.window.ClipboardText = buffer.ToString(); } catch( Exception ex ) { ErrorHandler.LogError( "Copy to clipboard", ex ); const string warning = "&cError while trying to copy to clipboard."; diff --git a/ClassicalSharp/2D/Widgets/Chat/TextInputWidget.cs b/ClassicalSharp/2D/Widgets/Chat/TextInputWidget.cs index 6ba20a65d..68bc2439b 100644 --- a/ClassicalSharp/2D/Widgets/Chat/TextInputWidget.cs +++ b/ClassicalSharp/2D/Widgets/Chat/TextInputWidget.cs @@ -12,7 +12,7 @@ namespace ClassicalSharp.Gui { HorizontalAnchor = Anchor.LeftOrTop; VerticalAnchor = Anchor.BottomOrRight; typingLogPos = game.Chat.InputLog.Count; // Index of newest entry + 1. - chatInputText = new WrappableStringBuffer( 64 * lines ); + buffer = new WrappableStringBuffer( 64 * lines ); DrawTextArgs args = new DrawTextArgs( "_", boldFont, true ); caretTex = game.Drawer2D.MakeChatTextTexture( ref args, 0, 0 ); @@ -35,7 +35,7 @@ namespace ClassicalSharp.Gui { int caretPos = -1, typingLogPos = 0; public int YOffset; int defaultCaretWidth, defaultWidth, defaultHeight; - internal WrappableStringBuffer chatInputText; + internal WrappableStringBuffer buffer; readonly Font font; FastColour caretCol; @@ -72,7 +72,7 @@ namespace ClassicalSharp.Gui { public override void Init() { X = 5; - chatInputText.WordWrap( game.Drawer2D, ref parts, ref partLens, + buffer.WordWrap( game.Drawer2D, ref parts, ref partLens, LineLength, TotalChars ); for( int y = 0; y < sizes.Length; y++ ) @@ -89,10 +89,10 @@ namespace ClassicalSharp.Gui { if( sizes[0].Height == 0 ) sizes[0].Height = defaultHeight; bool supports = game.Network.ServerSupportsPartialMessages; - if( chatInputText.Length > LineLength && !shownWarning && !supports ) { + if( buffer.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 <= LineLength && shownWarning ) { + } else if( buffer.Length <= LineLength && shownWarning ) { game.Chat.Add( null, MessageType.ClientStatus6 ); shownWarning = false; } @@ -104,8 +104,8 @@ namespace ClassicalSharp.Gui { } void CalculateCaretData() { - if( caretPos >= chatInputText.Length ) caretPos = -1; - chatInputText.MakeCoords( caretPos, partLens, out indexX, out indexY ); + if( caretPos >= buffer.Length ) caretPos = -1; + buffer.MakeCoords( caretPos, partLens, out indexX, out indexY ); DrawTextArgs args = new DrawTextArgs( null, font, true ); if( indexX == LineLength ) { @@ -204,7 +204,7 @@ namespace ClassicalSharp.Gui { public void SendTextInBufferAndReset() { SendInBuffer(); typingLogPos = game.Chat.InputLog.Count; // Index of newest entry + 1. - chatInputText.Clear(); + buffer.Clear(); caretPos = -1; Dispose(); Height = defaultHeight; @@ -216,8 +216,8 @@ namespace ClassicalSharp.Gui { } void SendInBuffer() { - if( chatInputText.Empty ) return; - string allText = chatInputText.GetString(); + if( buffer.Empty ) return; + string allText = buffer.GetString(); game.Chat.InputLog.Add( allText ); if( game.Network.ServerSupportsPartialMessages ) @@ -257,38 +257,38 @@ namespace ClassicalSharp.Gui { } public void Clear() { - chatInputText.Clear(); + buffer.Clear(); for( int i = 0; i < parts.Length; i++ ) { parts[i] = null; } } public void AppendText( string text ) { - if( chatInputText.Length + text.Length > TotalChars ) { - text = text.Substring( 0, TotalChars - chatInputText.Length ); + if( buffer.Length + text.Length > TotalChars ) { + text = text.Substring( 0, TotalChars - buffer.Length ); } if( text == "" ) return; if( caretPos == -1 ) { - chatInputText.InsertAt( chatInputText.Length, text ); + buffer.InsertAt( buffer.Length, text ); } else { - chatInputText.InsertAt( caretPos, text ); + buffer.InsertAt( caretPos, text ); caretPos += text.Length; - if( caretPos >= chatInputText.Length ) caretPos = -1; + if( caretPos >= buffer.Length ) caretPos = -1; } Dispose(); Init(); } public void AppendChar( char c ) { - if( chatInputText.Length == TotalChars ) return; + if( buffer.Length == TotalChars ) return; if( caretPos == -1 ) { - chatInputText.InsertAt( chatInputText.Length, c ); + buffer.InsertAt( buffer.Length, c ); } else { - chatInputText.InsertAt( caretPos, c ); + buffer.InsertAt( caretPos, c ); caretPos++; - if( caretPos >= chatInputText.Length ) caretPos = -1; + if( caretPos >= buffer.Length ) caretPos = -1; } Dispose(); Init(); diff --git a/ClassicalSharp/ClassicalSharp.csproj b/ClassicalSharp/ClassicalSharp.csproj index f4b59650a..12ed39020 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 diff --git a/ClassicalSharp/Entities/EntityList.cs b/ClassicalSharp/Entities/EntityList.cs index b3a74d87b..f76d06bb1 100644 --- a/ClassicalSharp/Entities/EntityList.cs +++ b/ClassicalSharp/Entities/EntityList.cs @@ -98,7 +98,7 @@ namespace ClassicalSharp.Entities { } void TextureChanged( object sender, TextureEventArgs e ) { - if( e.Texture != "char" ) return; + if( e.Texture != "char.png" ) return; for( int i = 0; i < Players.Length; i++ ) { if( Players[i] == null || Players[i].TextureId != -1 ) continue; Players[i].SkinType = game.DefaultPlayerSkinType; diff --git a/ClassicalSharp/Map/Formats/MapSchematic.Exporter.cs b/ClassicalSharp/Map/Formats/MapSchematic.Exporter.cs index e4ad70297..10d8c38ae 100644 --- a/ClassicalSharp/Map/Formats/MapSchematic.Exporter.cs +++ b/ClassicalSharp/Map/Formats/MapSchematic.Exporter.cs @@ -43,25 +43,21 @@ namespace ClassicalSharp.Map { } } - const int chunkSize = 64 * 1024; + void WriteBlocks( NbtFile nbt, byte[] blocks ) { - byte[] chunk = new byte[chunkSize]; + const int chunkSize = 64 * 1024 * 32; nbt.Write( NbtTagType.Int8Array ); nbt.Write( "Blocks" ); nbt.WriteInt32( blocks.Length ); for( int i = 0; i < blocks.Length; i += chunkSize ) { int count = Math.Min( chunkSize, blocks.Length - i ); - for( int j = 0; j < count; j++ ) { - byte block = blocks[i + j]; - //if( block > BlockInfo.CpeBlocksCount ) block = 0; - chunk[j] = block; - } - nbt.WriteBytes( chunk, count ); + nbt.WriteBytes( blocks, i, count ); } } - void WriteBlockData( NbtFile nbt, byte[] blocks ) { + void WriteBlockData( NbtFile nbt, byte[] blocks ) { + const int chunkSize = 64 * 1024; byte[] chunk = new byte[chunkSize]; nbt.Write( NbtTagType.Int8Array ); nbt.Write( "Data" ); @@ -70,7 +66,7 @@ namespace ClassicalSharp.Map { for( int i = 0; i < blocks.Length; i += chunkSize ) { // All 0 so we can skip this. int count = Math.Min( chunkSize, blocks.Length - i ); - nbt.WriteBytes( chunk, count ); + nbt.WriteBytes( chunk, 0, count ); } } } diff --git a/ClassicalSharp/Map/Formats/NbtFile.cs b/ClassicalSharp/Map/Formats/NbtFile.cs index 31f0ec604..9157a594d 100644 --- a/ClassicalSharp/Map/Formats/NbtFile.cs +++ b/ClassicalSharp/Map/Formats/NbtFile.cs @@ -55,7 +55,7 @@ namespace ClassicalSharp.Map { public void WriteBytes( byte[] v ) { writer.Write( v ); } - public void WriteBytes( byte[] v, int count ) { writer.Write( v, 0, count ); } + public void WriteBytes( byte[] v, int index, int count ) { writer.Write( v, index, count ); } public void Write( string value ) { ushort len = (ushort)value.Length; diff --git a/ClassicalSharp/TexturePack/TexturePackExtractor.cs b/ClassicalSharp/TexturePack/TexturePackExtractor.cs index 5c7ababfa..5739233ec 100644 --- a/ClassicalSharp/TexturePack/TexturePackExtractor.cs +++ b/ClassicalSharp/TexturePack/TexturePackExtractor.cs @@ -94,9 +94,7 @@ namespace ClassicalSharp.TexturePack { SetFontBitmap( game, stream ); break; } - if( !name.EndsWith( ".png" ) ) return; - string tex = name.Substring( 0, name.Length - 4 ); - game.Events.RaiseTextureChanged( tex ); + game.Events.RaiseTextureChanged( name ); } void SetFontBitmap( Game game, Stream stream ) { From 723585661a14ad8364b9964ab20049363acc19e3 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sun, 8 May 2016 23:05:56 +1000 Subject: [PATCH 14/19] Make Animations a game component, make TexturePackExtractor less hardcoded. --- .../2D/Screens/Menu/SaveLevelScreen.cs | 2 +- .../PlayerList/ClassicPlayerListWidget.cs | 8 ++--- .../PlayerList/NormalPlayerListWidget.cs | 8 ++--- ClassicalSharp/ClassicalSharp.csproj | 2 +- ClassicalSharp/Entities/EntityList.cs | 2 +- ClassicalSharp/Events/EntityEvents.cs | 8 ++--- ClassicalSharp/Events/Events.cs | 12 ++++--- ClassicalSharp/Game/Game.cs | 3 +- ClassicalSharp/Network/INetworkProcessor.cs | 8 ++--- .../Network/NetworkProcessor.Original.cs | 6 ++-- ClassicalSharp/TexturePack/Animations.cs | 34 ++++++++++++++++--- .../TexturePack/TexturePackExtractor.cs | 19 ++++------- 12 files changed, 66 insertions(+), 46 deletions(-) diff --git a/ClassicalSharp/2D/Screens/Menu/SaveLevelScreen.cs b/ClassicalSharp/2D/Screens/Menu/SaveLevelScreen.cs index 8bd31ac18..858cecd2c 100644 --- a/ClassicalSharp/2D/Screens/Menu/SaveLevelScreen.cs +++ b/ClassicalSharp/2D/Screens/Menu/SaveLevelScreen.cs @@ -64,7 +64,7 @@ namespace ClassicalSharp.Gui { Anchor.Centre, titleFont, SaveClassic ), ButtonWidget.Create( game, -150, 120, 201, 40, "Save schematic", Anchor.Centre, Anchor.Centre, titleFont, SaveSchematic ), - ChatTextWidget.Create( game, 120, 110, "&eCan be imported into MCedit", Anchor.Centre, + ChatTextWidget.Create( game, 110, 120, "&eCan be imported into MCedit", Anchor.Centre, Anchor.Centre, regularFont ), null, MakeBack( false, titleFont, diff --git a/ClassicalSharp/2D/Widgets/PlayerList/ClassicPlayerListWidget.cs b/ClassicalSharp/2D/Widgets/PlayerList/ClassicPlayerListWidget.cs index 908d17313..d2fcad1fa 100644 --- a/ClassicalSharp/2D/Widgets/PlayerList/ClassicPlayerListWidget.cs +++ b/ClassicalSharp/2D/Widgets/PlayerList/ClassicPlayerListWidget.cs @@ -89,8 +89,8 @@ namespace ClassicalSharp.Gui { base.Init(); if( !extList ) { - game.EntityEvents.EntityAdded += PlayerSpawned; - game.EntityEvents.EntityRemoved += PlayerDespawned; + game.EntityEvents.Added += PlayerSpawned; + game.EntityEvents.Removed += PlayerDespawned; } else { game.EntityEvents.CpeListInfoAdded += PlayerListInfoAdded; game.EntityEvents.CpeListInfoRemoved += PlayerDespawned; @@ -102,8 +102,8 @@ namespace ClassicalSharp.Gui { base.Dispose(); overview.Dispose(); if( !extList ) { - game.EntityEvents.EntityAdded -= PlayerSpawned; - game.EntityEvents.EntityRemoved -= PlayerDespawned; + game.EntityEvents.Added -= PlayerSpawned; + game.EntityEvents.Removed -= PlayerDespawned; } else { game.EntityEvents.CpeListInfoAdded -= PlayerListInfoAdded; game.EntityEvents.CpeListInfoChanged -= PlayerListInfoChanged; diff --git a/ClassicalSharp/2D/Widgets/PlayerList/NormalPlayerListWidget.cs b/ClassicalSharp/2D/Widgets/PlayerList/NormalPlayerListWidget.cs index 98f64fa0d..63eec8186 100644 --- a/ClassicalSharp/2D/Widgets/PlayerList/NormalPlayerListWidget.cs +++ b/ClassicalSharp/2D/Widgets/PlayerList/NormalPlayerListWidget.cs @@ -27,14 +27,14 @@ namespace ClassicalSharp.Gui { public override void Init() { base.Init(); - game.EntityEvents.EntityAdded += PlayerSpawned; - game.EntityEvents.EntityRemoved += PlayerDespawned; + game.EntityEvents.Added += PlayerSpawned; + game.EntityEvents.Removed += PlayerDespawned; } public override void Dispose() { base.Dispose(); - game.EntityEvents.EntityAdded -= PlayerSpawned; - game.EntityEvents.EntityRemoved -= PlayerDespawned; + game.EntityEvents.Added -= PlayerSpawned; + game.EntityEvents.Removed -= PlayerDespawned; } void PlayerSpawned( object sender, IdEventArgs e ) { diff --git a/ClassicalSharp/ClassicalSharp.csproj b/ClassicalSharp/ClassicalSharp.csproj index 12ed39020..f4b59650a 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/Entities/EntityList.cs b/ClassicalSharp/Entities/EntityList.cs index f76d06bb1..7d0ac0bc9 100644 --- a/ClassicalSharp/Entities/EntityList.cs +++ b/ClassicalSharp/Entities/EntityList.cs @@ -98,7 +98,7 @@ namespace ClassicalSharp.Entities { } void TextureChanged( object sender, TextureEventArgs e ) { - if( e.Texture != "char.png" ) return; + if( e.Name != "char.png" ) return; for( int i = 0; i < Players.Length; i++ ) { if( Players[i] == null || Players[i].TextureId != -1 ) continue; Players[i].SkinType = game.DefaultPlayerSkinType; diff --git a/ClassicalSharp/Events/EntityEvents.cs b/ClassicalSharp/Events/EntityEvents.cs index d8b81cbf3..5a5b6d920 100644 --- a/ClassicalSharp/Events/EntityEvents.cs +++ b/ClassicalSharp/Events/EntityEvents.cs @@ -10,12 +10,12 @@ namespace ClassicalSharp.Events { IdEventArgs idArgs = new IdEventArgs(); /// Raised when an entity is spawned in the current world. - public event EventHandler EntityAdded; - internal void RaiseEntityAdded( byte id ) { idArgs.Id = id; Raise( EntityAdded, idArgs ); } + public event EventHandler Added; + internal void RaiseAdded( byte id ) { idArgs.Id = id; Raise( Added, idArgs ); } /// Raised when an entity is despawned from the current world. - public event EventHandler EntityRemoved; - internal void RaiseEntityRemoved( byte id ) { idArgs.Id = id; Raise( EntityRemoved, idArgs ); } + public event EventHandler Removed; + internal void RaiseRemoved( byte id ) { idArgs.Id = id; Raise( Removed, idArgs ); } /// Raised when a new CPE player list entry is created. public event EventHandler CpeListInfoAdded; diff --git a/ClassicalSharp/Events/Events.cs b/ClassicalSharp/Events/Events.cs index f5fa40fd4..9a1d56598 100644 --- a/ClassicalSharp/Events/Events.cs +++ b/ClassicalSharp/Events/Events.cs @@ -11,8 +11,8 @@ namespace ClassicalSharp.Events { /// Raised when a texture is changed. (such as "terrain", "rain") public event EventHandler TextureChanged; - internal void RaiseTextureChanged( string texture ) { - texArgs.Texture = texture; Raise( TextureChanged, texArgs ); } + internal void RaiseTextureChanged( string name, byte[] data ) { + texArgs.Name = name; texArgs.Data = data; Raise( TextureChanged, texArgs ); } /// Raised when the user changed their view/fog distance. public event EventHandler ViewDistanceChanged; @@ -78,8 +78,10 @@ namespace ClassicalSharp.Events { public sealed class TextureEventArgs : EventArgs { - /// Location of the texture within a texture pack. (e.g. "snow", "default", "char") - /// See TexturePackExtractor for a list of supported textures. - public string Texture; + /// Location of the file within a texture pack, without a directory. (e.g. "snow.png") + public string Name; + + /// Raw data of the file. + public byte[] Data; } } diff --git a/ClassicalSharp/Game/Game.cs b/ClassicalSharp/Game/Game.cs index e24381473..5d1dfcd0d 100644 --- a/ClassicalSharp/Game/Game.cs +++ b/ClassicalSharp/Game/Game.cs @@ -84,7 +84,7 @@ namespace ClassicalSharp { TerrainAtlas1D = new TerrainAtlas1D( Graphics ); TerrainAtlas = new TerrainAtlas2D( Graphics, Drawer2D ); - Animations = new Animations( this ); + Animations = AddComponent( new Animations() ); Inventory = AddComponent( new Inventory() ); BlockInfo.SetDefaultBlockPermissions( Inventory.CanPlace, Inventory.CanDelete ); @@ -536,7 +536,6 @@ namespace ClassicalSharp { Graphics.DeleteIb( defaultIb ); Graphics.Dispose(); Drawer2D.DisposeInstance(); - Animations.Dispose(); Graphics.DeleteTexture( ref CloudsTexId ); Graphics.DeleteTexture( ref RainTexId ); Graphics.DeleteTexture( ref SnowTexId ); diff --git a/ClassicalSharp/Network/INetworkProcessor.cs b/ClassicalSharp/Network/INetworkProcessor.cs index a37907d1a..08931614f 100644 --- a/ClassicalSharp/Network/INetworkProcessor.cs +++ b/ClassicalSharp/Network/INetworkProcessor.cs @@ -128,7 +128,7 @@ namespace ClassicalSharp { if( item.Data != null ) { Bitmap bmp = (Bitmap)item.Data; game.World.TextureUrl = item.Url; - game.Animations.Dispose(); + game.Animations.Clear(); if( !FastBitmap.CheckFormat( bmp.PixelFormat ) ) { Utils.LogDebug( "Converting terrain atlas to 32bpp image" ); @@ -142,7 +142,7 @@ namespace ClassicalSharp { if( bmp == null ) {// Should never happen, but handle anyways. ExtractDefault(); } else if( item.Url != game.World.TextureUrl ) { - game.Animations.Dispose(); + game.Animations.Clear(); if( !game.ChangeTerrainAtlas( bmp ) ) { bmp.Dispose(); return; } } @@ -155,7 +155,7 @@ namespace ClassicalSharp { if( game.AsyncDownloader.TryGetItem( "texturePack", out item ) ) { if( item.Data != null ) { game.World.TextureUrl = item.Url; - game.Animations.Dispose(); + game.Animations.Clear(); TexturePackExtractor extractor = new TexturePackExtractor(); extractor.Extract( (byte[])item.Data, game ); @@ -166,7 +166,7 @@ namespace ClassicalSharp { if( data == null ) { // Should never happen, but handle anyways. ExtractDefault(); } else if( item.Url != game.World.TextureUrl ) { - game.Animations.Dispose(); + game.Animations.Clear(); TexturePackExtractor extractor = new TexturePackExtractor(); extractor.Extract( data, game ); } diff --git a/ClassicalSharp/Network/NetworkProcessor.Original.cs b/ClassicalSharp/Network/NetworkProcessor.Original.cs index 8863657cf..83e889c46 100644 --- a/ClassicalSharp/Network/NetworkProcessor.Original.cs +++ b/ClassicalSharp/Network/NetworkProcessor.Original.cs @@ -275,11 +275,11 @@ namespace ClassicalSharp.Net { if( entityId != 0xFF ) { Player oldPlayer = game.Players[entityId]; if( oldPlayer != null ) { - game.EntityEvents.RaiseEntityRemoved( entityId ); + game.EntityEvents.RaiseRemoved( entityId ); oldPlayer.Despawn(); } game.Players[entityId] = new NetPlayer( displayName, skinName, game, entityId ); - game.EntityEvents.RaiseEntityAdded( entityId ); + game.EntityEvents.RaiseAdded( entityId ); } else { // Server is only allowed to change our own name colours. if( Utils.StripColours( displayName ) != game.Username ) @@ -307,7 +307,7 @@ namespace ClassicalSharp.Net { if( player == null ) return; if( entityId != 0xFF ) { - game.EntityEvents.RaiseEntityRemoved( entityId ); + game.EntityEvents.RaiseRemoved( entityId ); player.Despawn(); game.Players[entityId] = null; } diff --git a/ClassicalSharp/TexturePack/Animations.cs b/ClassicalSharp/TexturePack/Animations.cs index b5acea3a0..91b5052a9 100644 --- a/ClassicalSharp/TexturePack/Animations.cs +++ b/ClassicalSharp/TexturePack/Animations.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Drawing; using System.IO; +using ClassicalSharp.Events; using ClassicalSharp.GraphicsAPI; #if ANDROID using Android.Graphics; @@ -11,7 +12,7 @@ using Android.Graphics; namespace ClassicalSharp.TexturePack { /// Contains and describes the various animations applied to the terrain atlas. - public class Animations { + public class Animations : IGameComponent { Game game; IGraphicsApi api; @@ -19,14 +20,34 @@ namespace ClassicalSharp.TexturePack { FastBitmap fastBmp; List animations = new List(); - public Animations( Game game ) { + public void Init( Game game ) { this.game = game; api = game.Graphics; + game.Events.TextureChanged += TextureChanged; + } + + public void Ready( Game game ) { } + public void Reset( Game game ) { } + public void OnNewMap( Game game ) { } + public void OnNewMapLoaded( Game game ) { } + + void TextureChanged( object sender, TextureEventArgs e ) { + if( e.Name == "animations.png" || e.Name == "animation.png" ) { + MemoryStream stream = new MemoryStream( e.Data ); + SetAtlas( Platform.ReadBmp( stream ) ); + } else if( e.Name == "animations.txt" || e.Name == "animation.txt" ) { + MemoryStream stream = new MemoryStream( e.Data ); + StreamReader reader = new StreamReader( stream ); + ReadAnimationsDescription( reader ); + } } /// Sets the atlas bitmap that animation frames are contained within. public void SetAtlas( Bitmap bmp ) { - Dispose(); + if( !FastBitmap.CheckFormat( bmp.PixelFormat ) ) + game.Drawer2D.ConvertTo32Bpp( ref bmp ); + + Clear(); this.bmp = bmp; fastBmp = new FastBitmap( bmp, true, true ); } @@ -124,12 +145,17 @@ namespace ClassicalSharp.TexturePack { /// Disposes the atlas bitmap that contains animation frames, and clears /// the list of defined animations. - public void Dispose() { + public void Clear() { animations.Clear(); if( bmp == null ) return; fastBmp.Dispose(); fastBmp = null; bmp.Dispose(); bmp = null; } + + public void Dispose() { + Clear(); + game.Events.TextureChanged -= TextureChanged; + } } } diff --git a/ClassicalSharp/TexturePack/TexturePackExtractor.cs b/ClassicalSharp/TexturePack/TexturePackExtractor.cs index 5739233ec..96f22f15e 100644 --- a/ClassicalSharp/TexturePack/TexturePackExtractor.cs +++ b/ClassicalSharp/TexturePack/TexturePackExtractor.cs @@ -26,7 +26,7 @@ namespace ClassicalSharp.TexturePack { void Extract( Stream stream, Game game ) { this.game = game; - game.Animations.Dispose(); + game.Animations.Clear(); ZipReader reader = new ZipReader(); reader.ShouldProcessZipEntry = (f) => true; @@ -79,22 +79,13 @@ namespace ClassicalSharp.TexturePack { UpdateTexture( ref game.GuiTexId, stream, false ); break; case "gui_classic.png": UpdateTexture( ref game.GuiClassicTexId, stream, false ); break; - case "animations.png": - case "animation.png": - game.Animations.SetAtlas( Platform.ReadBmp( stream ) ); break; - case "animations.txt": - case "animation.txt": - StreamReader reader = new StreamReader( stream ); - game.Animations.ReadAnimationsDescription( reader ); - break; case "particles.png": UpdateTexture( ref game.ParticleManager.ParticlesTexId, stream, false ); break; case "default.png": SetFontBitmap( game, stream ); break; - } - - game.Events.RaiseTextureChanged( name ); + } + game.Events.RaiseTextureChanged( name, data ); } void SetFontBitmap( Game game, Stream stream ) { @@ -105,7 +96,9 @@ namespace ClassicalSharp.TexturePack { game.Events.RaiseChatFontChanged(); } - void UpdateTexture( ref int texId, Stream stream, bool setSkinType ) { + /// Reads a bitmap from the stream (converting it to 32 bits per pixel if necessary), + /// and updates the native texture for it. + public void UpdateTexture( ref int texId, Stream stream, bool setSkinType ) { game.Graphics.DeleteTexture( ref texId ); using( Bitmap bmp = Platform.ReadBmp( stream ) ) { if( setSkinType ) From ec050aaefcded3c3738f0daca7af73d3d0869dd3 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sun, 8 May 2016 23:27:58 +1000 Subject: [PATCH 15/19] Move code away from TexturePackExtractor into their logical classes. --- ClassicalSharp/Game/Game.Properties.cs | 2 +- ClassicalSharp/Game/Game.cs | 22 ++++++++- ClassicalSharp/Model/ModelCache.cs | 36 ++++++++++++-- ClassicalSharp/Rendering/WeatherRenderer.cs | 27 +++++++--- .../TexturePack/TexturePackExtractor.cs | 49 ++----------------- 5 files changed, 78 insertions(+), 58 deletions(-) diff --git a/ClassicalSharp/Game/Game.Properties.cs b/ClassicalSharp/Game/Game.Properties.cs index f8a699ee2..1a55598e6 100644 --- a/ClassicalSharp/Game/Game.Properties.cs +++ b/ClassicalSharp/Game/Game.Properties.cs @@ -173,7 +173,7 @@ namespace ClassicalSharp { public Vector3 CurrentCameraPos; public Animations Animations; - internal int CloudsTexId, RainTexId, SnowTexId, GuiTexId, GuiClassicTexId; + internal int CloudsTexId, GuiTexId, GuiClassicTexId; internal bool screenshotRequested; internal EntryList AcceptedUrls = new EntryList( "acceptedurls.txt" ); internal EntryList DeniedUrls = new EntryList( "deniedurls.txt" ); diff --git a/ClassicalSharp/Game/Game.cs b/ClassicalSharp/Game/Game.cs index 5d1dfcd0d..af1ad91c5 100644 --- a/ClassicalSharp/Game/Game.cs +++ b/ClassicalSharp/Game/Game.cs @@ -537,8 +537,6 @@ namespace ClassicalSharp { Graphics.Dispose(); Drawer2D.DisposeInstance(); Graphics.DeleteTexture( ref CloudsTexId ); - Graphics.DeleteTexture( ref RainTexId ); - Graphics.DeleteTexture( ref SnowTexId ); Graphics.DeleteTexture( ref GuiTexId ); Graphics.DeleteTexture( ref GuiClassicTexId ); foreach( WarningScreen screen in WarningOverlays ) @@ -559,6 +557,26 @@ namespace ClassicalSharp { Inventory.CanPlace[block] && Inventory.CanDelete[block]; } + + /// Reads a bitmap from the stream (converting it to 32 bits per pixel if necessary), + /// and updates the native texture for it. + public void UpdateTexture( ref int texId, byte[] data, bool setSkinType ) { + MemoryStream stream = new MemoryStream( data ); + Graphics.DeleteTexture( ref texId ); + + using( Bitmap bmp = Platform.ReadBmp( stream ) ) { + if( setSkinType ) + DefaultPlayerSkinType = Utils.GetSkinType( bmp ); + + if( !FastBitmap.CheckFormat( bmp.PixelFormat ) ) { + using( Bitmap bmp32 = Drawer2D.ConvertTo32Bpp( bmp ) ) + texId = Graphics.CreateTexture( bmp32 ); + } else { + texId = Graphics.CreateTexture( bmp ); + } + } + } + public Game( string username, string mppass, string skinServer, bool nullContext, int width, int height ) { window = new DesktopWindow( this, username, nullContext, width, height ); diff --git a/ClassicalSharp/Model/ModelCache.cs b/ClassicalSharp/Model/ModelCache.cs index 048879a05..b039f02df 100644 --- a/ClassicalSharp/Model/ModelCache.cs +++ b/ClassicalSharp/Model/ModelCache.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.IO; +using ClassicalSharp.Events; using ClassicalSharp.GraphicsAPI; namespace ClassicalSharp.Model { @@ -12,7 +13,7 @@ namespace ClassicalSharp.Model { IGraphicsApi api; public ModelCache( Game window ) { this.game = window; - api = game.Graphics; + api = game.Graphics; } public CustomModel[] CustomModels = new CustomModel[256]; @@ -23,6 +24,7 @@ namespace ClassicalSharp.Model { model.CreateParts(); cache["humanoid"] = model; cache["human"] = cache["humanoid"]; + game.Events.TextureChanged += TextureChanged; } internal int vb; @@ -57,15 +59,16 @@ namespace ClassicalSharp.Model { else if( modelName == "zombie" ) return new ZombieModel( game ); else if( modelName == "block" ) return new BlockModel( game ); else if( modelName == "chibi" ) return new ChibiModel( game ); - else if( modelName == "giant" ) return new GiantModel( game ); + else if( modelName == "giant" ) return new GiantModel( game ); return null; } public void Dispose() { - foreach( var entry in cache ) { + foreach( var entry in cache ) entry.Value.Dispose(); - } api.DeleteDynamicVb( vb ); + game.Events.TextureChanged -= TextureChanged; + api.DeleteTexture( ref ChickenTexId ); api.DeleteTexture( ref CreeperTexId ); api.DeleteTexture( ref PigTexId ); @@ -74,7 +77,30 @@ namespace ClassicalSharp.Model { api.DeleteTexture( ref SpiderTexId ); api.DeleteTexture( ref ZombieTexId ); api.DeleteTexture( ref SheepFurTexId ); - api.DeleteTexture( ref HumanoidTexId ); + api.DeleteTexture( ref HumanoidTexId ); + } + + void TextureChanged( object sender, TextureEventArgs e ) { + switch( e.Name ) { + case "chicken.png": + game.UpdateTexture( ref ChickenTexId, e.Data, false ); break; + case "creeper.png": + game.UpdateTexture( ref CreeperTexId, e.Data, false ); break; + case "pig.png": + game.UpdateTexture( ref PigTexId, e.Data, false ); break; + case "sheep.png": + game.UpdateTexture( ref SheepTexId, e.Data, false ); break; + case "skeleton.png": + game.UpdateTexture( ref SkeletonTexId, e.Data, false ); break; + case "spider.png": + game.UpdateTexture( ref SpiderTexId, e.Data, false ); break; + case "zombie.png": + game.UpdateTexture( ref ZombieTexId, e.Data, false ); break; + case "sheep_fur.png": + game.UpdateTexture( ref SheepFurTexId, e.Data, false ); break; + case "char.png": + game.UpdateTexture( ref HumanoidTexId, e.Data, true ); break; + } } } } diff --git a/ClassicalSharp/Rendering/WeatherRenderer.cs b/ClassicalSharp/Rendering/WeatherRenderer.cs index 4961a6985..1c468e0bb 100644 --- a/ClassicalSharp/Rendering/WeatherRenderer.cs +++ b/ClassicalSharp/Rendering/WeatherRenderer.cs @@ -1,5 +1,7 @@ // ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT using System; +using System.IO; +using ClassicalSharp.Events; using ClassicalSharp.GraphicsAPI; using ClassicalSharp.Map; using OpenTK; @@ -12,6 +14,7 @@ namespace ClassicalSharp.Renderers { World map; IGraphicsApi graphics; BlockInfo info; + public int RainTexId, SnowTexId; public void Init( Game game ) { this.game = game; @@ -19,7 +22,8 @@ namespace ClassicalSharp.Renderers { graphics = game.Graphics; info = game.BlockInfo; weatherVb = graphics.CreateDynamicVb( VertexFormat.P3fT2fC4b, vertices.Length ); - } + game.Events.TextureChanged += TextureChanged; + } int weatherVb; short[] heightmap; @@ -34,7 +38,7 @@ namespace ClassicalSharp.Renderers { if( weather == Weather.Sunny ) return; if( heightmap == null ) InitHeightmap(); - graphics.BindTexture( weather == Weather.Rainy ? game.RainTexId : game.SnowTexId ); + graphics.BindTexture( weather == Weather.Rainy ? RainTexId : SnowTexId ); Vector3 camPos = game.CurrentCameraPos; Vector3I pos = Vector3I.Floor( camPos ); bool moved = pos != lastPos; @@ -109,6 +113,21 @@ namespace ClassicalSharp.Renderers { oneY = length * width; } + void TextureChanged( object sender, TextureEventArgs e ) { + if( e.Name == "snow.png" ) { + game.UpdateTexture( ref SnowTexId, e.Data, false ); + } else if( e.Name == "rain.png" ) { + game.UpdateTexture( ref RainTexId, e.Data, false ); + } + } + + public void Dispose() { + game.Graphics.DeleteTexture( ref RainTexId ); + game.Graphics.DeleteTexture( ref SnowTexId ); + graphics.DeleteDynamicVb( weatherVb ); + game.Events.TextureChanged -= TextureChanged; + } + void InitHeightmap() { heightmap = new short[map.Width * map.Length]; for( int i = 0; i < heightmap.Length; i++ ) { @@ -116,10 +135,6 @@ namespace ClassicalSharp.Renderers { } } - public void Dispose() { - graphics.DeleteDynamicVb( weatherVb ); - } - float GetRainHeight( int x, int z ) { if( x < 0 || z < 0 || x >= width || z >= length ) return map.EdgeHeight; int index = (x * length) + z; diff --git a/ClassicalSharp/TexturePack/TexturePackExtractor.cs b/ClassicalSharp/TexturePack/TexturePackExtractor.cs index 96f22f15e..f2ede71d9 100644 --- a/ClassicalSharp/TexturePack/TexturePackExtractor.cs +++ b/ClassicalSharp/TexturePack/TexturePackExtractor.cs @@ -50,38 +50,16 @@ namespace ClassicalSharp.TexturePack { Bitmap atlas = Platform.ReadBmp( stream ); if( !game.ChangeTerrainAtlas( atlas ) ) atlas.Dispose(); break; - case "chicken.png": - UpdateTexture( ref cache.ChickenTexId, stream, false ); break; - case "creeper.png": - UpdateTexture( ref cache.CreeperTexId, stream, false ); break; - case "pig.png": - UpdateTexture( ref cache.PigTexId, stream, false ); break; - case "sheep.png": - UpdateTexture( ref cache.SheepTexId, stream, false ); break; - case "skeleton.png": - UpdateTexture( ref cache.SkeletonTexId, stream, false ); break; - case "spider.png": - UpdateTexture( ref cache.SpiderTexId, stream, false ); break; - case "zombie.png": - UpdateTexture( ref cache.ZombieTexId, stream, false ); break; - case "sheep_fur.png": - UpdateTexture( ref cache.SheepFurTexId, stream, false ); break; - case "char.png": - UpdateTexture( ref cache.HumanoidTexId, stream, true ); break; case "clouds.png": case "cloud.png": - UpdateTexture( ref game.CloudsTexId, stream, false ); break; - case "rain.png": - UpdateTexture( ref game.RainTexId, stream, false ); break; - case "snow.png": - UpdateTexture( ref game.SnowTexId, stream, false ); break; + game.UpdateTexture( ref game.CloudsTexId, data, false ); break; case "gui.png": - UpdateTexture( ref game.GuiTexId, stream, false ); break; + game.UpdateTexture( ref game.GuiTexId, data, false ); break; case "gui_classic.png": - UpdateTexture( ref game.GuiClassicTexId, stream, false ); break; + game.UpdateTexture( ref game.GuiClassicTexId, data, false ); break; case "particles.png": - UpdateTexture( ref game.ParticleManager.ParticlesTexId, - stream, false ); break; + game.UpdateTexture( ref game.ParticleManager.ParticlesTexId, + data, false ); break; case "default.png": SetFontBitmap( game, stream ); break; } @@ -95,22 +73,5 @@ namespace ClassicalSharp.TexturePack { game.Drawer2D.SetFontBitmap( bmp ); game.Events.RaiseChatFontChanged(); } - - /// Reads a bitmap from the stream (converting it to 32 bits per pixel if necessary), - /// and updates the native texture for it. - public void UpdateTexture( ref int texId, Stream stream, bool setSkinType ) { - game.Graphics.DeleteTexture( ref texId ); - using( Bitmap bmp = Platform.ReadBmp( stream ) ) { - if( setSkinType ) - game.DefaultPlayerSkinType = Utils.GetSkinType( bmp ); - - if( !FastBitmap.CheckFormat( bmp.PixelFormat ) ) { - using( Bitmap bmp32 = game.Drawer2D.ConvertTo32Bpp( bmp ) ) - texId = game.Graphics.CreateTexture( bmp32 ); - } else { - texId = game.Graphics.CreateTexture( bmp ); - } - } - } } } From 5633b61fd9eb90309f052a1be869966e03ac8f75 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sun, 8 May 2016 23:41:12 +1000 Subject: [PATCH 16/19] Make select texture pack and load level menus nicer. --- ClassicalSharp/2D/Screens/FilesScreen.cs | 18 +++++++++--------- ClassicalSharp/Program.cs | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/ClassicalSharp/2D/Screens/FilesScreen.cs b/ClassicalSharp/2D/Screens/FilesScreen.cs index 8f9690722..8f9fee319 100644 --- a/ClassicalSharp/2D/Screens/FilesScreen.cs +++ b/ClassicalSharp/2D/Screens/FilesScreen.cs @@ -22,18 +22,18 @@ namespace ClassicalSharp.Gui { textFont = new Font( game.FontName, 16, FontStyle.Bold ); arrowFont = new Font( game.FontName, 18, FontStyle.Bold ); titleFont = new Font( game.FontName, 16, FontStyle.Bold ); - title = ChatTextWidget.Create( game, 0, -130, titleText, + title = ChatTextWidget.Create( game, 0, -155, titleText, Anchor.Centre, Anchor.Centre, titleFont ); buttons = new ButtonWidget[] { - MakeText( 0, -80, Get( 0 ) ), - MakeText( 0, -40, Get( 1 ) ), + MakeText( 0, -100, Get( 0 ) ), + MakeText( 0, -50, Get( 1 ) ), MakeText( 0, 0, Get( 2 ) ), - MakeText( 0, 40, Get( 3 ) ), - MakeText( 0, 80, Get( 4 ) ), + MakeText( 0, 50, Get( 3 ) ), + MakeText( 0, 100, Get( 4 ) ), - Make( -160, 0, "<", (g, w) => PageClick( false ) ), - Make( 160, 0, ">", (g, w) => PageClick( true ) ), + Make( -220, 0, "<", (g, w) => PageClick( false ) ), + Make( 220, 0, ">", (g, w) => PageClick( true ) ), null, }; } @@ -52,12 +52,12 @@ namespace ClassicalSharp.Gui { } ButtonWidget MakeText( int x, int y, string text ) { - return ButtonWidget.Create( game, x, y, 240, 30, text, + return ButtonWidget.Create( game, x, y, 301, 40, text, Anchor.Centre, Anchor.Centre, textFont, TextButtonClick ); } ButtonWidget Make( int x, int y, string text, Action onClick ) { - return ButtonWidget.Create( game, x, y, 40, 40, text, + return ButtonWidget.Create( game, x, y, 41, 40, text, Anchor.Centre, Anchor.Centre, arrowFont, LeftOnly( onClick ) ); } diff --git a/ClassicalSharp/Program.cs b/ClassicalSharp/Program.cs index 6b3fc410e..ffed8654e 100644 --- a/ClassicalSharp/Program.cs +++ b/ClassicalSharp/Program.cs @@ -52,10 +52,10 @@ namespace ClassicalSharp { width = 640; height = 480; if( device.Width >= 1024 && device.Height >= 768 ) { - width = 800; height = 600; + //width = 800; height = 600; } if( device.Width >= 1920 && device.Height >= 1080 ) { - width = 1600; height = 900; + //width = 1600; height = 900; } } From 3fa57fa6ac35fb4c2beafc6a0f7ebb454f14f5e1 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Mon, 9 May 2016 00:26:36 +1000 Subject: [PATCH 17/19] Add UserEvent events class. Only event currently is when user has manually placed a block. --- ClassicalSharp/ClassicalSharp.csproj | 1 + ClassicalSharp/Events/UserEvents.cs | 38 ++++++++++++++++++++++++++ ClassicalSharp/Game/Game.Properties.cs | 1 + ClassicalSharp/Game/PickingHandler.cs | 36 +++++++++++++----------- ClassicalSharp/Program.cs | 4 +-- 5 files changed, 62 insertions(+), 18 deletions(-) create mode 100644 ClassicalSharp/Events/UserEvents.cs diff --git a/ClassicalSharp/ClassicalSharp.csproj b/ClassicalSharp/ClassicalSharp.csproj index f4b59650a..2cf2eb609 100644 --- a/ClassicalSharp/ClassicalSharp.csproj +++ b/ClassicalSharp/ClassicalSharp.csproj @@ -165,6 +165,7 @@ + diff --git a/ClassicalSharp/Events/UserEvents.cs b/ClassicalSharp/Events/UserEvents.cs new file mode 100644 index 000000000..269893cf0 --- /dev/null +++ b/ClassicalSharp/Events/UserEvents.cs @@ -0,0 +1,38 @@ +// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT +using System; + +namespace ClassicalSharp.Events { + + public class UserEvents { + + /// Raised when the user changes a block in the world. + public event EventHandler BlockChanged; + internal void RaiseBlockChanged( Vector3I coords, byte old, byte block ) { + blockArgs.Coords = coords; blockArgs.OldBlock = old; blockArgs.Block = block; + Raise( BlockChanged, blockArgs ); + } + + BlockChangedEventArgs blockArgs = new BlockChangedEventArgs(); + protected void Raise( EventHandler handler ) { + if( handler != null ) + handler( this, EventArgs.Empty ); + } + + protected void Raise( EventHandler handler, T args ) where T : EventArgs { + if( handler != null ) + handler( this, args ); + } + } + + public sealed class BlockChangedEventArgs : EventArgs { + + /// Location within the world the block was updated at. + public Vector3I Coords; + + /// Block ID that was at the given location before. + public byte OldBlock; + + /// Block ID that is now at the given location. + public byte Block; + } +} diff --git a/ClassicalSharp/Game/Game.Properties.cs b/ClassicalSharp/Game/Game.Properties.cs index 1a55598e6..7dc6e746e 100644 --- a/ClassicalSharp/Game/Game.Properties.cs +++ b/ClassicalSharp/Game/Game.Properties.cs @@ -105,6 +105,7 @@ namespace ClassicalSharp { public OtherEvents Events = new OtherEvents(); public EntityEvents EntityEvents = new EntityEvents(); public WorldEvents WorldEvents = new WorldEvents(); + public UserEvents UserEvents = new UserEvents(); public InputHandler InputHandler; public Chat Chat; public BlockHandRenderer BlockHandRenderer; diff --git a/ClassicalSharp/Game/PickingHandler.cs b/ClassicalSharp/Game/PickingHandler.cs index 3edf8bee9..79a55b520 100644 --- a/ClassicalSharp/Game/PickingHandler.cs +++ b/ClassicalSharp/Game/PickingHandler.cs @@ -13,7 +13,7 @@ namespace ClassicalSharp { public PickingHandler( Game game, InputHandler input ) { this.game = game; this.input = input; - } + } internal DateTime lastClick = DateTime.MinValue; public void PickBlocks( bool cooldown, bool left, bool middle, bool right ) { @@ -32,47 +32,51 @@ namespace ClassicalSharp { } int buttonsDown = (left ? 1 : 0) + (right ? 1 : 0) + (middle ? 1 : 0); - if( buttonsDown > 1 || game.ActiveScreen.HandlesAllInput || + if( buttonsDown > 1 || game.ActiveScreen.HandlesAllInput || inv.HeldBlock == Block.Air ) return; // always play delete animations, even if we aren't picking a block. if( left ) game.BlockHandRenderer.SetAnimationClick( true ); if( !game.SelectedPos.Valid ) return; + BlockInfo info = game.BlockInfo; if( middle ) { Vector3I pos = game.SelectedPos.BlockPos; - byte block = 0; - if( game.World.IsValidPos( pos ) && (block = game.World.GetBlock( pos )) != 0 - && (inv.CanPlace[block] || inv.CanDelete[block]) ) { - + if( !game.World.IsValidPos( pos ) ) return; + byte old = game.World.GetBlock( pos ); + + if( !info.IsAir[old] && (inv.CanPlace[old] || inv.CanDelete[old]) ) { for( int i = 0; i < inv.Hotbar.Length; i++ ) { - if( inv.Hotbar[i] == (Block)block ) { + if( inv.Hotbar[i] == (Block)old ) { inv.HeldBlockIndex = i; return; } } - inv.HeldBlock = (Block)block; + inv.HeldBlock = (Block)old; } } else if( left ) { Vector3I pos = game.SelectedPos.BlockPos; - byte block = 0; - if( game.World.IsValidPos( pos ) && (block = game.World.GetBlock( pos )) != 0 - && inv.CanDelete[block] ) { - game.ParticleManager.BreakBlockEffect( pos, block ); - game.AudioPlayer.PlayDigSound( game.BlockInfo.DigSounds[block] ); + if( !game.World.IsValidPos( pos ) ) return; + byte old = game.World.GetBlock( pos ); + + if( !info.IsAir[old] && inv.CanDelete[old] ) { + game.ParticleManager.BreakBlockEffect( pos, old ); + game.AudioPlayer.PlayDigSound( game.BlockInfo.DigSounds[old] ); game.UpdateBlock( pos.X, pos.Y, pos.Z, 0 ); game.Network.SendSetBlock( pos.X, pos.Y, pos.Z, false, (byte)inv.HeldBlock ); + game.UserEvents.RaiseBlockChanged( pos, old, 0 ); } } else if( right ) { Vector3I pos = game.SelectedPos.TranslatedPos; if( !game.World.IsValidPos( pos ) ) return; - + byte old = game.World.GetBlock( pos ); byte block = (byte)inv.HeldBlock; - if( !game.CanPick( game.World.GetBlock( pos ) ) && inv.CanPlace[block] - && CheckIsFree( game.SelectedPos, block ) ) { + + if( !game.CanPick( old ) && inv.CanPlace[block] && CheckIsFree( game.SelectedPos, block ) ) { game.UpdateBlock( pos.X, pos.Y, pos.Z, block ); game.AudioPlayer.PlayDigSound( game.BlockInfo.StepSounds[block] ); game.Network.SendSetBlock( pos.X, pos.Y, pos.Z, true, block ); game.BlockHandRenderer.SetAnimationClick( false ); + game.UserEvents.RaiseBlockChanged( pos, old, block ); } } } diff --git a/ClassicalSharp/Program.cs b/ClassicalSharp/Program.cs index ffed8654e..6b3fc410e 100644 --- a/ClassicalSharp/Program.cs +++ b/ClassicalSharp/Program.cs @@ -52,10 +52,10 @@ namespace ClassicalSharp { width = 640; height = 480; if( device.Width >= 1024 && device.Height >= 768 ) { - //width = 800; height = 600; + width = 800; height = 600; } if( device.Width >= 1920 && device.Height >= 1080 ) { - //width = 1600; height = 900; + width = 1600; height = 900; } } From 60111bcbf225d2f571149504bdbb0fc17915f395 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Mon, 9 May 2016 08:38:59 +1000 Subject: [PATCH 18/19] Add /cuboid command for singleplayer. (Thanks MrGoober) --- .../2D/Screens/Inventory/InventoryScreen.cs | 40 +----- ClassicalSharp/Blocks/BlockInfo.cs | 39 ++++++ ClassicalSharp/ClassicalSharp.csproj | 1 + ClassicalSharp/Commands/CommandManager.cs | 5 +- ClassicalSharp/Commands/DefaultCommands.cs | 21 ---- .../Commands/SinglePlayerCommands.cs | 115 ++++++++++++++++++ 6 files changed, 162 insertions(+), 59 deletions(-) create mode 100644 ClassicalSharp/Commands/SinglePlayerCommands.cs diff --git a/ClassicalSharp/2D/Screens/Inventory/InventoryScreen.cs b/ClassicalSharp/2D/Screens/Inventory/InventoryScreen.cs index e4e2fb12c..732ed3887 100644 --- a/ClassicalSharp/2D/Screens/Inventory/InventoryScreen.cs +++ b/ClassicalSharp/2D/Screens/Inventory/InventoryScreen.cs @@ -132,20 +132,12 @@ namespace ClassicalSharp.Gui { RecreateBlockInfoTexture(); } - static string[] normalNames = null; - void UpdateBlockInfoString( Block block ) { - if( normalNames == null ) - MakeNormalNames(); - + void UpdateBlockInfoString( Block block ) { int index = 0; buffer.Clear(); buffer.Append( ref index, "&f" ); - string value = game.BlockInfo.Name[(byte)block]; - if( (byte)block < BlockInfo.CpeBlocksCount && value == "Invalid" ) { - buffer.Append( ref index, normalNames[(byte)block] ); - } else { - buffer.Append( ref index, value ); - } + string value = game.BlockInfo.GetBlockName( (byte)block ); + buffer.Append( ref index, value ); if( game.ClassicMode ) return; buffer.Append( ref index, " (ID: " ); @@ -157,32 +149,6 @@ namespace ClassicalSharp.Gui { buffer.Append( ref index, "&f)" ); } - void MakeNormalNames() { - normalNames = new string[BlockInfo.CpeBlocksCount]; - for( int i = 0; i < normalNames.Length; i++ ) { - string origName = Enum.GetName( typeof(Block), (byte)i ); - buffer.Clear(); - int index = 0; - SplitUppercase( origName, ref index ); - normalNames[i] = buffer.ToString(); - } - } - - void SplitUppercase( string value, ref int index ) { - for( int i = 0; i < value.Length; i++ ) { - char c = value[i]; - bool upper = Char.IsUpper( c ) && i > 0; - bool nextLower = i < value.Length - 1 && !Char.IsUpper( value[i + 1] ); - - if( upper && nextLower ) { - buffer.Append( ref index, ' ' ); - buffer.Append( ref index, Char.ToLower( c ) ); - } else { - buffer.Append( ref index, c ); - } - } - } - int lastCreatedIndex = -1000; void RecreateBlockInfoTexture() { if( selIndex == lastCreatedIndex ) return; diff --git a/ClassicalSharp/Blocks/BlockInfo.cs b/ClassicalSharp/Blocks/BlockInfo.cs index 4eb683154..d4f63994a 100644 --- a/ClassicalSharp/Blocks/BlockInfo.cs +++ b/ClassicalSharp/Blocks/BlockInfo.cs @@ -223,6 +223,45 @@ namespace ClassicalSharp { StepSounds[id] = SoundType.None; DigSounds[id] = SoundType.None; } + + internal static string[] normalNames = null; + public string GetBlockName( byte block ) { + if( normalNames == null ) + MakeNormalNames(); + + string value = Name[block]; + if( block < CpeBlocksCount && value == "Invalid" ) + return normalNames[block]; + return value; + } + + static void MakeNormalNames() { + StringBuffer buffer = new StringBuffer( 64 ); + normalNames = new string[CpeBlocksCount]; + + for( int i = 0; i < normalNames.Length; i++ ) { + string origName = Enum.GetName( typeof(Block), (byte)i ); + buffer.Clear(); + int index = 0; + SplitUppercase( buffer, origName, ref index ); + normalNames[i] = buffer.ToString(); + } + } + + static void SplitUppercase( StringBuffer buffer, string value, ref int index ) { + for( int i = 0; i < value.Length; i++ ) { + char c = value[i]; + bool upper = Char.IsUpper( c ) && i > 0; + bool nextLower = i < value.Length - 1 && !Char.IsUpper( value[i + 1] ); + + if( upper && nextLower ) { + buffer.Append( ref index, ' ' ); + buffer.Append( ref index, Char.ToLower( c ) ); + } else { + buffer.Append( ref index, c ); + } + } + } } public enum CollideType : byte { diff --git a/ClassicalSharp/ClassicalSharp.csproj b/ClassicalSharp/ClassicalSharp.csproj index 2cf2eb609..65e13bbc0 100644 --- a/ClassicalSharp/ClassicalSharp.csproj +++ b/ClassicalSharp/ClassicalSharp.csproj @@ -145,6 +145,7 @@ + diff --git a/ClassicalSharp/Commands/CommandManager.cs b/ClassicalSharp/Commands/CommandManager.cs index b5e8b2fb4..198b51178 100644 --- a/ClassicalSharp/Commands/CommandManager.cs +++ b/ClassicalSharp/Commands/CommandManager.cs @@ -21,8 +21,11 @@ namespace ClassicalSharp.Commands { Register( new HelpCommand() ); Register( new InfoCommand() ); Register( new RenderTypeCommand() ); - if( game.Network.IsSinglePlayer ) + + if( game.Network.IsSinglePlayer ) { Register( new ModelCommand() ); + Register( new CuboidCommand() ); + } } public void Ready( Game game ) { } diff --git a/ClassicalSharp/Commands/DefaultCommands.cs b/ClassicalSharp/Commands/DefaultCommands.cs index 8bbf7598e..6351ad15a 100644 --- a/ClassicalSharp/Commands/DefaultCommands.cs +++ b/ClassicalSharp/Commands/DefaultCommands.cs @@ -150,25 +150,4 @@ namespace ClassicalSharp.Commands { } } } - - public sealed class ModelCommand : Command { - - public ModelCommand() { - Name = "Model"; - Help = new [] { - "&a/client model [name]", - "&bnames: &echibi, chicken, creeper, human, pig, sheep", - "&e skeleton, spider, zombie, ", - }; - } - - public override void Execute( CommandReader reader ) { - string name = reader.Next(); - if( String.IsNullOrEmpty( name ) ) { - game.Chat.Add( "&e/client model: &cYou didn't specify a model name." ); - } else { - game.LocalPlayer.SetModel( name ); - } - } - } } diff --git a/ClassicalSharp/Commands/SinglePlayerCommands.cs b/ClassicalSharp/Commands/SinglePlayerCommands.cs new file mode 100644 index 000000000..4c07e9850 --- /dev/null +++ b/ClassicalSharp/Commands/SinglePlayerCommands.cs @@ -0,0 +1,115 @@ +// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT +using System; +using System.Collections.Generic; +using System.Text; +using ClassicalSharp.Events; +using ClassicalSharp.Renderers; +using OpenTK.Input; + +namespace ClassicalSharp.Commands { + + public sealed class ModelCommand : Command { + + public ModelCommand() { + Name = "Model"; + Help = new [] { + "&a/client model [name]", + "&bnames: &echibi, chicken, creeper, human, pig, sheep", + "&e skeleton, spider, zombie, ", + }; + } + + public override void Execute( CommandReader reader ) { + string name = reader.Next(); + if( String.IsNullOrEmpty( name ) ) { + game.Chat.Add( "&e/client model: &cYou didn't specify a model name." ); + } else { + game.LocalPlayer.SetModel( name ); + } + } + } + + public sealed class CuboidCommand : Command { + + public CuboidCommand() { + Name = "Cuboid"; + Help = new [] { + "&a/client cuboid [block] [persist]", + "&eFills the 3D rectangle between two points with [block].", + "&eIf no block is given, uses your currently held block.", + "&e If persist is given and is \"yes\", then the command", + "&e will repeatedly cuboid, without needing to be typed in again.", + }; + } + byte block = 0xFF; + Vector3I mark1, mark2; + bool persist = false; + + public override void Execute( CommandReader reader ) { + game.UserEvents.BlockChanged -= BlockChanged; + block = 0xFF; + mark1 = new Vector3I( int.MaxValue ); + mark2 = new Vector3I( int.MaxValue ); + persist = false; + + if( !ParseBlock( reader ) ) return; + string arg = reader.Next(); + if( arg != null && Utils.CaselessEquals( arg, "yes" ) ) + persist = true; + + game.Chat.Add( "&eCuboid: &fPlace or delete a block.", MessageType.ClientStatus3 ); + game.UserEvents.BlockChanged += BlockChanged; + } + + bool ParseBlock( CommandReader reader ) { + string id = reader.Next(); + if( id == null ) return true; + if( Utils.CaselessEquals( id, "yes" ) ) { persist = true; return true; } + + byte blockID = 0; + if( !byte.TryParse( id, out blockID ) ) { + game.Chat.Add( "&eCuboid: &c\"" + id + "\" is not a valid block id." ); return false; + } + if( blockID >= BlockInfo.CpeBlocksCount && game.BlockInfo.Name[blockID] == "Invalid" ) { + game.Chat.Add( "&eCuboid: &cThere is no block with id \"" + id + "\"." ); return false; + } + block = blockID; + return true; + } + + void BlockChanged( object sender, BlockChangedEventArgs e ) { + if( mark1.X == int.MaxValue ) { + mark1 = e.Coords; + game.UpdateBlock( mark1.X, mark1.Y, mark1.Z, e.OldBlock ); + game.Chat.Add( "&eCuboid: &fMark 1 placed at (" + e.Coords + "), place mark 2.", + MessageType.ClientStatus3 ); + } else { + mark2 = e.Coords; + DoCuboid(); + game.Chat.Add( null, MessageType.ClientStatus3 ); + + if( !persist ) { + game.UserEvents.BlockChanged -= BlockChanged; + } else { + mark1 = new Vector3I( int.MaxValue ); + game.Chat.Add( "&eCuboid: &fPlace or delete a block.", MessageType.ClientStatus3 ); + } + } + } + + void DoCuboid() { + Vector3I min = Vector3I.Min( mark1, mark2 ); + Vector3I max = Vector3I.Max( mark1, mark2 ); + if( !game.World.IsValidPos( min ) || !game.World.IsValidPos( max ) ) return; + byte id = block; + + if( id == 0xFF ) id = (byte)game.Inventory.HeldBlock; + for( int y = min.Y; y <= max.Y; y++ ) + for( int z = min.Z; z <= max.Z; z++ ) + for( int x = min.X; x <= max.X; x++ ) + { + game.UpdateBlock( x, y, z, id ); + } + } + } +} From 7427c56e199d1007bc01849c6164b9f1964a3a32 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Mon, 9 May 2016 08:46:04 +1000 Subject: [PATCH 19/19] Fix client status widget returning too big a 'used height'. --- ClassicalSharp/2D/Widgets/Chat/TextGroupWidget.cs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/ClassicalSharp/2D/Widgets/Chat/TextGroupWidget.cs b/ClassicalSharp/2D/Widgets/Chat/TextGroupWidget.cs index cb9c2c6ad..3126873b2 100644 --- a/ClassicalSharp/2D/Widgets/Chat/TextGroupWidget.cs +++ b/ClassicalSharp/2D/Widgets/Chat/TextGroupWidget.cs @@ -90,15 +90,11 @@ namespace ClassicalSharp.Gui { } public int GetUsedHeight() { - int sum = 0, max = Textures.Length; + int sum = 0; for( int i = 0; i < Textures.Length; i++ ) { - if( Textures[i].IsValid ) { - max = i; break; - } - } - - for( int i = max; i < Textures.Length; i++ ) + if( !Textures[i].IsValid ) continue; sum += Textures[i].Height; + } return sum; }