From f652953582b0e32e16b3c3b9fcf283b098bb2fe6 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Thu, 10 Dec 2015 21:36:55 +1100 Subject: [PATCH] Add a generation gui. --- ClassicalSharp/2D/Screens/HotkeyScreen.cs | 6 +- .../2D/Screens/Menu/GenLevelScreen.cs | 165 ++++++++++++++++++ .../2D/Screens/Menu/MenuInputScreen.cs | 8 +- ClassicalSharp/2D/Screens/Menu/PauseScreen.cs | 6 +- .../2D/Screens/Menu/SaveLevelScreen.cs | 5 +- .../2D/Widgets/Menu/MenuInputWidget.cs | 12 +- ClassicalSharp/ClassicalSharp.csproj | 2 +- ClassicalSharp/Generator/NotchyGenerator.cs | 1 + ClassicalSharp/Rendering/WeatherRenderer.cs | 1 + ClassicalSharp/Singleplayer/Commands.cs | 44 ----- ClassicalSharp/Singleplayer/Physics.cs | 2 +- ClassicalSharp/Singleplayer/Server.cs | 46 ++--- 12 files changed, 202 insertions(+), 96 deletions(-) create mode 100644 ClassicalSharp/2D/Screens/Menu/GenLevelScreen.cs delete mode 100644 ClassicalSharp/Singleplayer/Commands.cs diff --git a/ClassicalSharp/2D/Screens/HotkeyScreen.cs b/ClassicalSharp/2D/Screens/HotkeyScreen.cs index 0321f78e2..ffdb6f0ce 100644 --- a/ClassicalSharp/2D/Screens/HotkeyScreen.cs +++ b/ClassicalSharp/2D/Screens/HotkeyScreen.cs @@ -13,7 +13,7 @@ namespace ClassicalSharp { hotkeys = game.InputHandler.Hotkeys; } - Font hintFont, arrowFont, textFont; + Font arrowFont, textFont; public override void Render( double delta ) { RenderMenuBounds(); graphicsApi.Texturing = true; @@ -75,7 +75,6 @@ namespace ClassicalSharp { game.Keyboard.KeyRepeat = true; base.Init(); regularFont = new Font( "Arial", 16, FontStyle.Regular ); - hintFont = new Font( "Arial", 14, FontStyle.Italic ); arrowFont = new Font( "Arial", 18, FontStyle.Bold ); textFont = new Font( "Arial", 14, FontStyle.Bold ); @@ -111,7 +110,6 @@ namespace ClassicalSharp { game.Keyboard.KeyRepeat = false; DisposeEditingWidgets(); - hintFont.Dispose(); arrowFont.Dispose(); textFont.Dispose(); base.Dispose(); @@ -202,7 +200,7 @@ namespace ClassicalSharp { currentAction = MenuInputWidget.Create( game, 0, 90, 600, 25, "", Anchor.Centre, Anchor.Centre, - regularFont, titleFont, hintFont, new StringValidator( 64 ) ); + regularFont, titleFont, new StringValidator( 64 ) ); currentMoreInputLabel = TextWidget.Create( game, -170, 120, "Keep input bar open:", Anchor.Centre, Anchor.Centre, textFont ); diff --git a/ClassicalSharp/2D/Screens/Menu/GenLevelScreen.cs b/ClassicalSharp/2D/Screens/Menu/GenLevelScreen.cs new file mode 100644 index 000000000..b8e9ed604 --- /dev/null +++ b/ClassicalSharp/2D/Screens/Menu/GenLevelScreen.cs @@ -0,0 +1,165 @@ +using System; +using System.Drawing; +using System.IO; +using ClassicalSharp.Generator; +using ClassicalSharp.Singleplayer; +using OpenTK.Input; + +namespace ClassicalSharp { + + public sealed class GenLevelScreen : MenuScreen { + + public GenLevelScreen( Game game ) : base( game ) { + } + + TextWidget[] labels; + MenuInputWidget[] inputs; + MenuInputWidget selectedWidget; + + public override void Render( double delta ) { + RenderMenuBounds(); + graphicsApi.Texturing = true; + RenderMenuButtons( delta ); + for( int i = 0; i < inputs.Length; i++ ) + inputs[i].Render( delta ); + for( int i = 0; i < labels.Length; i++ ) + labels[i].Render( delta ); + graphicsApi.Texturing = false; + + if( textPath != null ) { + SaveMap( textPath ); + textPath = null; + } + } + + public override bool HandlesMouseClick( int mouseX, int mouseY, MouseButton button ) { + return HandleMouseClick( buttons, mouseX, mouseY, button ) || + HandleMouseClick( inputs, mouseX, mouseY, button ); + } + + public override bool HandlesKeyPress( char key ) { + return selectedWidget == null ? true : + selectedWidget.HandlesKeyPress( key ); + } + + public override bool HandlesKeyDown( Key key ) { + if( key == Key.Escape ) { + game.SetNewScreen( null ); + return true; + } + return selectedWidget == null ? true : + selectedWidget.HandlesKeyDown( key ); + } + + public override bool HandlesKeyUp( Key key ) { + return selectedWidget == null ? true : + selectedWidget.HandlesKeyUp( key ); + } + + public override void Init() { + game.Keyboard.KeyRepeat = true; + base.Init(); + int size = game.Drawer2D.UseBitmappedChat ? 14 : 18; + titleFont = new Font( "Arial", size, FontStyle.Bold ); + regularFont = new Font( "Arial", 16, FontStyle.Regular ); + + inputs = new [] { MakeInput( -80 ), MakeInput( -40 ), + MakeInput( 0 ), MakeInput( 40 ) + }; + labels = new [] { MakeLabel( -80, "Width:" ), MakeLabel( -40, "Height:" ), + MakeLabel( 0, "Length:" ), MakeLabel( 40, "Seed:" ), + }; + buttons = new [] { + ButtonWidget.Create( game, 0, 90, 250, 30, "Generate flatgrass", Anchor.Centre, + Anchor.Centre, titleFont, GenFlatgrassClick ), + ButtonWidget.Create( game, 0, 140, 250, 30, "Generate notchy", Anchor.Centre, + Anchor.Centre, titleFont, GenNotchyClick ), + MakeBack( false, titleFont, + (g, w) => g.SetNewScreen( new PauseScreen( g ) ) ), + }; + } + + MenuInputWidget MakeInput( int y ) { + MenuInputWidget widget = MenuInputWidget.Create( + game, 0, y, 200, 25, "", Anchor.Centre, Anchor.Centre, + regularFont, titleFont, new IntegerValidator( 1, 8192 ) ); + widget.Active = false; + widget.OnClick = InputClick; + return widget; + } + + TextWidget MakeLabel( int y, string text ) { + return TextWidget.Create( game, -140, y, text, + Anchor.Centre, Anchor.Centre, titleFont ); + } + + public override void OnResize( int oldWidth, int oldHeight, int width, int height ) { + for( int i = 0; i < inputs.Length; i++ ) + inputs[i].OnResize( oldWidth, oldHeight, width, height ); + for( int i = 0; i < labels.Length; i++ ) + labels[i].OnResize( oldWidth, oldHeight, width, height ); + base.OnResize( oldWidth, oldHeight, width, height ); + } + + public override void Dispose() { + game.Keyboard.KeyRepeat = false; + for( int i = 0; i < inputs.Length; i++ ) + inputs[i].Dispose(); + for( int i = 0; i < labels.Length; i++ ) + labels[i].Dispose(); + base.Dispose(); + } + + void InputClick( Game game, Widget widget ) { + if( selectedWidget != null ) + selectedWidget.Active = false; + + selectedWidget = (MenuInputWidget)widget; + selectedWidget.Active = true; + } + + void GenFlatgrassClick( Game game, Widget widget ) { + GenerateMap( new FlatGrassGenerator() ); + } + + void GenNotchyClick( Game game, Widget widget ) { + GenerateMap( new NotchyGenerator() ); + } + + void GenerateMap( IMapGenerator gen ) { + SinglePlayerServer server = (SinglePlayerServer)game.Network; + int width = GetInt( 0 ), height = GetInt( 1 ); + int length = GetInt( 2 ), seed = GetInt( 3 ); + + long volume = (long)width * height * length; + if( volume > 800 * 800 * 800 ) { + game.Chat.Add( "&cThe generated map's volume is too big." ); + } else if( width == 0 || height == 0 || length == 0 ) { + game.Chat.Add( "&cOne of the map dimensions is invalid."); + } else { + server.GenMap( width, height, length, seed, gen ); + } + } + + int GetInt( int index ) { + string text = inputs[index].GetText(); + if( !inputs[index].Validator.IsValidValue( text ) ) + return 0; + return text == "" ? 0 : Int32.Parse( text ); + } + + string textPath; + void SaveMap( string path ) { + try { + using( FileStream fs = new FileStream( path, FileMode.CreateNew, FileAccess.Write ) ) { + IMapFileFormat map = new MapCw(); + map.Save( fs, game ); + } + } catch( Exception ex ) { + ErrorHandler.LogError( "saving map", ex ); + return; + } + game.SetNewScreen( new PauseScreen( game ) ); + } + } +} \ No newline at end of file diff --git a/ClassicalSharp/2D/Screens/Menu/MenuInputScreen.cs b/ClassicalSharp/2D/Screens/Menu/MenuInputScreen.cs index 21d5276aa..1bde20320 100644 --- a/ClassicalSharp/2D/Screens/Menu/MenuInputScreen.cs +++ b/ClassicalSharp/2D/Screens/Menu/MenuInputScreen.cs @@ -12,7 +12,6 @@ namespace ClassicalSharp { protected MenuInputWidget inputWidget; protected MenuInputValidator[] validators; protected TextWidget descWidget; - protected Font hintFont; protected int okayIndex; public override void Render( double delta ) { @@ -29,7 +28,6 @@ namespace ClassicalSharp { public override void Init() { base.Init(); regularFont = new Font( "Arial", 16, FontStyle.Regular ); - hintFont = new Font( "Arial", 14, FontStyle.Italic ); game.Keyboard.KeyRepeat = true; } @@ -69,7 +67,6 @@ namespace ClassicalSharp { descWidget.Dispose(); if( inputWidget != null ) inputWidget.Dispose(); - hintFont.Dispose(); game.Keyboard.KeyRepeat = false; base.Dispose(); } @@ -126,9 +123,8 @@ namespace ClassicalSharp { inputWidget.Dispose(); targetWidget = selectedWidget; - inputWidget = MenuInputWidget.Create( game, 0, 150, 400, 25, button.GetValue( game ), - Anchor.Centre, Anchor.Centre, regularFont, titleFont, - hintFont, validator ); + inputWidget = MenuInputWidget.Create( game, 0, 150, 400, 25, button.GetValue( game ), Anchor.Centre, + Anchor.Centre, regularFont, titleFont, validator ); buttons[okayIndex] = ButtonWidget.Create( game, 240, 150, 30, 30, "OK", Anchor.Centre, Anchor.Centre, titleFont, OnWidgetClick ); UpdateDescription( targetWidget ); diff --git a/ClassicalSharp/2D/Screens/Menu/PauseScreen.cs b/ClassicalSharp/2D/Screens/Menu/PauseScreen.cs index e7a854230..55a2b21e3 100644 --- a/ClassicalSharp/2D/Screens/Menu/PauseScreen.cs +++ b/ClassicalSharp/2D/Screens/Menu/PauseScreen.cs @@ -30,15 +30,19 @@ namespace ClassicalSharp { (g, w) => g.SetNewScreen( new NormalKeyBindingsScreen( g ) ) ), Make( -140, 50, "Hotkeys", Anchor.Centre, (g, w) => g.SetNewScreen( new HotkeyScreen( g ) ) ), + // Column 2 Make( 140, -150, "Save level", Anchor.Centre, (g, w) => g.SetNewScreen( new SaveLevelScreen( g ) ) ), !game.Network.IsSinglePlayer ? null : Make( 140, -100, "Load level", Anchor.Centre, (g, w) => g.SetNewScreen( new LoadLevelScreen( g ) ) ), - // TODO: singleplayer Generate level screen + !game.Network.IsSinglePlayer ? null : + Make( 140, -50, "Generate level", Anchor.Centre, + (g, w) => g.SetNewScreen( new GenLevelScreen( g ) ) ), Make( 140, 50, "Select texture pack", Anchor.Centre, (g, w) => g.SetNewScreen( new TexturePackScreen( g ) ) ), + // Other MakeOther( 10, 5, 120, "Quit game", Anchor.BottomOrRight, (g, w) => g.Exit() ), diff --git a/ClassicalSharp/2D/Screens/Menu/SaveLevelScreen.cs b/ClassicalSharp/2D/Screens/Menu/SaveLevelScreen.cs index 124c8fc3c..4455ab9bf 100644 --- a/ClassicalSharp/2D/Screens/Menu/SaveLevelScreen.cs +++ b/ClassicalSharp/2D/Screens/Menu/SaveLevelScreen.cs @@ -11,7 +11,6 @@ namespace ClassicalSharp { } MenuInputWidget inputWidget; - Font hintFont; TextWidget descWidget; public override void Render( double delta ) { @@ -49,11 +48,10 @@ namespace ClassicalSharp { game.Keyboard.KeyRepeat = true; base.Init(); regularFont = new Font( "Arial", 16, FontStyle.Regular ); - hintFont = new Font( "Arial", 14, FontStyle.Italic ); inputWidget = MenuInputWidget.Create( game, -30, 50, 500, 25, "", Anchor.Centre, Anchor.Centre, - regularFont, titleFont, hintFont, new PathValidator() ); + regularFont, titleFont, new PathValidator() ); buttons = new [] { ButtonWidget.Create( game, 260, 50, 60, 30, "Save", Anchor.Centre, @@ -72,7 +70,6 @@ namespace ClassicalSharp { public override void Dispose() { game.Keyboard.KeyRepeat = false; inputWidget.Dispose(); - hintFont.Dispose(); DisposeDescWidget(); base.Dispose(); } diff --git a/ClassicalSharp/2D/Widgets/Menu/MenuInputWidget.cs b/ClassicalSharp/2D/Widgets/Menu/MenuInputWidget.cs index 902dc401a..cc62f6226 100644 --- a/ClassicalSharp/2D/Widgets/Menu/MenuInputWidget.cs +++ b/ClassicalSharp/2D/Widgets/Menu/MenuInputWidget.cs @@ -6,18 +6,17 @@ namespace ClassicalSharp { public sealed class MenuInputWidget : Widget { - public MenuInputWidget( Game game, Font font, Font boldFont, Font hintFont ) : base( game ) { + public MenuInputWidget( Game game, Font font, Font boldFont ) : base( game ) { HorizontalAnchor = Anchor.LeftOrTop; VerticalAnchor = Anchor.BottomOrRight; this.font = font; this.boldFont = boldFont; - this.hintFont = hintFont; chatInputText = new StringBuffer( 64 ); } public static MenuInputWidget Create( Game game, int x, int y, int width, int height, string text, Anchor horizontal, - Anchor vertical, Font font, Font tildeFont, Font hintFont, MenuInputValidator validator ) { - MenuInputWidget widget = new MenuInputWidget( game, font, tildeFont, hintFont ); + Anchor vertical, Font font, Font tildeFont, MenuInputValidator validator ) { + MenuInputWidget widget = new MenuInputWidget( game, font, tildeFont ); widget.HorizontalAnchor = horizontal; widget.VerticalAnchor = vertical; @@ -33,16 +32,17 @@ namespace ClassicalSharp { Texture chatInputTexture, chatCaretTexture; Color backColour = Color.FromArgb( 200, 30, 30, 30 ); - readonly Font font, boldFont, hintFont; + readonly Font font, boldFont; StringBuffer chatInputText; public int XOffset = 0, YOffset = 0; public int DesiredMaxWidth, DesiredMaxHeight; public MenuInputValidator Validator; + public bool Active = true; double accumulator; public override void Render( double delta ) { chatInputTexture.Render( graphicsApi ); - if( (accumulator % 1) >= 0.5 ) + if( (accumulator % 1) >= 0.5 && Active ) chatCaretTexture.Render( graphicsApi ); accumulator += delta; } diff --git a/ClassicalSharp/ClassicalSharp.csproj b/ClassicalSharp/ClassicalSharp.csproj index dde097b16..d97d71115 100644 --- a/ClassicalSharp/ClassicalSharp.csproj +++ b/ClassicalSharp/ClassicalSharp.csproj @@ -98,6 +98,7 @@ + @@ -228,7 +229,6 @@ - diff --git a/ClassicalSharp/Generator/NotchyGenerator.cs b/ClassicalSharp/Generator/NotchyGenerator.cs index 89331042a..dc94eda13 100644 --- a/ClassicalSharp/Generator/NotchyGenerator.cs +++ b/ClassicalSharp/Generator/NotchyGenerator.cs @@ -226,6 +226,7 @@ namespace ClassicalSharp.Generator { bool sand = n1.Compute( x, z ) > 8; bool gravel = n2.Compute( x, z ) > 12; int y = heightmap[hMapIndex++]; + if( y >= height ) continue; int index = (y * length + z) * width + x; byte blockAbove = y >= (height - 1) ? (byte)0 : blocks[index + oneY]; diff --git a/ClassicalSharp/Rendering/WeatherRenderer.cs b/ClassicalSharp/Rendering/WeatherRenderer.cs index 8542b30ab..7e0ca2916 100644 --- a/ClassicalSharp/Rendering/WeatherRenderer.cs +++ b/ClassicalSharp/Rendering/WeatherRenderer.cs @@ -145,6 +145,7 @@ namespace ClassicalSharp { } internal void UpdateHeight( int x, int y, int z, byte oldBlock, byte newBlock ) { + if( game.Map.IsNotLoaded ) return; bool didBlock = BlocksRain( oldBlock ); bool nowBlocks = BlocksRain( newBlock ); if( didBlock == nowBlocks ) return; diff --git a/ClassicalSharp/Singleplayer/Commands.cs b/ClassicalSharp/Singleplayer/Commands.cs deleted file mode 100644 index c7a004dc7..000000000 --- a/ClassicalSharp/Singleplayer/Commands.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.IO; -using ClassicalSharp.Commands; - -namespace ClassicalSharp.Singleplayer { - - /// Command that generates a new flatgrass map in singleplayer mode. - public sealed class GenerateCommand : Command { - - public GenerateCommand() { - Name = "Generate"; - Help = new [] { - "&a/client generate [width height length]", - "&bwidth: &eSpecifies X-axis/width of the new map.", - "&bheight: &eSpecifies Y-axis/height of the new map.", - "&blength: &eSpecifies Z-axis/length of the new map.", - }; - } - - public override void Execute( CommandReader reader ) { - int width, height, length; - if( !reader.NextInt( out width ) || !reader.NextInt( out height ) || !reader.NextInt( out length ) ) { - game.Chat.Add( "&e/client generate: &cInvalid dimensions." ); - } else { - if( width < 16 || height < 16 || length < 16 ) { - game.Chat.Add( "&e/client generate: &cDimensions too small." ); - return; - } - if( width > 1024 || height > 1024 || length > 1024 ) { - game.Chat.Add( "&e/client generate: &cDimensions too large." ); - return; - } - if( !( game.Network is SinglePlayerServer ) ) { - game.Chat.Add( "&e/client generate: &cThis command only works in singleplayer mode." ); - return; - } - SinglePlayerServer server = (SinglePlayerServer)game.Network; - server.NewMap(); - game.chatInInputBuffer = null; - server.MakeMap( width, height, length ); - } - } - } -} diff --git a/ClassicalSharp/Singleplayer/Physics.cs b/ClassicalSharp/Singleplayer/Physics.cs index de6754f9a..e40e9d0cb 100644 --- a/ClassicalSharp/Singleplayer/Physics.cs +++ b/ClassicalSharp/Singleplayer/Physics.cs @@ -61,7 +61,7 @@ namespace ClassicalSharp.Singleplayer { int tickCount = 0; public void Tick() { - if( !Enabled ) return; + if( !Enabled || game.Map.IsNotLoaded ) return; //if( (tickCount % 5) == 0 ) { TickLava(); diff --git a/ClassicalSharp/Singleplayer/Server.cs b/ClassicalSharp/Singleplayer/Server.cs index 81113bba0..859e87460 100644 --- a/ClassicalSharp/Singleplayer/Server.cs +++ b/ClassicalSharp/Singleplayer/Server.cs @@ -11,6 +11,10 @@ namespace ClassicalSharp.Singleplayer { Game game; internal Physics physics; + internal byte[] generatedMap; + IMapGenerator generator; + string lastState; + public SinglePlayerServer( Game window ) { game = window; physics = new Physics( game ); @@ -28,13 +32,8 @@ namespace ClassicalSharp.Singleplayer { } game.Events.RaiseBlockPermissionsChanged(); - NewMap(); - #if TEST_VANILLA - MakeMap( 384, 64, 384 ); - #else - MakeMap( 128, 128, 128 ); - #endif - game.CommandManager.RegisterCommand( new GenerateCommand() ); + int seed = new Random().Next(); + GenMap( 128, 64, 128, seed, new NotchyGenerator() ); } public override void SendChat( string text, bool partial ) { @@ -48,7 +47,7 @@ namespace ClassicalSharp.Singleplayer { } public override void SendSetBlock( int x, int y, int z, bool place, byte block ) { - if( place ) + if( place ) physics.OnBlockPlaced( x, y, z, block ); } @@ -59,7 +58,6 @@ namespace ClassicalSharp.Singleplayer { physics.Dispose(); } - string lastState; public override void Tick( double delta ) { if( Disconnected ) return; physics.Tick(); @@ -81,16 +79,6 @@ namespace ClassicalSharp.Singleplayer { } } - IMapGenerator generator; - internal void NewMap() { - ServerName = "Single player"; - ServerMotd = "Generating a map.."; - game.LocalPlayer.UserType = 0x64; - - game.Map.Reset(); - game.SetNewScreen( new LoadingMapScreen( game, ServerName, ServerMotd ) ); - } - void EndGeneration() { game.SetNewScreen( null ); if( generatedMap == null ) { @@ -109,16 +97,14 @@ namespace ClassicalSharp.Singleplayer { game.Chat.Add( "&ePlaying single player", CpeMessage.Status1 ); GC.Collect(); } - - public byte[] generatedMap; - internal void MakeMap( int width, int height, int length ) { - #if TEST_VANILLA - generator = new NotchyGenerator(); - generator.GenerateAsync( game, width, height, length, 0x5553200 ); - #else - generator = new FlatGrassGenerator(); + + internal void GenMap( int width, int height, int length, int seed, IMapGenerator generator ) { + game.Map.Reset(); + GC.Collect(); + this.generator = generator; + + game.SetNewScreen( new LoadingMapScreen( game, "Single player", "Generating.." ) ); generator.GenerateAsync( game, width, height, length, 0 ); - #endif } unsafe void MapSet( int width, int length, byte* ptr, int yStart, int yEnd, byte block ) { @@ -128,7 +114,9 @@ namespace ClassicalSharp.Singleplayer { } void ResetPlayerPosition() { - float x = game.Map.Width / 2, y = game.Map.Height / 2, z = game.Map.Length / 2; + int x = game.Map.Width / 2, z = game.Map.Length / 2; + int y = game.Map.GetLightHeight( x, z ) + 2; + LocationUpdate update = LocationUpdate.MakePosAndOri( x, y, z, 0, 0, false ); game.LocalPlayer.SetLocation( update, false ); }