diff --git a/ClassicalSharp/2D/Screens/ErrorScreen.cs b/ClassicalSharp/2D/Screens/ErrorScreen.cs index d32d0dc1a..ee8a4ebed 100644 --- a/ClassicalSharp/2D/Screens/ErrorScreen.cs +++ b/ClassicalSharp/2D/Screens/ErrorScreen.cs @@ -1,5 +1,6 @@ using System; using System.Drawing; +using OpenTK.Input; namespace ClassicalSharp { @@ -52,5 +53,19 @@ namespace ClassicalSharp { public override bool HidesHud { get { return true; } } + + public override bool HandlesKeyDown( Key key ) { return true; } + + public override bool HandlesKeyPress( char key ) { return true; } + + public override bool HandlesKeyUp( Key key ) { return true; } + + public override bool HandlesMouseClick( int mouseX, int mouseY, MouseButton button ) { return true; } + + public override bool HandlesMouseMove( int mouseX, int mouseY ) { return true; } + + public override bool HandlesMouseScroll( int delta ) { return true; } + + public override bool HandlesMouseUp( int mouseX, int mouseY, MouseButton button ) { return true; } } } diff --git a/ClassicalSharp/2D/Screens/LoadingMapScreen.cs b/ClassicalSharp/2D/Screens/LoadingMapScreen.cs index 0ad0451a1..ec15f5e06 100644 --- a/ClassicalSharp/2D/Screens/LoadingMapScreen.cs +++ b/ClassicalSharp/2D/Screens/LoadingMapScreen.cs @@ -1,5 +1,6 @@ using System; using System.Drawing; +using OpenTK.Input; namespace ClassicalSharp { @@ -77,5 +78,19 @@ namespace ClassicalSharp { public override bool HidesHud { get { return true; } } + + public override bool HandlesKeyDown( Key key ) { return true; } + + public override bool HandlesKeyPress( char key ) { return true; } + + public override bool HandlesKeyUp( Key key ) { return true; } + + public override bool HandlesMouseClick( int mouseX, int mouseY, MouseButton button ) { return true; } + + public override bool HandlesMouseMove( int mouseX, int mouseY ) { return true; } + + public override bool HandlesMouseScroll( int delta ) { return true; } + + public override bool HandlesMouseUp( int mouseX, int mouseY, MouseButton button ) { return true; } } } diff --git a/ClassicalSharp/2D/Screens/WarningScreen.cs b/ClassicalSharp/2D/Screens/WarningScreen.cs index 44c21bc72..08c40e564 100644 --- a/ClassicalSharp/2D/Screens/WarningScreen.cs +++ b/ClassicalSharp/2D/Screens/WarningScreen.cs @@ -1,13 +1,23 @@ using System; using System.Drawing; +using OpenTK.Input; namespace ClassicalSharp { - // TODO: get and set activescreen. public sealed class WarningScreen : MenuScreen { - public WarningScreen( Game game ) : base( game ) { + public WarningScreen( Game game, object metadata, Action yesClick, + Action noClick, string title, params string[] body ) : base( game ) { + this.Metadata = metadata; + this.yesClick = yesClick; + this.noClick = noClick; + this.title = title; + this.body = body; } + internal Screen lastScreen; + internal bool lastCursorVisible; + readonly string title; + readonly string[] body; public override void Init() { titleFont = new Font( "Arial", 16, FontStyle.Bold ); @@ -19,21 +29,41 @@ namespace ClassicalSharp { ButtonWidget.Create( game, 60, 30, 60, 20, "No", Anchor.Centre, Anchor.Centre, titleFont, OnNoClick ), }; - labels = new TextWidget[] { - TextWidget.Create( game, 0, -120, "Do you want to XYZ?", - Anchor.Centre, Anchor.Centre, titleFont ), - TextWidget.Create( game, 0, -70, "Warning text here", - Anchor.Centre, Anchor.Centre, regularFont ), - }; + + labels = new TextWidget[body.Length + 1]; + labels[0] = TextWidget.Create( game, 0, -120, title, + Anchor.Centre, Anchor.Centre, titleFont ); + for( int i = 0; i < body.Length; i++ ) { + labels[i + 1] = TextWidget.Create( game, 0, -70 + 20 * i, body[i], + Anchor.Centre, Anchor.Centre, regularFont ); + } } TextWidget[] labels; + Action yesClick, noClick; void OnYesClick( Game g, Widget w ) { - game.SetNewScreen( null ); + if( yesClick != null ) + yesClick( Metadata ); + Dispose(); + CloseScreen(); } void OnNoClick( Game g, Widget w ) { - game.SetNewScreen( null ); + if( noClick != null ) + noClick( Metadata ); + Dispose(); + CloseScreen(); + } + + void CloseScreen() { + game.WarningScreens.RemoveAt( 0 ); + if( game.WarningScreens.Count > 0 ) { + game.activeScreen = game.WarningScreens[0]; + } else { + game.activeScreen = lastScreen; + if( game.CursorVisible != lastCursorVisible ) + game.CursorVisible = lastCursorVisible; + } } public override void Render( double delta ) { @@ -50,5 +80,11 @@ namespace ClassicalSharp { for( int i = 0; i < labels.Length; i++ ) labels[i].OnResize( oldWidth, oldHeight, width, height ); } + + public override void Dispose() { + base.Dispose(); + for( int i = 0; i < labels.Length; i++ ) + labels[i].Dispose(); + } } } \ No newline at end of file diff --git a/ClassicalSharp/ClassicalSharp.csproj b/ClassicalSharp/ClassicalSharp.csproj index 6d9eb207f..c3055eb77 100644 --- a/ClassicalSharp/ClassicalSharp.csproj +++ b/ClassicalSharp/ClassicalSharp.csproj @@ -211,6 +211,7 @@ + diff --git a/ClassicalSharp/Game/Game.cs b/ClassicalSharp/Game/Game.cs index 96630a128..2ce669871 100644 --- a/ClassicalSharp/Game/Game.cs +++ b/ClassicalSharp/Game/Game.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Drawing; using System.IO; using System.Net; @@ -75,6 +76,8 @@ namespace ClassicalSharp { internal int CloudsTextureId, RainTextureId, SnowTextureId; internal bool screenshotRequested; public Bitmap FontBitmap; + internal List WarningScreens = new List(); + internal AcceptedUrls AcceptedUrls = new AcceptedUrls(); string defTexturePack = "default.zip"; public string DefaultTexturePack { @@ -109,6 +112,7 @@ namespace ClassicalSharp { Players = new EntityList( this ); Options.Load(); + AcceptedUrls.Load(); ViewDistance = Options.GetInt( OptionsKey.ViewDist, 16, 4096, 512 ); InputHandler = new InputHandler( this ); Chat = new ChatLog( this ); @@ -192,11 +196,6 @@ namespace ClassicalSharp { UpdateProjection(); } - public void RefreshHud() { - hudScreen.Dispose(); - hudScreen.Init(); - } - /// Gets whether the active screen handles all input. public bool ScreenLockedInput { get { return activeScreen == null ? hudScreen.HandlesAllInput : @@ -335,6 +334,18 @@ namespace ClassicalSharp { internal Screen activeScreen; public void SetNewScreen( Screen screen ) { + // don't switch to the new screen immediately if the user + // is currently looking at a warning dialog. + if( activeScreen is WarningScreen ) { + WarningScreen warning = (WarningScreen)activeScreen; + if( warning.lastScreen != null ) + warning.lastScreen.Dispose(); + + warning.lastScreen = screen; + if( warning.lastScreen != null ) + screen.Init(); + return; + } InputHandler.ScreenChanged( activeScreen, screen ); if( activeScreen != null ) activeScreen.Dispose(); @@ -350,6 +361,25 @@ namespace ClassicalSharp { activeScreen = screen; } + public void RefreshHud() { + hudScreen.Dispose(); + hudScreen.Init(); + } + + public void ShowWarning( WarningScreen screen ) { + if( !(activeScreen is WarningScreen) ) { + screen.lastScreen = activeScreen; + activeScreen = screen; + + screen.lastCursorVisible = CursorVisible; + if( !CursorVisible) CursorVisible = true; + } else { + screen.lastCursorVisible = WarningScreens[0].lastCursorVisible; + } + WarningScreens.Add( screen ); + screen.Init(); + } + public void SetCamera( bool thirdPerson ) { PerspectiveCamera oldCam = (PerspectiveCamera)Camera; Camera = (thirdPerson && CanUseThirdPersonCamera) ? diff --git a/ClassicalSharp/Network/NetworkProcessor.CPE.cs b/ClassicalSharp/Network/NetworkProcessor.CPE.cs index a65ad1ad5..0f4a1dc1c 100644 --- a/ClassicalSharp/Network/NetworkProcessor.CPE.cs +++ b/ClassicalSharp/Network/NetworkProcessor.CPE.cs @@ -290,18 +290,31 @@ namespace ClassicalSharp { TexturePackExtractor extractor = new TexturePackExtractor(); extractor.Extract( game.DefaultTexturePack, game ); } else if( Utils.IsUrlPrefix( url ) ) { - game.Animations.Dispose(); - DateTime lastModified = TextureCache.GetLastModifiedFromCache( url ); - - if( usingTexturePack ) - game.AsyncDownloader.DownloadData( url, true, "texturePack", lastModified ); - else - game.AsyncDownloader.DownloadImage( url, true, "terrain", lastModified ); - + if( !game.AcceptedUrls.HasAccepted( url ) ) { + game.ShowWarning( new WarningScreen( + game, url, DownloadTexturePack, null, + "Do you want to download the server's texture pack?", + "The texture pack is located at:", url ) ); + } else { + DownloadTexturePack( url ); + } } Utils.LogDebug( "Image url: " + url ); } + void DownloadTexturePack( object metadata ) { + string url = (string)metadata; + game.Animations.Dispose(); + DateTime lastModified = TextureCache.GetLastModifiedFromCache( url ); + if( !game.AcceptedUrls.HasAccepted( url ) ) + game.AcceptedUrls.AddAccepted( url ); + + if( usingTexturePack ) + game.AsyncDownloader.DownloadData( url, true, "texturePack", lastModified ); + else + game.AsyncDownloader.DownloadImage( url, true, "terrain", lastModified ); + } + void HandleCpeEnvWeatherType() { game.Map.SetWeather( (Weather)reader.ReadUInt8() ); } diff --git a/ClassicalSharp/TexturePack/AcceptedUrls.cs b/ClassicalSharp/TexturePack/AcceptedUrls.cs new file mode 100644 index 000000000..bc8b94a4e --- /dev/null +++ b/ClassicalSharp/TexturePack/AcceptedUrls.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace ClassicalSharp { + + public sealed class AcceptedUrls { + + List acceptedUrls = new List(); + const string folder = "texturecache", file = "acceptedurls.txt"; + + public void AddAccepted( string url ) { + acceptedUrls.Add( url ); + Save(); + } + + public bool HasAccepted( string url ) { + return acceptedUrls.Contains( url ); + } + + public bool Load() { + try { + using( Stream fs = File.OpenRead( Path.Combine( folder, file ) ) ) + using( StreamReader reader = new StreamReader( fs, false ) ) + { + string line; + while( (line = reader.ReadLine()) != null ) { + if( line.Length == 0 && line[0] == '#' ) continue; + acceptedUrls.Add( line ); + } + } + return true; + } catch( FileNotFoundException ) { + return true; + } catch( IOException ex ) { + ErrorHandler.LogError( "loading accepted urls", ex ); + return false; + } + } + + public bool Save() { + try { + if( !Directory.Exists( folder ) ) + Directory.CreateDirectory( folder ); + + using( Stream fs = File.Create( Path.Combine( folder, file ) ) ) + using( StreamWriter writer = new StreamWriter( fs ) ) + { + foreach( string value in acceptedUrls ) + writer.WriteLine( value ); + } + return true; + } catch( IOException ex ) { + ErrorHandler.LogError( "saving accepted urls", ex ); + return false; + } + } + } +} diff --git a/ClassicalSharp/Utils/Options.cs b/ClassicalSharp/Utils/Options.cs index 8d56f7777..4f741b815 100644 --- a/ClassicalSharp/Utils/Options.cs +++ b/ClassicalSharp/Utils/Options.cs @@ -97,7 +97,7 @@ namespace ClassicalSharp { static void LoadFrom( StreamReader reader ) { string line; - while( ( line = reader.ReadLine() ) != null ) { + while( (line = reader.ReadLine()) != null ) { if( line.Length == 0 && line[0] == '#' ) continue; int separatorIndex = line.IndexOf( '=' );