Add hotkey gui, workaround MCDzienny servers adding a + for classicube.net accounts.

This commit is contained in:
UnknownShadow200 2015-10-26 10:46:48 +11:00
parent e83957c685
commit a9406906cb
24 changed files with 526 additions and 143 deletions

View File

@ -0,0 +1,48 @@
using System;
using System.Drawing;
using OpenTK.Input;
namespace ClassicalSharp {
public abstract class ClickableScreen : Screen {
public ClickableScreen( Game game ) : base( game ) {
}
protected bool HandleMouseClick( Widget[] widgets, int mouseX, int mouseY, MouseButton button ) {
if( button != MouseButton.Left ) return false;
// iterate backwards (because last elements rendered are shown over others)
for( int i = widgets.Length - 1; i >= 0; i-- ) {
Widget widget = widgets[i];
if( widget != null && widget.Bounds.Contains( mouseX, mouseY ) ) {
if( widget.OnClick != null )
widget.OnClick( game, widget );
return true;
}
}
return false;
}
protected bool HandleMouseMove( Widget[] widgets, int mouseX, int mouseY ) {
for( int i = 0; i < widgets.Length; i++ ) {
if( widgets[i] == null ) continue;
widgets[i].Active = false;
}
for( int i = widgets.Length - 1; i >= 0; i-- ) {
Widget widget = widgets[i];
if( widget != null && widget.Bounds.Contains( mouseX, mouseY ) ) {
widget.Active = true;
WidgetSelected( widget );
return true;
}
}
WidgetSelected( null );
return false;
}
protected virtual void WidgetSelected( Widget widget ) {
}
}
}

View File

@ -4,7 +4,7 @@ using OpenTK.Input;
namespace ClassicalSharp { namespace ClassicalSharp {
public abstract class FilesScreen : Screen { public abstract class FilesScreen : ClickableScreen {
public FilesScreen( Game game ) : base( game ) { public FilesScreen( Game game ) : base( game ) {
} }
@ -55,12 +55,12 @@ namespace ClassicalSharp {
Anchor.Centre, Anchor.Centre, textFont, TextButtonClick ); Anchor.Centre, Anchor.Centre, textFont, TextButtonClick );
} }
ButtonWidget Make( int x, int y, string text, Action<Game, ButtonWidget> onClick ) { ButtonWidget Make( int x, int y, string text, Action<Game, Widget> onClick ) {
return ButtonWidget.Create( game, x, y, 40, 40, text, return ButtonWidget.Create( game, x, y, 40, 40, text,
Anchor.Centre, Anchor.Centre, arrowFont, onClick ); Anchor.Centre, Anchor.Centre, arrowFont, onClick );
} }
protected abstract void TextButtonClick( Game game, ButtonWidget widget ); protected abstract void TextButtonClick( Game game, Widget widget );
protected void PageClick( bool forward ) { protected void PageClick( bool forward ) {
currentIndex += forward ? 5 : -5; currentIndex += forward ? 5 : -5;
@ -88,29 +88,11 @@ namespace ClassicalSharp {
} }
public override bool HandlesMouseMove( int mouseX, int mouseY ) { public override bool HandlesMouseMove( int mouseX, int mouseY ) {
for( int i = 0; i < buttons.Length; i++ ) return HandleMouseMove( buttons, mouseX, mouseY );
buttons[i].Active = false;
for( int i = 0; i < buttons.Length; i++ ) {
ButtonWidget widget = buttons[i];
if( widget.Bounds.Contains( mouseX, mouseY ) ) {
widget.Active = true;
return true;
}
}
return false;
} }
public override bool HandlesMouseClick( int mouseX, int mouseY, MouseButton button ) { public override bool HandlesMouseClick( int mouseX, int mouseY, MouseButton button ) {
if( button != MouseButton.Left ) return false; return HandleMouseClick( buttons, mouseX, mouseY, button );
for( int i = 0; i < buttons.Length; i++ ) {
ButtonWidget widget = buttons[i];
if( widget.Bounds.Contains( mouseX, mouseY ) ) {
widget.OnClick( game, widget );
return true;
}
}
return false;
} }
public override bool HandlesAllInput { public override bool HandlesAllInput {

View File

@ -0,0 +1,310 @@
using System;
using System.Drawing;
using ClassicalSharp.Hotkeys;
using OpenTK.Input;
namespace ClassicalSharp {
// TODO: Hotkey added event for CPE
// TODO: save hotkeys
public sealed class HotkeyScreen : MenuScreen {
HotkeyList hotkeys;
public HotkeyScreen( Game game ) : base( game ) {
hotkeys = game.InputHandler.Hotkeys;
}
Font hintFont, arrowFont, textFont;
public override void Render( double delta ) {
RenderMenuBounds();
graphicsApi.Texturing = true;
RenderMenuButtons( delta );
if( currentAction != null ) {
currentAction.Render( delta );
currentMoreInputLabel.Render( delta );
}
graphicsApi.Texturing = false;
}
public override bool HandlesMouseMove( int mouseX, int mouseY ) {
return HandleMouseMove( buttons, mouseX, mouseY );
}
public override bool HandlesMouseClick( int mouseX, int mouseY, MouseButton button ) {
return HandleMouseClick( buttons, mouseX, mouseY, button );
}
bool supressNextPress;
public override bool HandlesKeyPress( char key ) {
if( supressNextPress ) {
supressNextPress = false;
return true;
}
return currentAction == null ? false :
currentAction.HandlesKeyPress( key );
}
public override bool HandlesKeyDown( Key key ) {
if( key == Key.Escape ) {
game.SetNewScreen( new NormalScreen( game ) );
return true;
} else if( focusWidget != null ) {
FocusKeyDown( key );
return true;
}
if( key == Key.Left ) {
PageClick( false );
return true;
} else if( key == Key.Right ) {
PageClick( true );
return true;
}
return currentAction == null ? false :
currentAction.HandlesKeyDown( key );
}
public override bool HandlesKeyUp( Key key ) {
return currentAction == null ? false :
currentAction.HandlesKeyUp( key );
}
public override void Init() {
game.Keyboard.KeyRepeat = true;
titleFont = new Font( "Arial", 16, FontStyle.Bold );
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 );
buttons = new [] {
MakeHotkey( 0, -160, 0 ),
MakeHotkey( 0, -120, 1 ),
MakeHotkey( 0, -80, 2 ),
MakeHotkey( 0, -40, 3 ),
MakeAddNew( 0, 0 ),
Make( -160, -80, "<", 40, 40, arrowFont, (g, w) => PageClick( false ) ),
Make( 160, -80, ">", 40, 40, arrowFont, (g, w) => PageClick( true ) ),
ButtonWidget.Create( game, 0, 5, 240, 35, "Back to menu", Anchor.Centre, Anchor.BottomOrRight,
titleFont, (g, w) => g.SetNewScreen( new PauseScreen( g ) ) ),
null, // current key
null, // current modifiers
null, // leave open current
null, // save current
null, // remove current
null,
};
}
public override void OnResize( int oldWidth, int oldHeight, int width, int height ) {
if( currentAction != null ) {
currentAction.OnResize( oldWidth, oldHeight, width, height );
currentMoreInputLabel.OnResize( oldWidth, oldHeight, width, height );
}
base.OnResize( oldWidth, oldHeight, width, height );
}
public override void Dispose() {
game.Keyboard.KeyRepeat = false;
DisposeEditingWidgets();
hintFont.Dispose();
arrowFont.Dispose();
textFont.Dispose();
base.Dispose();
}
ButtonWidget Make( int x, int y, string text, int width, int height,
Font font, Action<Game, Widget> onClick ) {
return ButtonWidget.Create( game, x, y, width, height, text,
Anchor.Centre, Anchor.Centre, font, onClick );
}
ButtonWidget MakeHotkey( int x, int y, int index ) {
string text = Get( index );
ButtonWidget button = ButtonWidget.Create(
game, x, y, 240, 30, text, Anchor.Centre, Anchor.Centre,
textFont, TextButtonClick );
if( text != "-----" )
button.Metadata = hotkeys.Hotkeys[index];
return button;
}
ButtonWidget MakeAddNew( int x, int y ) {
ButtonWidget button = ButtonWidget.Create(
game, x, y, 240, 30, "Add new", Anchor.Centre, Anchor.Centre,
textFont, TextButtonClick );
button.Metadata = default( Hotkey );
return button;
}
string Get( int index ) {
if( index >= hotkeys.Hotkeys.Count ) return "-----";
Hotkey hKey = hotkeys.Hotkeys[index];
return hKey.BaseKey + " | " + MakeFlagsString( hKey.Flags );
}
void Set( int index ) {
string text = Get( index );
ButtonWidget button = buttons[index];
button.SetText( text);
button.Metadata = null;
if( text != "-----" )
button.Metadata = hotkeys.Hotkeys[index];
}
string MakeFlagsString( byte flags ) {
if( flags == 0 ) return "None";
return ((flags & 1) == 0 ? " " : "Ctrl ") +
((flags & 2) == 0 ? " " : "Shift ") +
((flags & 4) == 0 ? " " : "Alt ");
}
int currentIndex;
void PageClick( bool forward ) {
currentIndex += forward ? 4 : -4;
if( currentIndex >= hotkeys.Hotkeys.Count ) currentIndex -= 4;
if( currentIndex < 0 ) currentIndex = 0;
LostFocus();
for( int i = 0; i < 4; i++ )
Set( currentIndex + i );
}
void TextButtonClick( Game game, Widget widget ) {
LostFocus();
ButtonWidget button = (ButtonWidget)widget;
if( button.Metadata != null ) {
curHotkey = (Hotkey)button.Metadata;
origHotkey = curHotkey;
// do stuff here
CreateEditingWidgets();
}
}
#region Modifying hotkeys
Hotkey curHotkey, origHotkey;
MenuInputWidget currentAction;
TextWidget currentMoreInputLabel;
ButtonWidget focusWidget;
void CreateEditingWidgets() {
DisposeEditingWidgets();
buttons[8] = Make( -140, 60, "Key: " + curHotkey.BaseKey,
250, 30, textFont, BaseKeyClick );
buttons[9] = Make( 140, 60, "Modifiers: " + MakeFlagsString( curHotkey.Flags ),
250, 30, textFont, ModifiersClick );
buttons[10] = Make( -10, 120, curHotkey.MoreInput ? "yes" : "no",
50, 25, textFont, LeaveOpenClick );
buttons[11] = Make( -100, 160, "Save changes",
160, 30, textFont, SaveChangesClick );
buttons[12] = Make( 100, 160, "Remove hotkey",
160, 30, textFont, RemoveHotkeyClick );
currentAction = MenuInputWidget.Create(
game, 0, 90, 600, 25, "", Anchor.Centre, Anchor.Centre,
regularFont, titleFont, hintFont, new StringValidator( 64 ) );
currentMoreInputLabel = TextWidget.Create(
game, -170, 120, "Leave open for further input:",
Anchor.Centre, Anchor.Centre, textFont );
if( curHotkey.Text == null ) curHotkey.Text = "";
currentAction.SetText( curHotkey.Text );
}
void DisposeEditingWidgets() {
if( currentAction != null ) {
currentAction.Dispose();
currentAction = null;
}
for( int i = 8; i < buttons.Length - 1; i++ ) {
if( buttons[i] != null ) {
buttons[i].Dispose();
buttons[i] = null;
}
}
focusWidget = null;
}
void LeaveOpenClick( Game game, Widget widget ) {
LostFocus();
curHotkey.MoreInput = !curHotkey.MoreInput;
buttons[10].SetText( curHotkey.MoreInput ? "yes" : "no" );
}
void SaveChangesClick( Game game, Widget widget ) {
if( origHotkey.BaseKey != Key.Unknown )
hotkeys.RemoveHotkey( origHotkey.BaseKey, origHotkey.Flags );
if( curHotkey.BaseKey != Key.Unknown )
hotkeys.AddHotkey( curHotkey.BaseKey, curHotkey.Flags,
currentAction.GetText(), curHotkey.MoreInput );
for( int i = 0; i < 4; i++ )
Set( currentIndex + i );
DisposeEditingWidgets();
}
void RemoveHotkeyClick( Game game, Widget widget ) {
if( origHotkey.BaseKey != Key.Unknown )
hotkeys.RemoveHotkey( origHotkey.BaseKey, origHotkey.Flags );
for( int i = 0; i < 4; i++ )
Set( currentIndex + i );
DisposeEditingWidgets();
}
void BaseKeyClick( Game game, Widget widget ) {
focusWidget = buttons[8];
focusWidget.SetText( "Key: press a key.." );
supressNextPress = true;
}
void ModifiersClick( Game game, Widget widget ) {
focusWidget = buttons[9];
focusWidget.SetText( "Modifiers: press a key.." );
supressNextPress = true;
}
void FocusKeyDown( Key key ) {
if( focusWidget == buttons[8] ) {
curHotkey.BaseKey = key;
buttons[8].SetText( "Key: " + curHotkey.BaseKey );
supressNextPress = true;
} else if( focusWidget == buttons[9] ) {
if( key == Key.ControlLeft || key == Key.ControlRight ) curHotkey.Flags |= 1;
else if( key == Key.ShiftLeft || key == Key.ShiftRight ) curHotkey.Flags |= 2;
else if( key == Key.AltLeft || key == Key.AltRight ) curHotkey.Flags |= 4;
else curHotkey.Flags = 0;
buttons[9].SetText( "Modifiers: " + MakeFlagsString( curHotkey.Flags ) );
supressNextPress = true;
}
focusWidget = null;
}
void LostFocus() {
if( focusWidget == null ) return;
if( focusWidget == buttons[8] ) {
buttons[8].SetText( "Key: " + curHotkey.BaseKey );
} else if( focusWidget == buttons[9] ) {
buttons[9].SetText( "Modifiers: " + MakeFlagsString( curHotkey.Flags ) );
}
focusWidget = null;
supressNextPress = false;
}
#endregion
}
}

View File

@ -71,7 +71,7 @@ namespace ClassicalSharp {
okayIndex = buttons.Length - 1; okayIndex = buttons.Length - 1;
} }
ButtonWidget Make( int x, int y, string text, Anchor vDocking, Action<Game, ButtonWidget> onClick, ButtonWidget Make( int x, int y, string text, Anchor vDocking, Action<Game, Widget> onClick,
Func<Game, string> getter, Action<Game, string> setter ) { Func<Game, string> getter, Action<Game, string> setter ) {
ButtonWidget widget = ButtonWidget.Create( game, x, y, 240, 35, text, Anchor.Centre, vDocking, titleFont, onClick ); ButtonWidget widget = ButtonWidget.Create( game, x, y, 240, 35, text, Anchor.Centre, vDocking, titleFont, onClick );
widget.GetValue = getter; widget.GetValue = getter;

View File

@ -53,10 +53,10 @@ namespace ClassicalSharp {
} }
} }
ButtonWidget widget; ButtonWidget curWidget;
void OnWidgetClick( Game game, ButtonWidget widget ) { void OnWidgetClick( Game game, Widget realWidget ) {
this.widget = widget; this.curWidget = (ButtonWidget)realWidget;
int index = Array.IndexOf<ButtonWidget>( buttons, widget ); int index = Array.IndexOf<ButtonWidget>( buttons, curWidget );
statusWidget.Dispose(); statusWidget.Dispose();
string text = "Press new key binding for " + descriptions[index] + ":"; string text = "Press new key binding for " + descriptions[index] + ":";
@ -66,8 +66,8 @@ namespace ClassicalSharp {
public override bool HandlesKeyDown( Key key ) { public override bool HandlesKeyDown( Key key ) {
if( key == Key.Escape ) { if( key == Key.Escape ) {
game.SetNewScreen( new NormalScreen( game ) ); game.SetNewScreen( new NormalScreen( game ) );
} else if( widget != null ) { } else if( curWidget != null ) {
int index = Array.IndexOf<ButtonWidget>( buttons, widget ); int index = Array.IndexOf<ButtonWidget>( buttons, curWidget );
KeyBinding mapping = (KeyBinding)index; KeyBinding mapping = (KeyBinding)index;
KeyMap map = game.InputHandler.Keys; KeyMap map = game.InputHandler.Keys;
Key oldKey = map[mapping]; Key oldKey = map[mapping];
@ -81,15 +81,15 @@ namespace ClassicalSharp {
statusWidget.SetText( String.Format( format, descriptions[index], oldKey, key ) ); statusWidget.SetText( String.Format( format, descriptions[index], oldKey, key ) );
string text = descriptions[index] + " : " + keyNames[(int)key]; string text = descriptions[index] + " : " + keyNames[(int)key];
widget.SetText( text ); curWidget.SetText( text );
map[mapping] = key; map[mapping] = key;
} }
widget = null; curWidget = null;
} }
return true; return true;
} }
ButtonWidget Make( int x, int y, string text, Anchor vDocking, Action<Game, ButtonWidget> onClick ) { ButtonWidget Make( int x, int y, string text, Anchor vDocking, Action<Game, Widget> onClick ) {
return ButtonWidget.Create( game, x, y, 240, 35, text, Anchor.Centre, vDocking, keyFont, onClick ); return ButtonWidget.Create( game, x, y, 240, 35, text, Anchor.Centre, vDocking, keyFont, onClick );
} }

View File

@ -27,13 +27,13 @@ namespace ClassicalSharp {
Make( 0, 5, "Back to menu", (g, w) => g.SetNewScreen( new PauseScreen( g ) ) ); Make( 0, 5, "Back to menu", (g, w) => g.SetNewScreen( new PauseScreen( g ) ) );
} }
ButtonWidget Make( int x, int y, string text, Action<Game, ButtonWidget> onClick ) { ButtonWidget Make( int x, int y, string text, Action<Game, Widget> onClick ) {
return ButtonWidget.Create( game, x, y, 240, 35, text, return ButtonWidget.Create( game, x, y, 240, 35, text,
Anchor.Centre, Anchor.BottomOrRight, titleFont, onClick ); Anchor.Centre, Anchor.BottomOrRight, titleFont, onClick );
} }
protected override void TextButtonClick( Game game, ButtonWidget widget ) { protected override void TextButtonClick( Game game, Widget widget ) {
string path = widget.Text; string path = ((ButtonWidget)widget).Text;
if( File.Exists( path ) ) if( File.Exists( path ) )
LoadMap( path ); LoadMap( path );
} }

View File

@ -75,11 +75,12 @@ namespace ClassicalSharp {
} }
ButtonWidget selectedWidget, targetWidget; ButtonWidget selectedWidget, targetWidget;
protected override void WidgetSelected( ButtonWidget widget ) { protected override void WidgetSelected( Widget widget ) {
if( selectedWidget == widget || widget == null || ButtonWidget button = (ButtonWidget)widget;
widget == buttons[buttons.Length - 2] ) return; if( selectedWidget == button || button == null ||
button == buttons[buttons.Length - 2] ) return;
selectedWidget = widget; selectedWidget = button;
if( targetWidget != null ) return; if( targetWidget != null ) return;
UpdateDescription( selectedWidget ); UpdateDescription( selectedWidget );
} }
@ -93,18 +94,19 @@ namespace ClassicalSharp {
descWidget = TextWidget.Create( game, 0, 100, text, Anchor.Centre, Anchor.Centre, regularFont ); descWidget = TextWidget.Create( game, 0, 100, text, Anchor.Centre, Anchor.Centre, regularFont );
} }
protected void OnWidgetClick( Game game, ButtonWidget widget ) { protected void OnWidgetClick( Game game, Widget widget ) {
if( widget == buttons[okayIndex] ) { if( widget == buttons[okayIndex] ) {
ChangeSetting(); ChangeSetting();
return; return;
} }
ButtonWidget button = (ButtonWidget)widget;
int index = Array.IndexOf<ButtonWidget>( buttons, widget ); int index = Array.IndexOf<ButtonWidget>( buttons, button );
MenuInputValidator validator = validators[index]; MenuInputValidator validator = validators[index];
if( validator is BooleanValidator ) { if( validator is BooleanValidator ) {
string value = widget.GetValue( game ); string value = button.GetValue( game );
widget.SetValue( game, value == "yes" ? "no" : "yes" ); button.SetValue( game, value == "yes" ? "no" : "yes" );
UpdateDescription( widget ); UpdateDescription( button );
return; return;
} }
@ -112,7 +114,7 @@ namespace ClassicalSharp {
inputWidget.Dispose(); inputWidget.Dispose();
targetWidget = selectedWidget; targetWidget = selectedWidget;
inputWidget = MenuInputWidget.Create( game, 0, 150, 400, 25, widget.GetValue( game ), inputWidget = MenuInputWidget.Create( game, 0, 150, 400, 25, button.GetValue( game ),
Anchor.Centre, Anchor.Centre, regularFont, titleFont, Anchor.Centre, Anchor.Centre, regularFont, titleFont,
hintFont, validator ); hintFont, validator );
buttons[okayIndex] = ButtonWidget.Create( game, 240, 150, 30, 30, "OK", buttons[okayIndex] = ButtonWidget.Create( game, 240, 150, 30, 30, "OK",

View File

@ -4,7 +4,7 @@ using OpenTK.Input;
namespace ClassicalSharp { namespace ClassicalSharp {
public abstract class MenuScreen : Screen { public abstract class MenuScreen : ClickableScreen {
public MenuScreen( Game game ) : base( game ) { public MenuScreen( Game game ) : base( game ) {
} }
@ -44,34 +44,11 @@ namespace ClassicalSharp {
} }
public override bool HandlesMouseClick( int mouseX, int mouseY, MouseButton button ) { public override bool HandlesMouseClick( int mouseX, int mouseY, MouseButton button ) {
if( button != MouseButton.Left ) return false; return HandleMouseClick( buttons, mouseX, mouseY, button );
for( int i = 0; i < buttons.Length; i++ ) {
ButtonWidget widget = buttons[i];
if( widget != null && widget.Bounds.Contains( mouseX, mouseY ) ) {
if( widget.OnClick != null )
widget.OnClick( game, widget );
return true;
}
}
return false;
} }
public override bool HandlesMouseMove( int mouseX, int mouseY ) { public override bool HandlesMouseMove( int mouseX, int mouseY ) {
for( int i = 0; i < buttons.Length; i++ ) { return HandleMouseMove( buttons, mouseX, mouseY );
if( buttons[i] == null ) continue;
buttons[i].Active = false;
}
for( int i = 0; i < buttons.Length; i++ ) {
ButtonWidget widget = buttons[i];
if( widget != null && widget.Bounds.Contains( mouseX, mouseY ) ) {
widget.Active = true;
WidgetSelected( widget );
return true;
}
}
WidgetSelected( null );
return false;
} }
public override bool HandlesKeyPress( char key ) { public override bool HandlesKeyPress( char key ) {
@ -85,8 +62,5 @@ namespace ClassicalSharp {
public override bool HandlesKeyUp( Key key ) { public override bool HandlesKeyUp( Key key ) {
return true; return true;
} }
protected virtual void WidgetSelected( ButtonWidget widget ) {
}
} }
} }

View File

@ -79,7 +79,7 @@ namespace ClassicalSharp {
okayIndex = buttons.Length - 1; okayIndex = buttons.Length - 1;
} }
ButtonWidget Make( int x, int y, string text, Anchor vDocking, Action<Game, ButtonWidget> onClick, ButtonWidget Make( int x, int y, string text, Anchor vDocking, Action<Game, Widget> onClick,
Func<Game, string> getter, Action<Game, string> setter ) { Func<Game, string> getter, Action<Game, string> setter ) {
ButtonWidget widget = ButtonWidget.Create( game, x, y, 240, 35, text, Anchor.Centre, vDocking, titleFont, onClick ); ButtonWidget widget = ButtonWidget.Create( game, x, y, 240, 35, text, Anchor.Centre, vDocking, titleFont, onClick );
widget.GetValue = getter; widget.GetValue = getter;

View File

@ -18,30 +18,23 @@ namespace ClassicalSharp {
public override void Init() { public override void Init() {
titleFont = new Font( "Arial", 16, FontStyle.Bold ); titleFont = new Font( "Arial", 16, FontStyle.Bold );
if( game.Network.IsSinglePlayer ) { buttons = new ButtonWidget[] {
buttons = new ButtonWidget[] { Make( -140, -100, "Options", Anchor.Centre, (g, w) => g.SetNewScreen( new OptionsScreen( g ) ) ),
Make( -140, -50, "Options", Anchor.Centre, (g, w) => g.SetNewScreen( new OptionsScreen( g ) ) ), Make( -140, -50, "Environment settings", Anchor.Centre, (g, w) => g.SetNewScreen( new EnvSettingsScreen( g ) ) ),
Make( -140, 0, "Environment settings", Anchor.Centre, (g, w) => g.SetNewScreen( new EnvSettingsScreen( g ) ) ), Make( -140, 0, "Select texture pack", Anchor.Centre, (g, w) => g.SetNewScreen( new TexturePackScreen( g ) ) ),
Make( -140, 50, "Select texture pack", Anchor.Centre, (g, w) => g.SetNewScreen( new TexturePackScreen( g ) ) ), Make( -140, 50, "Hotkeys", Anchor.Centre, (g, w) => g.SetNewScreen( new HotkeyScreen( g ) ) ),
Make( 140, -50, "Save level", Anchor.Centre, (g, w) => g.SetNewScreen( new SaveLevelScreen( g ) ) ),
Make( 140, 0, "Load level", Anchor.Centre, (g, w) => g.SetNewScreen( new LoadLevelScreen( g ) ) ), Make( 140, -100, "Save level", Anchor.Centre, (g, w) => g.SetNewScreen( new SaveLevelScreen( g ) ) ),
// TODO: singleplayer Make( 0, 50, "Load/Save/Gen level", Docking.Centre, (g, w) => g.SetNewScreen( new SaveLevelScreen( g ) ) ), !game.Network.IsSinglePlayer ? null :
Make( 0, 55, "Back to game", Anchor.BottomOrRight, (g, w) => g.SetNewScreen( new NormalScreen( g ) ) ), Make( 140, -50, "Load level", Anchor.Centre, (g, w) => g.SetNewScreen( new LoadLevelScreen( g ) ) ),
Make( 0, 5, "Quit game", Anchor.BottomOrRight, (g, w) => g.Exit() ), // TODO: singleplayer Generate level screen
};
} else { Make( 0, 55, "Back to game", Anchor.BottomOrRight, (g, w) => g.SetNewScreen( new NormalScreen( g ) ) ),
buttons = new ButtonWidget[] { Make( 0, 5, "Quit game", Anchor.BottomOrRight, (g, w) => g.Exit() ),
Make( 0, -100, "Options", Anchor.Centre, (g, w) => g.SetNewScreen( new OptionsScreen( g ) ) ), };
Make( 0, -50, "Environment settings", Anchor.Centre, (g, w) => g.SetNewScreen( new EnvSettingsScreen( g ) ) ),
Make( 0, 0, "Select texture pack", Anchor.Centre, (g, w) => g.SetNewScreen( new TexturePackScreen( g ) ) ),
Make( 0, 50, "Save level", Anchor.Centre, (g, w) => g.SetNewScreen( new SaveLevelScreen( g ) ) ),
Make( 0, 55, "Back to game", Anchor.BottomOrRight, (g, w) => g.SetNewScreen( new NormalScreen( g ) ) ),
Make( 0, 5, "Quit game", Anchor.BottomOrRight, (g, w) => g.Exit() ),
};
}
} }
ButtonWidget Make( int x, int y, string text, Anchor vDocking, Action<Game, ButtonWidget> onClick ) { ButtonWidget Make( int x, int y, string text, Anchor vDocking, Action<Game, Widget> onClick ) {
return ButtonWidget.Create( game, x, y, 240, 35, text, Anchor.Centre, vDocking, titleFont, onClick ); return ButtonWidget.Create( game, x, y, 240, 35, text, Anchor.Centre, vDocking, titleFont, onClick );
} }

View File

@ -77,7 +77,7 @@ namespace ClassicalSharp {
base.Dispose(); base.Dispose();
} }
void OkButtonClick( Game game, ButtonWidget widget ) { void OkButtonClick( Game game, Widget widget ) {
string text = inputWidget.GetText(); string text = inputWidget.GetText();
if( text.Length == 0 ) { if( text.Length == 0 ) {
MakeDescWidget( "Please enter a filename" ); MakeDescWidget( "Please enter a filename" );

View File

@ -25,13 +25,13 @@ namespace ClassicalSharp {
Make( 0, 5, "Back to menu", (g, w) => g.SetNewScreen( new PauseScreen( g ) ) ); Make( 0, 5, "Back to menu", (g, w) => g.SetNewScreen( new PauseScreen( g ) ) );
} }
ButtonWidget Make( int x, int y, string text, Action<Game, ButtonWidget> onClick ) { ButtonWidget Make( int x, int y, string text, Action<Game, Widget> onClick ) {
return ButtonWidget.Create( game, x, y, 240, 35, text, return ButtonWidget.Create( game, x, y, 240, 35, text,
Anchor.Centre, Anchor.BottomOrRight, titleFont, onClick ); Anchor.Centre, Anchor.BottomOrRight, titleFont, onClick );
} }
protected override void TextButtonClick( Game game, ButtonWidget widget ) { protected override void TextButtonClick( Game game, Widget widget ) {
string path = widget.Text; string path = ((ButtonWidget)widget).Text;
if( File.Exists( path ) ) { if( File.Exists( path ) ) {
TexturePackExtractor extractor = new TexturePackExtractor(); TexturePackExtractor extractor = new TexturePackExtractor();
extractor.Extract( path, game ); extractor.Extract( path, game );

View File

@ -11,15 +11,13 @@ namespace ClassicalSharp {
} }
public static ButtonWidget Create( Game game, int x, int y, int width, int height, string text, Anchor horizontal, public static ButtonWidget Create( Game game, int x, int y, int width, int height, string text, Anchor horizontal,
Anchor vertical, Font font, Action<Game, ButtonWidget> onClick ) { Anchor vertical, Font font, Action<Game, Widget> onClick ) {
ButtonWidget widget = new ButtonWidget( game, font ); ButtonWidget widget = new ButtonWidget( game, font );
widget.Init(); widget.Init();
widget.HorizontalAnchor = horizontal; widget.HorizontalAnchor = horizontal;
widget.VerticalAnchor = vertical; widget.VerticalAnchor = vertical;
widget.XOffset = x; widget.XOffset = x; widget.YOffset = y;
widget.YOffset = y; widget.DesiredMaxWidth = width; widget.DesiredMaxHeight = height;
widget.DesiredMaxWidth = width;
widget.DesiredMaxHeight = height;
widget.SetText( text ); widget.SetText( text );
widget.OnClick = onClick; widget.OnClick = onClick;
return widget; return widget;
@ -75,10 +73,8 @@ namespace ClassicalSharp {
Y = newY; Y = newY;
} }
public Action<Game, ButtonWidget> OnClick;
public Func<Game, string> GetValue; public Func<Game, string> GetValue;
public Action<Game, string> SetValue; public Action<Game, string> SetValue;
public bool Active;
void MakeTexture( string text ) { void MakeTexture( string text ) {
DrawTextArgs args = new DrawTextArgs( text, font, true ); DrawTextArgs args = new DrawTextArgs( text, font, true );

View File

@ -126,4 +126,21 @@ namespace ClassicalSharp {
return s == "yes" || s == "no"; return s == "yes" || s == "no";
} }
} }
public sealed class StringValidator : MenuInputValidator {
int maxLen;
public StringValidator( int len ) {
Range = "&7(Enter text)";
maxLen = len;
}
public override bool IsValidChar( char c ) {
return !(c < ' ' || c == '&' || c > '~');
}
public override bool IsValidString( string s ) {
return s.Length <= maxLen;
}
}
} }

View File

@ -11,6 +11,12 @@ namespace ClassicalSharp {
VerticalAnchor = Anchor.LeftOrTop; VerticalAnchor = Anchor.LeftOrTop;
} }
/// <summary> Whether this widget is currently being moused over. </summary>
public bool Active;
/// <summary> Invoked when this widget is clicked on. Can be left null. </summary>
public Action<Game, Widget> OnClick;
/// <summary> Horizontal coordinate of top left corner in window space. </summary> /// <summary> Horizontal coordinate of top left corner in window space. </summary>
public int X; public int X;

View File

@ -82,9 +82,11 @@
<Compile Include="2D\Drawing\IDrawer2D.cs" /> <Compile Include="2D\Drawing\IDrawer2D.cs" />
<Compile Include="2D\Screens\BlockSelectScreen.cs" /> <Compile Include="2D\Screens\BlockSelectScreen.cs" />
<Compile Include="2D\Screens\ChatScreen.cs" /> <Compile Include="2D\Screens\ChatScreen.cs" />
<Compile Include="2D\Screens\ClickableScreen.cs" />
<Compile Include="2D\Screens\ErrorScreen.cs" /> <Compile Include="2D\Screens\ErrorScreen.cs" />
<Compile Include="2D\Screens\FilesScreen.cs" /> <Compile Include="2D\Screens\FilesScreen.cs" />
<Compile Include="2D\Screens\FpsScreen.cs" /> <Compile Include="2D\Screens\FpsScreen.cs" />
<Compile Include="2D\Screens\HotkeyScreen.cs" />
<Compile Include="2D\Screens\LoadingMapScreen.cs" /> <Compile Include="2D\Screens\LoadingMapScreen.cs" />
<Compile Include="2D\Screens\Menu\EnvSettingsScreen.cs" /> <Compile Include="2D\Screens\Menu\EnvSettingsScreen.cs" />
<Compile Include="2D\Screens\Menu\KeyBindingsScreen.cs" /> <Compile Include="2D\Screens\Menu\KeyBindingsScreen.cs" />

View File

@ -17,6 +17,7 @@ namespace ClassicalSharp.Commands {
RegisterCommand( new HelpCommand() ); RegisterCommand( new HelpCommand() );
RegisterCommand( new InfoCommand() ); RegisterCommand( new InfoCommand() );
RegisterCommand( new RenderTypeCommand() ); RegisterCommand( new RenderTypeCommand() );
RegisterCommand( new HotkeyCommand() );
} }
public void RegisterCommand( Command command ) { public void RegisterCommand( Command command ) {

View File

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using ClassicalSharp.Renderers; using ClassicalSharp.Renderers;
using OpenTK.Input;
namespace ClassicalSharp.Commands { namespace ClassicalSharp.Commands {
@ -100,6 +101,46 @@ namespace ClassicalSharp.Commands {
} }
} }
public sealed class HotkeyCommand : Command {
public HotkeyCommand() {
Name = "Hotkey";
Help = new [] {
"&a/client hotkey [key] [modifiers] [more] [action]",
};
}
public override void Execute( CommandReader reader ) {
Key key;
byte modifiers;
bool more;
if( !reader.NextOf( out key, ParseKey ) ||
!reader.NextOf( out modifiers, Byte.TryParse ) ||
!reader.NextOf( out more, Boolean.TryParse ) ) {
game.Chat.Add( "NOPE!" );
return;
}
string action = reader.NextAll();
if( action != null ) {
game.InputHandler.Hotkeys
.AddHotkey( key, modifiers, action, more );
game.Chat.Add( "Added" );
}
}
bool ParseKey( string value, out Key key ) {
try {
key = (Key)Enum.Parse( typeof( Key ), value, true );
return true;
} catch {
key = Key.Unknown;
return false;
}
}
}
public sealed class RenderTypeCommand : Command { public sealed class RenderTypeCommand : Command {
public RenderTypeCommand() { public RenderTypeCommand() {

View File

@ -7,14 +7,7 @@ namespace ClassicalSharp.Hotkeys {
/// <summary> Maintains the list of hotkeys defined by the client and by SetTextHotkey packets. </summary> /// <summary> Maintains the list of hotkeys defined by the client and by SetTextHotkey packets. </summary>
public sealed class HotkeyList { public sealed class HotkeyList {
struct Hotkey { public List<Hotkey> Hotkeys = new List<Hotkey>();
public Key BaseKey;
public byte Flags; // ctrl 1, shift 2, alt 4
public string Text; // contents to copy directly into the input bar
public bool MoreInput; // whether the user is able to enter further input
}
List<Hotkey> hotkeys = new List<Hotkey>();
/// <summary> Creates or updates an existing hotkey with the given baseKey and modifier flags. </summary> /// <summary> Creates or updates an existing hotkey with the given baseKey and modifier flags. </summary>
public void AddHotkey( Key baseKey, byte flags, string text, bool more ) { public void AddHotkey( Key baseKey, byte flags, string text, bool more ) {
@ -26,10 +19,10 @@ namespace ClassicalSharp.Hotkeys {
/// <returns> Whether a hotkey with the given baseKey and modifier flags was found /// <returns> Whether a hotkey with the given baseKey and modifier flags was found
/// and subsequently removed. </returns> /// and subsequently removed. </returns>
public bool RemoveHotkey( Key baseKey, byte flags ) { public bool RemoveHotkey( Key baseKey, byte flags ) {
for( int i = 0; i < hotkeys.Count; i++ ) { for( int i = 0; i < Hotkeys.Count; i++ ) {
Hotkey hKey = hotkeys[i]; Hotkey hKey = Hotkeys[i];
if( hKey.BaseKey == baseKey && hKey.Flags == flags ) { if( hKey.BaseKey == baseKey && hKey.Flags == flags ) {
hotkeys.RemoveAt( i ); Hotkeys.RemoveAt( i );
return true; return true;
} }
} }
@ -37,12 +30,12 @@ namespace ClassicalSharp.Hotkeys {
} }
bool UpdateExistingHotkey( Key baseKey, byte flags, string text, bool more ) { bool UpdateExistingHotkey( Key baseKey, byte flags, string text, bool more ) {
for( int i = 0; i < hotkeys.Count; i++ ) { for( int i = 0; i < Hotkeys.Count; i++ ) {
Hotkey hKey = hotkeys[i]; Hotkey hKey = Hotkeys[i];
if( hKey.BaseKey == baseKey && hKey.Flags == flags ) { if( hKey.BaseKey == baseKey && hKey.Flags == flags ) {
hKey.Text = text; hKey.Text = text;
hKey.MoreInput = more; hKey.MoreInput = more;
hotkeys[i] = hKey; Hotkeys[i] = hKey;
return true; return true;
} }
} }
@ -55,9 +48,10 @@ namespace ClassicalSharp.Hotkeys {
hotkey.Flags = flags; hotkey.Flags = flags;
hotkey.Text = text; hotkey.Text = text;
hotkey.MoreInput = more; hotkey.MoreInput = more;
hotkeys.Add( hotkey );
Hotkeys.Add( hotkey );
// sort so that hotkeys with largest modifiers are first // sort so that hotkeys with largest modifiers are first
hotkeys.Sort( (a, b) => b.Flags.CompareTo( a.Flags ) ); Hotkeys.Sort( (a, b) => b.Flags.CompareTo( a.Flags ) );
} }
/// <summary> Determines whether a hotkey is active based on the given key, /// <summary> Determines whether a hotkey is active based on the given key,
@ -69,7 +63,7 @@ namespace ClassicalSharp.Hotkeys {
if( keyboard[Key.ShiftLeft] || keyboard[Key.ShiftRight] ) flags |= 2; if( keyboard[Key.ShiftLeft] || keyboard[Key.ShiftRight] ) flags |= 2;
if( keyboard[Key.AltLeft] || keyboard[Key.AltRight] ) flags |= 4; if( keyboard[Key.AltLeft] || keyboard[Key.AltRight] ) flags |= 4;
foreach( Hotkey hKey in hotkeys ) { foreach( Hotkey hKey in Hotkeys ) {
if( (hKey.Flags & flags) == hKey.Flags && hKey.BaseKey == key ) { if( (hKey.Flags & flags) == hKey.Flags && hKey.BaseKey == key ) {
text = hKey.Text; text = hKey.Text;
moreInput = hKey.MoreInput; moreInput = hKey.MoreInput;
@ -82,4 +76,11 @@ namespace ClassicalSharp.Hotkeys {
return false; return false;
} }
} }
public struct Hotkey {
public Key BaseKey;
public byte Flags; // ctrl 1, shift 2, alt 4
public string Text; // contents to copy directly into the input bar
public bool MoreInput; // whether the user is able to enter further input
}
} }

View File

@ -140,18 +140,20 @@ namespace ClassicalSharp {
Console.WriteLine( "CPE Hotkey added: " + key + "," + keyMods + " : " + action ); Console.WriteLine( "CPE Hotkey added: " + key + "," + keyMods + " : " + action );
if( action == "" ) { if( action == "" ) {
game.InputHandler.Hotkeys.RemoveHotkey( key, keyMods ); game.InputHandler.Hotkeys.RemoveHotkey( key, keyMods );
} else if( action[action.Length - 1] == '\n' ) { // more input needed by user } else if( action[action.Length - 1] == '\n' ) {
action = action.Substring( 0, action.Length - 1 ); action = action.Substring( 0, action.Length - 1 );
game.InputHandler.Hotkeys.AddHotkey( key, keyMods, action, true );
} else {
game.InputHandler.Hotkeys.AddHotkey( key, keyMods, action, false ); game.InputHandler.Hotkeys.AddHotkey( key, keyMods, action, false );
} else { // more input needed by user
game.InputHandler.Hotkeys.AddHotkey( key, keyMods, action, true );
} }
} }
void HandleCpeExtAddPlayerName() { void HandleCpeExtAddPlayerName() {
short nameId = reader.ReadInt16(); short nameId = reader.ReadInt16();
string playerName = Utils.StripColours( reader.ReadAsciiString() ); string playerName = Utils.StripColours( reader.ReadAsciiString() );
playerName = Utils.RemoveEndPlus( playerName );
string listName = reader.ReadAsciiString(); string listName = reader.ReadAsciiString();
listName = Utils.RemoveEndPlus( listName );
string groupName = reader.ReadAsciiString(); string groupName = reader.ReadAsciiString();
byte groupRank = reader.ReadUInt8(); byte groupRank = reader.ReadUInt8();
@ -159,7 +161,6 @@ namespace ClassicalSharp {
CpeListInfo oldInfo = game.CpePlayersList[nameId]; CpeListInfo oldInfo = game.CpePlayersList[nameId];
CpeListInfo info = new CpeListInfo( (byte)nameId, playerName, listName, groupName, groupRank ); CpeListInfo info = new CpeListInfo( (byte)nameId, playerName, listName, groupName, groupRank );
game.CpePlayersList[nameId] = info; game.CpePlayersList[nameId] = info;
//Console.WriteLine( nameId + ": " + groupRank + " , " + groupName + " : " + listName );
if( oldInfo != null ) { if( oldInfo != null ) {
game.Events.RaiseCpeListInfoChanged( (byte)nameId ); game.Events.RaiseCpeListInfoChanged( (byte)nameId );
@ -172,7 +173,9 @@ namespace ClassicalSharp {
void HandleCpeExtAddEntity() { void HandleCpeExtAddEntity() {
byte entityId = reader.ReadUInt8(); byte entityId = reader.ReadUInt8();
string displayName = reader.ReadAsciiString(); string displayName = reader.ReadAsciiString();
displayName = Utils.RemoveEndPlus( displayName );
string skinName = reader.ReadAsciiString(); string skinName = reader.ReadAsciiString();
skinName = Utils.RemoveEndPlus( skinName );
AddEntity( entityId, displayName, skinName, false ); AddEntity( entityId, displayName, skinName, false );
} }

View File

@ -99,7 +99,7 @@ namespace ClassicalSharp {
reader.ReadPendingData(); reader.ReadPendingData();
} catch( IOException ex ) { } catch( IOException ex ) {
ErrorHandler.LogError( "reading packets", ex ); ErrorHandler.LogError( "reading packets", ex );
game.Disconnect( "&eLost connection to the server", "IO error when reading packets" ); game.Disconnect( "&eLost connection to the server", "I/O error when reading packets" );
Dispose(); Dispose();
return; return;
} }
@ -205,7 +205,7 @@ namespace ClassicalSharp {
stream.Write( outBuffer, 0, packetLength ); stream.Write( outBuffer, 0, packetLength );
} catch( IOException ex ) { } catch( IOException ex ) {
ErrorHandler.LogError( "wrting packets", ex ); ErrorHandler.LogError( "wrting packets", ex );
game.Disconnect( "&eLost connection to the server", "IO Error while writing packets" ); game.Disconnect( "&eLost connection to the server", "I/O Error while writing packets" );
Dispose(); Dispose();
} }
} }
@ -334,6 +334,7 @@ namespace ClassicalSharp {
void HandleAddEntity() { void HandleAddEntity() {
byte entityId = reader.ReadUInt8(); byte entityId = reader.ReadUInt8();
string name = reader.ReadAsciiString(); string name = reader.ReadAsciiString();
name = Utils.RemoveEndPlus( name );
AddEntity( entityId, name, name, true ); AddEntity( entityId, name, name, true );
} }

View File

@ -7,18 +7,14 @@ namespace ClassicalSharp {
public float U1, V1, U2, V2; public float U1, V1, U2, V2;
public TextureRec( float u, float v, float uWidth, float vHeight ) { public TextureRec( float u, float v, float uWidth, float vHeight ) {
U1 = u; U1 = u; V1 = v;
V1 = v; U2 = u + uWidth; V2 = v + vHeight;
U2 = u + uWidth;
V2 = v + vHeight;
} }
public static TextureRec FromPoints( float u1, float u2, float v1, float v2 ) { public static TextureRec FromPoints( float u1, float u2, float v1, float v2 ) {
TextureRec rec; TextureRec rec;
rec.U1 = u1; rec.U1 = u1;rec.U2 = u2;
rec.U2 = u2; rec.V1 = v1; rec.V2 = v2;
rec.V1 = v1;
rec.V2 = v2;
return rec; return rec;
} }

View File

@ -65,6 +65,16 @@ namespace ClassicalSharp {
return new String( output, 0, usedChars ); return new String( output, 0, usedChars );
} }
/// <summary> Returns a string with a + removed if it is the last character in the string. </summary>
public static string RemoveEndPlus( string value ) {
// Some servers (e.g. MCDzienny) use a '+' at the end to distinguish classicube.net accounts
// from minecraft.net accounts. Unfortunately they also send this ending + to the client.
if( String.IsNullOrEmpty( value ) ) return value;
return value[value.Length - 1] == '+' ?
value.Substring( 0, value.Length - 1 ) : value;
}
/// <summary> Returns whether a equals b, ignoring any case differences. </summary> /// <summary> Returns whether a equals b, ignoring any case differences. </summary>
public static bool CaselessEquals( string a, string b ) { public static bool CaselessEquals( string a, string b ) {
return a.Equals( b, StringComparison.OrdinalIgnoreCase ); return a.Equals( b, StringComparison.OrdinalIgnoreCase );

View File

@ -104,7 +104,7 @@ namespace Launcher2 {
MakeButtonAt( "No", 60, 30, textFont, Anchor.Centre, MakeButtonAt( "No", 60, 30, textFont, Anchor.Centre,
50, 40, (x, y) => game.SetScreen( new MainScreen( game ) ) ); 50, 40, (x, y) => game.SetScreen( new MainScreen( game ) ) );
} else { } else {
MakeButtonAt( "Dismiss", 120, 30, textFont, Anchor.Centre, MakeButtonAt( "Cancel", 120, 30, textFont, Anchor.Centre,
0, 40, (x, y) => game.SetScreen( new MainScreen( game ) ) ); 0, 40, (x, y) => game.SetScreen( new MainScreen( game ) ) );
} }
} }