Redesign overlays. Fix 'always no' to actually work.

This commit is contained in:
UnknownShadow200 2018-03-26 19:03:19 +11:00
parent a298f55cb9
commit 59ca55a984
20 changed files with 337 additions and 426 deletions

View File

@ -424,7 +424,7 @@ namespace ClassicalSharp.Gui.Screens {
if (Utils.IsUrlPrefix(url, 0)) {
Overlay overlay = new UrlWarningOverlay(game, url);
game.Gui.ShowOverlay(overlay);
game.Gui.ShowOverlay(overlay, false);
} else if (game.ClickableChat) {
input.Append(text);
}

View File

@ -9,7 +9,7 @@ namespace ClassicalSharp.Gui.Screens {
public abstract class Overlay : MenuScreen {
public Action<Overlay> OnRenderFrame;
protected TextWidget[] labels;
protected TextWidget[] labels = new TextWidget[4];
public string[] lines = new string[4];
public string Metadata;
@ -53,37 +53,30 @@ namespace ClassicalSharp.Gui.Screens {
protected void CloseOverlay() {
Dispose();
if (game.Gui.overlays.Count > 0)
game.Gui.overlays.RemoveAt(0);
game.Gui.overlays.Remove(this);
if (game.Gui.overlays.Count == 0)
game.CursorVisible = game.realVisible;
game.Camera.RegrabMouse();
}
public abstract void RedrawText();
public abstract void MakeButtons();
protected void SetTextWidgets(string[] lines) {
if (labels != null) {
for (int i = 0; i < labels.Length; i++)
labels[i].Dispose();
public virtual void RedrawText() {
for (int i = 0; i < labels.Length; i++) {
if (labels[i] == null) continue;
labels[i].Dispose();
labels[i] = null;
}
int count = 0;
for (int i = 0; i < lines.Length; i++) {
if (lines[i] != null) count++;
}
labels = new TextWidget[count];
labels[0] = TextWidget.Create(game, lines[0], titleFont)
.SetLocation(Anchor.Centre, Anchor.Centre, 0, -120);
for (int i = 1; i < count; i++) {
for (int i = 1; i < 4; i++) {
if (lines[i] == null) continue;
labels[i] = TextWidget.Create(game, lines[i], regularFont)
.SetLocation(Anchor.Centre, Anchor.Centre, 0, -70 + 20 * i);
labels[i].Colour = new FastColour(224, 224, 224);
}
}
public abstract void MakeButtons();
}
}

View File

@ -1,14 +1,13 @@
// Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
using System;
using System.Diagnostics;
using System.Drawing;
using ClassicalSharp.Gui.Widgets;
using ClassicalSharp.Network;
using ClassicalSharp.Textures;
using OpenTK.Input;
namespace ClassicalSharp.Gui.Screens {
public delegate void WarningClickHandler(WarningOverlay screen, bool isAlways);
public sealed class UrlWarningOverlay : Overlay {
public UrlWarningOverlay(Game game, string url) : base(game) {
@ -19,10 +18,6 @@ namespace ClassicalSharp.Gui.Screens {
lines[2] = "Be careful - links from strangers may be websites that";
lines[3] = " have viruses, or things you may not want to open/see.";
}
public override void RedrawText() {
SetTextWidgets(lines);
}
public override void MakeButtons() {
DisposeWidgets(widgets);
@ -34,44 +29,84 @@ namespace ClassicalSharp.Gui.Screens {
void OpenUrl(Game g, Widget w, MouseButton btn, int x, int y) {
if (btn != MouseButton.Left) return;
CloseOverlay();
try {
Process.Start(Metadata);
} catch (Exception ex) {
ErrorHandler.LogError("UrlWarningOverlay.OpenUrl", ex);
}
CloseOverlay();
}
void AppendUrl(Game g, Widget w, MouseButton btn, int x, int y) {
if (btn != MouseButton.Left) return;
CloseOverlay();
if (game.ClickableChat) {
game.Gui.hudScreen.AppendInput(Metadata);
}
}
}
public abstract class WarningOverlay : Overlay {
public WarningOverlay(Game game) : base(game) { }
public override void MakeButtons() {
DisposeWidgets(widgets);
widgets[0] = ButtonWidget.Create(game, 160, "Yes", titleFont, OnYesClick)
.SetLocation(Anchor.Centre, Anchor.Centre, -110, 30);
widgets[1] = ButtonWidget.Create(game, 160, "No", titleFont, OnNoClick)
.SetLocation(Anchor.Centre, Anchor.Centre, 110, 30);
widgets[2] = ButtonWidget.Create(game, 160, "Always yes", titleFont, OnYesClick)
.SetLocation(Anchor.Centre, Anchor.Centre, -110, 85);
widgets[3] = ButtonWidget.Create(game, 160, "Always no", titleFont, OnNoClick)
.SetLocation(Anchor.Centre, Anchor.Centre, 110, 85);
}
protected abstract void OnYesClick(Game g, Widget w, MouseButton btn, int x, int y);
protected abstract void OnNoClick(Game g, Widget w, MouseButton btn, int x, int y);
}
public sealed class PluginOverlay : WarningOverlay {
public PluginOverlay(Game game, string plugin) : base(game) {
Metadata = plugin;
widgets = new ButtonWidget[4];
lines[0] = "&eAre you sure you want to load plugin " + plugin + " ?";
lines[1] = "Be careful - plugins from strangers may have viruses";
lines[2] = " or other malicious behaviour.";
}
protected override void OnYesClick(Game g, Widget w, MouseButton btn, int x, int y) {
if (btn != MouseButton.Left) return;
CloseOverlay();
EntryList accepted = PluginLoader.Accepted;
if (IndexOfWidget(w) >= 2 && !accepted.Has(Metadata)) accepted.Add(Metadata);
PluginLoader.Load(Metadata, true);
}
protected override void OnNoClick(Game g, Widget w, MouseButton btn, int x, int y) {
if (btn != MouseButton.Left) return;
CloseOverlay();
EntryList denied = PluginLoader.Denied;
if (IndexOfWidget(w) >= 2 && !denied.Has(Metadata)) denied.Add(Metadata);
}
}
public sealed class ConfirmDenyOverlay : Overlay {
WarningClickHandler noClick;
bool alwaysDeny;
public ConfirmDenyOverlay(Game game, string url, bool always, WarningClickHandler noClick) : base(game) {
Metadata = url;
public ConfirmDenyOverlay(Game game, bool always) : base(game) {
alwaysDeny = always;
this.noClick = noClick;
widgets = new ButtonWidget[2];
lines[0] = "&eYou might be missing out.",
lines[1] = "Texture packs can play a vital role in the look and feel of maps.",
lines[0] = "&eYou might be missing out.";
lines[1] = "Texture packs can play a vital role in the look and feel of maps.";
lines[2] = "";
lines[3] = "Sure you don't want to download the texture pack?";
}
public override void RedrawText() {
SetTextWidgets(lines);
}
public override void MakeButtons() {
DisposeWidgets(widgets);
widgets[0] = ButtonWidget.Create(game, 160, "I'm sure", titleFont, ConfirmNoClick)
@ -82,101 +117,72 @@ namespace ClassicalSharp.Gui.Screens {
void ConfirmNoClick(Game g, Widget w, MouseButton btn, int x, int y) {
if (btn != MouseButton.Left) return;
noClick(this, alwaysDeny);
CloseOverlay();
string url = Metadata.Substring(3);
if (alwaysDeny && !game.DeniedUrls.Has(url)) {
game.DeniedUrls.Add(url);
}
}
void GoBackClick(Game g, Widget w, MouseButton btn, int x, int y) {
if (btn != MouseButton.Left) return;
// TODO: Do the back thingy here
CloseOverlay();
Overlay overlay = new TexPackOverlay(game, Metadata.Substring(3));
game.Gui.ShowOverlay(overlay, true);
}
}
public sealed class WarningOverlay : Overlay {
public WarningOverlay(Game game, bool showAlways, bool confirmNo) : base(game) {
this.confirmNo = confirmNo;
this.showAlways = showAlways;
}
public void SetHandlers(WarningClickHandler yesClick,
WarningClickHandler noClick) {
this.yesClick = yesClick;
this.noClick = noClick;
}
bool confirmNo, confirmingMode, showAlways;
int alwaysIndex = 100;
public sealed class TexPackOverlay : WarningOverlay {
public override void RedrawText() {
if (confirmingMode) {
SetTextWidgets(new string[] {
"&eYou might be missing out.",
"Texture packs can play a vital role in the look and feel of maps.",
"", "Sure you don't want to download the texture pack?"});
} else {
SetTextWidgets(lines);
}
public TexPackOverlay(Game game, string url) : base(game) {
string address = url;
if (url.StartsWith("https://")) address = url.Substring(8);
if (url.StartsWith("http://")) address = url.Substring(7);
Metadata = "CL_" + url;
OnRenderFrame = TexPackTick;
widgets = new ButtonWidget[4];
lines[0] = "Do you want to download the server's texture pack?";
lines[1] = "Texture pack url:";
lines[2] = address;
lines[3] = "Download size: Determining...";
}
public override void MakeButtons() {
DisposeWidgets(widgets);
alwaysIndex = 100;
if (confirmingMode) {
widgets = new ButtonWidget[2];
widgets[0] = ButtonWidget.Create(game, 160, "I'm sure", titleFont, OnNoClick)
.SetLocation(Anchor.Centre, Anchor.Centre, -110, 30);
widgets[1] = ButtonWidget.Create(game, 160, "Go back", titleFont, GoBackClick)
.SetLocation(Anchor.Centre, Anchor.Centre, 110, 30);
return;
}
widgets = new ButtonWidget[showAlways ? 4 : 2];
widgets[0] = ButtonWidget.Create(game, 160, "Yes", titleFont, OnYesClick)
.SetLocation(Anchor.Centre, Anchor.Centre, -110, 30);
widgets[1] = ButtonWidget.Create(game, 160, "No", titleFont, OnNoClick)
.SetLocation(Anchor.Centre, Anchor.Centre, 110, 30);
if (!showAlways) return;
alwaysIndex = 2;
widgets[2] = ButtonWidget.Create(game, 160, "Always yes", titleFont, OnYesClick)
.SetLocation(Anchor.Centre, Anchor.Centre, -110, 85);
widgets[3] = ButtonWidget.Create(game, 160, "Always no", titleFont, OnNoClick)
.SetLocation(Anchor.Centre, Anchor.Centre, 110, 85);
}
WarningClickHandler yesClick, noClick;
void OnYesClick(Game g, Widget w, MouseButton btn, int x, int y) {
protected override void OnYesClick(Game g, Widget w, MouseButton btn, int x, int y) {
if (btn != MouseButton.Left) return;
bool always = IndexOfWidget(w) >= alwaysIndex;
CloseOverlay();
string url = Metadata.Substring(3);
if (yesClick != null) yesClick(this, always);
game.Server.DownloadTexturePack(url);
if (IndexOfWidget(w) >= 2 && !game.AcceptedUrls.Has(url)) {
game.AcceptedUrls.Add(url);
}
}
protected override void OnNoClick(Game g, Widget w, MouseButton btn, int x, int y) {
if (btn != MouseButton.Left) return;
CloseOverlay();
string url = Metadata.Substring(3);
ConfirmDenyOverlay overlay = new ConfirmDenyOverlay(game, IndexOfWidget(w) >= 2);
overlay.Metadata = Metadata;
game.Gui.ShowOverlay(overlay, true);
}
void OnNoClick(Game g, Widget w, MouseButton btn, int x, int y) {
if (btn != MouseButton.Left) return;
bool always = IndexOfWidget(w) >= alwaysIndex;
void TexPackTick(Overlay warning) {
string identifier = warning.Metadata;
Request item;
if (!game.Downloader.TryGetItem(identifier, out item) || item.Data == null) return;
if (confirmNo && !confirmingMode) {
confirmingMode = true;
ContextRecreated();
return;
}
long contentLength = (long)item.Data;
if (contentLength <= 0) return;
string url = identifier.Substring(3);
if (noClick != null) noClick(this, always);
CloseOverlay();
}
void GoBackClick(Game g, Widget w, MouseButton btn, int x, int y) {
if (btn != MouseButton.Left) return;
confirmingMode = false;
ContextRecreated();
float contentLengthMB = (contentLength / 1024f / 1024f);
warning.lines[3] = "Download size: " + contentLengthMB.ToString("F3") + " MB";
warning.RedrawText();
}
}
}

View File

@ -90,7 +90,7 @@
<Compile Include="2D\Screens\InventoryScreen.cs" />
<Compile Include="2D\Screens\Overlays\Overlay.cs" />
<Compile Include="2D\Screens\Overlays\TexIdsOverlay.cs" />
<Compile Include="2D\Screens\Overlays\WarningOverlay.cs" />
<Compile Include="2D\Screens\Overlays\WarningOverlays.cs" />
<Compile Include="2D\Screens\StatusScreen.cs" />
<Compile Include="2D\Screens\LoadingMapScreen.cs" />
<Compile Include="2D\Screens\MenuScreen.cs" />

View File

@ -130,8 +130,8 @@ namespace ClassicalSharp {
AxisLinesRenderer = new AxisLinesRenderer(); Components.Add(AxisLinesRenderer);
SkyboxRenderer = new SkyboxRenderer(); Components.Add(SkyboxRenderer);
plugins = new PluginLoader(this);
List<string> nonLoaded = plugins.LoadAll();
PluginLoader.game = this;
List<string> nonLoaded = PluginLoader.LoadAll();
for (int i = 0; i < Components.Count; i++)
Components[i].Init(this);
@ -142,7 +142,8 @@ namespace ClassicalSharp {
if (nonLoaded != null) {
for (int i = 0; i < nonLoaded.Count; i++) {
plugins.MakeWarning(this, nonLoaded[i]);
Overlay warning = new PluginOverlay(this, nonLoaded[i]);
Gui.ShowOverlay(warning, false);
}
}

View File

@ -205,8 +205,6 @@ namespace ClassicalSharp {
internal EntryList ETags = new EntryList("texturecache", "etags.txt");
internal EntryList LastModified = new EntryList("texturecache", "lastmodified.txt");
PluginLoader plugins;
/// <summary> Calculates the amount that the hotbar widget should be scaled by when rendered. </summary>
/// <remarks> Affected by both the current resolution of the window, as well as the
/// scaling specified by the user (field HotbarScale). </remarks>

View File

@ -97,10 +97,15 @@ namespace ClassicalSharp {
public void RefreshHud() { hudScreen.Recreate(); }
public void ShowOverlay(Overlay overlay) {
public void ShowOverlay(Overlay overlay, bool inFront) {
bool cursorVis = game.CursorVisible;
if (overlays.Count == 0) game.CursorVisible = true;
overlays.Add(overlay);
if (inFront) {
overlays.Insert(0, overlay);
} else {
overlays.Add(overlay);
}
if (overlays.Count == 1) game.CursorVisible = cursorVis;
// Save cursor visibility state
overlay.Init();

View File

@ -246,7 +246,7 @@ namespace ClassicalSharp {
} else if (game.Mode.HandlesKeyDown(key)) {
} else if (key == Keys[KeyBind.IDOverlay]) {
if (game.Gui.overlays.Count > 0) return true;
game.Gui.ShowOverlay(new TexIdsOverlay(game));
game.Gui.ShowOverlay(new TexIdsOverlay(game), false);
} else {
return false;
}

View File

@ -15,65 +15,34 @@ namespace ClassicalSharp {
string ClientVersion { get; }
}
internal class PluginLoader {
internal static class PluginLoader {
EntryList accepted, denied;
Game game;
public static EntryList Accepted, Denied;
internal static Game game;
public PluginLoader(Game game) { this.game = game; }
internal List<string> LoadAll() {
internal static List<string> LoadAll() {
string dir = Path.Combine(Program.AppDirectory, "plugins");
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir);
accepted = new EntryList("plugins", "accepted.txt");
denied = new EntryList("plugins", "denied.txt");
accepted.Load();
denied.Load();
Accepted = new EntryList("plugins", "accepted.txt");
Denied = new EntryList("plugins", "denied.txt");
Accepted.Load();
Denied.Load();
return LoadPlugins(dir);
}
internal void MakeWarning(Game game, string plugin) {
WarningOverlay warning = new WarningOverlay(game, true, false);
warning.Metadata = plugin;
warning.SetHandlers(Accept, Deny);
warning.lines[0] = "&eAre you sure you want to load plugin " + plugin + " ?";
warning.lines[1] = "Be careful - plugins from strangers may have viruses";
warning.lines[2] = " or other malicious behaviour.";
game.Gui.ShowOverlay(warning);
}
void Accept(Overlay overlay, bool always) {
string plugin = overlay.Metadata;
if (always && !accepted.HasEntry(plugin)) {
accepted.AddEntry(plugin);
}
string dir = Path.Combine(Program.AppDirectory, "plugins");
Load(Path.Combine(dir, plugin + ".dll"), true);
}
void Deny(Overlay overlay, bool always) {
string plugin = overlay.Metadata;
if (always && !denied.HasEntry(plugin)) {
denied.AddEntry(plugin);
}
}
List<string> LoadPlugins(string dir) {
static List<string> LoadPlugins(string dir) {
string[] dlls = Directory.GetFiles(dir, "*.dll");
List<string> nonLoaded = null;
for (int i = 0; i < dlls.Length; i++) {
string plugin = Path.GetFileNameWithoutExtension(dlls[i]);
if (denied.HasEntry(plugin)) continue;
if (Denied.Has(plugin)) continue;
if (accepted.HasEntry(plugin)) {
Load(dlls[i], false);
if (Accepted.Has(plugin)) {
Load(plugin, false);
} else if (nonLoaded == null) {
nonLoaded = new List<string>();
nonLoaded.Add(plugin);
@ -84,8 +53,10 @@ namespace ClassicalSharp {
return nonLoaded;
}
void Load(string path, bool needsInit) {
public static void Load(string pluginName, bool needsInit) {
try {
string dir = Path.Combine(Program.AppDirectory, "plugins");
string path = Path.Combine(dir, pluginName + ".dll");
Assembly lib = Assembly.LoadFrom(path);
Type[] types = lib.GetTypes();
@ -103,8 +74,7 @@ namespace ClassicalSharp {
game.Components.Add(plugin);
}
} catch (Exception ex) {
path = Path.GetFileNameWithoutExtension(path);
ErrorHandler.LogError("PluginLoader.Load() - " + path, ex);
ErrorHandler.LogError("PluginLoader.Load() - " + pluginName, ex);
}
}

View File

@ -62,59 +62,18 @@ namespace ClassicalSharp {
protected Game game;
protected int netTicks;
protected void WarningScreenTick(Overlay warning) {
string identifier = warning.Metadata;
Request item;
if (!game.Downloader.TryGetItem(identifier, out item) || item.Data == null) return;
long contentLength = (long)item.Data;
if (contentLength <= 0) return;
string url = identifier.Substring(3);
float contentLengthMB = (contentLength / 1024f / 1024f);
warning.lines[3] = "Download size: " + contentLengthMB.ToString("F3") + " MB";
warning.RedrawText();
}
protected internal void RetrieveTexturePack(string url) {
if (!game.AcceptedUrls.HasEntry(url) && !game.DeniedUrls.HasEntry(url)) {
if (!game.AcceptedUrls.Has(url) && !game.DeniedUrls.Has(url)) {
game.Downloader.AsyncGetContentLength(url, true, "CL_" + url);
string address = url;
if (url.StartsWith("https://")) address = url.Substring(8);
if (url.StartsWith("http://")) address = url.Substring(7);
WarningOverlay warning = new WarningOverlay(game, true, true);
warning.Metadata = "CL_" + url;
warning.SetHandlers(DownloadTexturePack, SkipTexturePack);
warning.OnRenderFrame = WarningScreenTick;
warning.lines[0] = "Do you want to download the server's texture pack?";
warning.lines[1] = "Texture pack url:";
warning.lines[2] = address;
warning.lines[3] = "Download size: Determining...";
game.Gui.ShowOverlay(warning);
Overlay warning = new TexPackOverlay(game, url);
game.Gui.ShowOverlay(warning, false);
} else {
DownloadTexturePack(url);
}
}
void DownloadTexturePack(Overlay texPackOverlay, bool always) {
string url = texPackOverlay.Metadata.Substring(3);
DownloadTexturePack(url);
if (always && !game.AcceptedUrls.HasEntry(url)) {
game.AcceptedUrls.AddEntry(url);
}
}
void SkipTexturePack(Overlay texPackOverlay, bool always) {
string url = texPackOverlay.Metadata.Substring(3);
if (always && !game.DeniedUrls.HasEntry(url)) {
game.DeniedUrls.AddEntry(url);
}
}
void DownloadTexturePack(string url) {
if (game.DeniedUrls.HasEntry(url)) return;
internal void DownloadTexturePack(string url) {
if (game.DeniedUrls.Has(url)) return;
string path = TextureCache.MakePath(url), etag = null;
DateTime lastModified = DateTime.MinValue;

View File

@ -15,12 +15,12 @@ namespace ClassicalSharp.Textures {
this.file = file;
}
public void AddEntry(string entry) {
public void Add(string entry) {
Entries.Add(entry);
Save();
}
public bool HasEntry(string entry) {
public bool Has(string entry) {
return Entries.Contains(entry);
}

View File

@ -109,7 +109,7 @@ namespace ClassicalSharp.Textures {
tags.Entries[i] = crc32 + " " + data;
tags.Save(); return;
}
tags.AddEntry(crc32 + " " + data);
tags.Add(crc32 + " " + data);
}

View File

@ -152,8 +152,8 @@ void Builder_Stretch(Int32 x1, Int32 y1, Int32 z1) {
}
Builder_X = x; Builder_Y = y; Builder_Z = z;
Builder_FullBright = Block_FullBright[b];
UInt32 tileIdx = b * BLOCK_COUNT;
Builder_FullBright = Block_FullBright[b];
UInt32 tileIdx = b * BLOCK_COUNT;
/* All of these function calls are inlined as they can be called tens of millions to hundreds of millions of times. */
if (Builder_Counts[index] == 0 ||

View File

@ -204,7 +204,6 @@
<ClInclude Include="GameMode.h" />
<ClInclude Include="Gui.h" />
<ClInclude Include="HeldBlockRenderer.h" />
<ClInclude Include="Hotkeys.h" />
<ClInclude Include="IModel.h" />
<ClInclude Include="Input.h" />
<ClInclude Include="InputHandler.h" />
@ -280,7 +279,6 @@
<ClCompile Include="GameMode.c" />
<ClCompile Include="Gui.c" />
<ClCompile Include="HeldBlockRenderer.c" />
<ClCompile Include="Hotkeys.c" />
<ClCompile Include="InputHandler.c" />
<ClCompile Include="Inventory.c" />
<ClCompile Include="MapGenerator.c" />

View File

@ -369,9 +369,6 @@
<ClInclude Include="Event.h">
<Filter>Header Files\Game</Filter>
</ClInclude>
<ClInclude Include="Hotkeys.h">
<Filter>Header Files\Game</Filter>
</ClInclude>
<ClInclude Include="EntityComponents.h">
<Filter>Header Files\Entities</Filter>
</ClInclude>
@ -584,9 +581,6 @@
<ClCompile Include="Event.c">
<Filter>Source Files\Game</Filter>
</ClCompile>
<ClCompile Include="Hotkeys.c">
<Filter>Source Files\Game</Filter>
</ClCompile>
<ClCompile Include="EntityComponents.c">
<Filter>Source Files\Entities</Filter>
</ClCompile>

View File

@ -1,164 +0,0 @@
#include "Hotkeys.h"
#include "Options.h"
#include "Constants.h"
#include "Utils.h"
#include "Funcs.h"
#include "ErrorHandler.h"
UInt8 Hotkeys_LWJGL[256] = {
0, Key_Escape, Key_1, Key_2, Key_3, Key_4, Key_5, Key_6, Key_7, Key_8, Key_9, Key_0, Key_Minus, Key_Plus, Key_BackSpace, Key_Tab,
Key_Q, Key_W, Key_E, Key_R, Key_T, Key_Y, Key_U, Key_I, Key_O, Key_P, Key_BracketLeft, Key_BracketRight, Key_Enter, Key_ControlLeft, Key_A, Key_S,
Key_D, Key_F, Key_G, Key_H, Key_J, Key_K, Key_L, Key_Semicolon, Key_Quote, Key_Tilde, Key_ShiftLeft, Key_BackSlash, Key_Z, Key_X, Key_C, Key_V,
Key_B, Key_N, Key_M, Key_Comma, Key_Period, Key_Slash, Key_ShiftRight, 0, Key_AltLeft, Key_Space, Key_CapsLock, Key_F1, Key_F2, Key_F3, Key_F4, Key_F5,
Key_F6, Key_F7, Key_F8, Key_F9, Key_F10, Key_NumLock, Key_ScrollLock, Key_Keypad7, Key_Keypad8, Key_Keypad9, Key_KeypadSubtract, Key_Keypad4, Key_Keypad5, Key_Keypad6, Key_KeypadAdd, Key_Keypad1,
Key_Keypad2, Key_Keypad3, Key_Keypad0, Key_KeypadDecimal, 0, 0, 0, Key_F11, Key_F12, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, Key_F13, Key_F14, Key_F15, Key_F16, Key_F17, Key_F18, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Key_KeypadAdd, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Key_KeypadEnter, Key_ControlRight, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, Key_KeypadDivide, 0, 0, Key_AltRight, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, Key_Pause, 0, Key_Home, Key_Up, Key_PageUp, 0, Key_Left, 0, Key_Right, 0, Key_End,
Key_Down, Key_PageDown, Key_Insert, Key_Delete, 0, 0, 0, 0, 0, 0, 0, Key_WinLeft, Key_WinRight, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
void Hotkeys_QuickSort(Int32 left, Int32 right) {
HotkeyData* keys = HotkeysList; HotkeyData key;
while (left < right) {
Int32 i = left, j = right;
UInt8 pivot = keys[(i + j) / 2].Flags;
/* partition the list */
while (i <= j) {
while (pivot > keys[i].Flags) i++;
while (pivot < keys[j].Flags) j--;
QuickSort_Swap_Maybe();
}
/* recurse into the smaller subset */
QuickSort_Recurse(Hotkeys_QuickSort)
}
}
void Hotkeys_AddNewHotkey(Key baseKey, UInt8 flags, STRING_PURE String* text, bool more) {
HotkeyData hKey;
hKey.BaseKey = baseKey;
hKey.Flags = flags;
hKey.TextIndex = HotkeysText.Count;
hKey.StaysOpen = more;
if (HotkeysText.Count == HOTKEYS_MAX_COUNT) {
ErrorHandler_Fail("Cannot define more than 256 hotkeys");
}
HotkeysList[HotkeysText.Count] = hKey;
StringsBuffer_Add(&HotkeysText, text);
/* sort so that hotkeys with largest modifiers are first */
Hotkeys_QuickSort(0, HotkeysText.Count - 1);
}
void Hotkeys_Add(Key baseKey, UInt8 flags, STRING_PURE String* text, bool more) {
UInt32 i;
for (i = 0; i < HotkeysText.Count; i++) {
HotkeyData hKey = HotkeysList[i];
if (hKey.BaseKey == baseKey && hKey.Flags == flags) {
StringsBuffer_Remove(&HotkeysText, hKey.TextIndex);
HotkeysList[i].StaysOpen = more;
HotkeysList[i].TextIndex = HotkeysText.Count;
StringsBuffer_Add(&HotkeysText, text);
return;
}
}
Hotkeys_AddNewHotkey(baseKey, flags, text, more);
}
bool Hotkeys_Remove(Key baseKey, UInt8 flags) {
UInt32 i, j;
for (i = 0; i < HotkeysText.Count; i++) {
HotkeyData hKey = HotkeysList[i];
if (hKey.BaseKey == baseKey && hKey.Flags == flags) {
for (j = i + 1; j < HotkeysText.Count; j++) { HotkeysList[j - 1] = HotkeysList[j]; }
StringsBuffer_Remove(&HotkeysText, hKey.TextIndex);
HotkeysList[i].TextIndex = UInt32_MaxValue;
return true;
}
}
return false;
}
bool Hotkeys_IsHotkey(Key key, STRING_TRANSIENT String* text, bool* moreInput) {
UInt8 flags = 0;
if (Key_IsControlPressed()) flags |= 1;
if (Key_IsShiftPressed()) flags |= 2;
if (Key_IsAltPressed()) flags |= 4;
String_Clear(text);
*moreInput = false;
UInt32 i;
for (i = 0; i < HotkeysText.Count; i++) {
HotkeyData hKey = HotkeysList[i];
if ((hKey.Flags & flags) == hKey.Flags && hKey.BaseKey == key) {
String hkeyText = StringsBuffer_UNSAFE_Get(&HotkeysText, hKey.TextIndex);
String_AppendString(text, &hkeyText);
*moreInput = hKey.StaysOpen;
return true;
}
}
return false;
}
void Hotkeys_Init(void) {
StringsBuffer_Init(&HotkeysText);
String prefix = String_FromConst("hotkey-");
UInt32 i;
for (i = 0; i < Options_Keys.Count; i++) {
String key = StringsBuffer_UNSAFE_Get(&Options_Keys, i);
if (!String_CaselessStarts(&key, &prefix)) continue;
Int32 keySplit = String_IndexOf(&key, '&', prefix.length);
if (keySplit < 0) continue; /* invalid key */
String strKey = String_UNSAFE_Substring(&key, prefix.length, keySplit - prefix.length);
String strFlags = String_UNSAFE_SubstringAt(&key, keySplit + 1);
String value = StringsBuffer_UNSAFE_Get(&Options_Values, i);
Int32 valueSplit = String_IndexOf(&value, '&', 0);
if (valueSplit < 0) continue; /* invalid value */
String strMoreInput = String_UNSAFE_Substring(&value, 0, valueSplit - 0);
String strText = String_UNSAFE_SubstringAt(&value, valueSplit + 1);
/* Then try to parse the key and value */
Key hotkey = Utils_ParseEnum(&strKey, Key_Unknown, Key_Names, Array_Elems(Key_Names));
UInt8 flags; bool moreInput;
if (hotkey == Key_Unknown || strText.length == 0 || !Convert_TryParseUInt8(&strFlags, &flags)
|| !Convert_TryParseBool(&strMoreInput, &moreInput)) { continue; }
Hotkeys_Add(hotkey, flags, &strText, moreInput);
}
}
void Hotkeys_UserRemovedHotkey(Key baseKey, UInt8 flags) {
UInt8 keyBuffer[String_BufferSize(STRING_SIZE)];
String key = String_InitAndClearArray(keyBuffer);
String_AppendConst(&key, "hotkey-"); String_AppendConst(&key, Key_Names[baseKey]);
String_Append(&key, '&'); String_AppendInt32(&key, flags);
Options_Set(key.buffer, NULL);
}
void Hotkeys_UserAddedHotkey(Key baseKey, UInt8 flags, bool moreInput, STRING_PURE String* text) {
UInt8 keyBuffer[String_BufferSize(STRING_SIZE)];
String key = String_InitAndClearArray(keyBuffer);
UInt8 valueBuffer[String_BufferSize(STRING_SIZE * 2)];
String value = String_InitAndClearArray(valueBuffer);
String_AppendConst(&key, "hotkey-"); String_AppendConst(&key, Key_Names[baseKey]);
String_Append(&key, '&'); String_AppendInt32(&key, flags);
String_AppendBool(&value, moreInput); String_Append(&value, '&');
String_AppendString(&value, text);
Options_Set(key.buffer, &value);
}

View File

@ -1,32 +0,0 @@
#ifndef CC_HOTKEYS_H
#define CC_HOTKEYS_H
#include "Typedefs.h"
#include "Input.h"
#include "String.h"
/* Maintains list of hotkeys defined by the client and SetTextHotkey packets.
Copyright 2017 ClassicalSharp | Licensed under BSD-3
*/
extern UInt8 Hotkeys_LWJGL[256];
typedef struct HotkeyData_ {
UInt32 TextIndex; /* contents to copy directly into the input bar */
UInt8 BaseKey; /* Member of Key enumeration */
UInt8 Flags; /* ctrl 1, shift 2, alt 4 */
bool StaysOpen; /* whether the user is able to enter further input */
} HotkeyData;
#define HOTKEYS_MAX_COUNT 256
HotkeyData HotkeysList[HOTKEYS_MAX_COUNT];
StringsBuffer HotkeysText;
#define HOTKEYS_FLAG_CTRL 1
#define HOTKEYS_FLAG_SHIFT 2
#define HOTKEYS_FLAT_ALT 4
void Hotkeys_Add(Key baseKey, UInt8 flags, STRING_PURE String* text, bool more);
bool Hotkeys_Remove(Key baseKey, UInt8 flags);
bool Hotkeys_IsHotkey(Key key, STRING_TRANSIENT String* text, bool* moreInput);
void Hotkeys_Init(void);
void Hotkeys_UserRemovedHotkey(Key baseKey, UInt8 flags);
void Hotkeys_UserAddedHotkey(Key baseKey, UInt8 flags, bool moreInput, STRING_PURE String* text);
#endif

View File

@ -169,4 +169,163 @@ void KeyBind_Init(void) {
KeyBind_Keys[i] = KeyBind_Defaults[i];
}
KeyBind_Load();
}
UInt8 Hotkeys_LWJGL[256] = {
0, Key_Escape, Key_1, Key_2, Key_3, Key_4, Key_5, Key_6, Key_7, Key_8, Key_9, Key_0, Key_Minus, Key_Plus, Key_BackSpace, Key_Tab,
Key_Q, Key_W, Key_E, Key_R, Key_T, Key_Y, Key_U, Key_I, Key_O, Key_P, Key_BracketLeft, Key_BracketRight, Key_Enter, Key_ControlLeft, Key_A, Key_S,
Key_D, Key_F, Key_G, Key_H, Key_J, Key_K, Key_L, Key_Semicolon, Key_Quote, Key_Tilde, Key_ShiftLeft, Key_BackSlash, Key_Z, Key_X, Key_C, Key_V,
Key_B, Key_N, Key_M, Key_Comma, Key_Period, Key_Slash, Key_ShiftRight, 0, Key_AltLeft, Key_Space, Key_CapsLock, Key_F1, Key_F2, Key_F3, Key_F4, Key_F5,
Key_F6, Key_F7, Key_F8, Key_F9, Key_F10, Key_NumLock, Key_ScrollLock, Key_Keypad7, Key_Keypad8, Key_Keypad9, Key_KeypadSubtract, Key_Keypad4, Key_Keypad5, Key_Keypad6, Key_KeypadAdd, Key_Keypad1,
Key_Keypad2, Key_Keypad3, Key_Keypad0, Key_KeypadDecimal, 0, 0, 0, Key_F11, Key_F12, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, Key_F13, Key_F14, Key_F15, Key_F16, Key_F17, Key_F18, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Key_KeypadAdd, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Key_KeypadEnter, Key_ControlRight, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, Key_KeypadDivide, 0, 0, Key_AltRight, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, Key_Pause, 0, Key_Home, Key_Up, Key_PageUp, 0, Key_Left, 0, Key_Right, 0, Key_End,
Key_Down, Key_PageDown, Key_Insert, Key_Delete, 0, 0, 0, 0, 0, 0, 0, Key_WinLeft, Key_WinRight, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
void Hotkeys_QuickSort(Int32 left, Int32 right) {
HotkeyData* keys = HotkeysList; HotkeyData key;
while (left < right) {
Int32 i = left, j = right;
UInt8 pivot = keys[(i + j) / 2].Flags;
/* partition the list */
while (i <= j) {
while (pivot > keys[i].Flags) i++;
while (pivot < keys[j].Flags) j--;
QuickSort_Swap_Maybe();
}
/* recurse into the smaller subset */
QuickSort_Recurse(Hotkeys_QuickSort)
}
}
void Hotkeys_AddNewHotkey(Key baseKey, UInt8 flags, STRING_PURE String* text, bool more) {
HotkeyData hKey;
hKey.BaseKey = baseKey;
hKey.Flags = flags;
hKey.TextIndex = HotkeysText.Count;
hKey.StaysOpen = more;
if (HotkeysText.Count == HOTKEYS_MAX_COUNT) {
ErrorHandler_Fail("Cannot define more than 256 hotkeys");
}
HotkeysList[HotkeysText.Count] = hKey;
StringsBuffer_Add(&HotkeysText, text);
/* sort so that hotkeys with largest modifiers are first */
Hotkeys_QuickSort(0, HotkeysText.Count - 1);
}
void Hotkeys_Add(Key baseKey, UInt8 flags, STRING_PURE String* text, bool more) {
UInt32 i;
for (i = 0; i < HotkeysText.Count; i++) {
HotkeyData hKey = HotkeysList[i];
if (hKey.BaseKey == baseKey && hKey.Flags == flags) {
StringsBuffer_Remove(&HotkeysText, hKey.TextIndex);
HotkeysList[i].StaysOpen = more;
HotkeysList[i].TextIndex = HotkeysText.Count;
StringsBuffer_Add(&HotkeysText, text);
return;
}
}
Hotkeys_AddNewHotkey(baseKey, flags, text, more);
}
bool Hotkeys_Remove(Key baseKey, UInt8 flags) {
UInt32 i, j;
for (i = 0; i < HotkeysText.Count; i++) {
HotkeyData hKey = HotkeysList[i];
if (hKey.BaseKey == baseKey && hKey.Flags == flags) {
for (j = i + 1; j < HotkeysText.Count; j++) { HotkeysList[j - 1] = HotkeysList[j]; }
StringsBuffer_Remove(&HotkeysText, hKey.TextIndex);
HotkeysList[i].TextIndex = UInt32_MaxValue;
return true;
}
}
return false;
}
bool Hotkeys_IsHotkey(Key key, STRING_TRANSIENT String* text, bool* moreInput) {
UInt8 flags = 0;
if (Key_IsControlPressed()) flags |= HOTKEYS_FLAG_CTRL;
if (Key_IsShiftPressed()) flags |= HOTKEYS_FLAG_SHIFT;
if (Key_IsAltPressed()) flags |= HOTKEYS_FLAT_ALT;
String_Clear(text);
*moreInput = false;
UInt32 i;
for (i = 0; i < HotkeysText.Count; i++) {
HotkeyData hKey = HotkeysList[i];
if ((hKey.Flags & flags) == hKey.Flags && hKey.BaseKey == key) {
String hkeyText = StringsBuffer_UNSAFE_Get(&HotkeysText, hKey.TextIndex);
String_AppendString(text, &hkeyText);
*moreInput = hKey.StaysOpen;
return true;
}
}
return false;
}
void Hotkeys_Init(void) {
StringsBuffer_Init(&HotkeysText);
String prefix = String_FromConst("hotkey-");
UInt32 i;
for (i = 0; i < Options_Keys.Count; i++) {
String key = StringsBuffer_UNSAFE_Get(&Options_Keys, i);
if (!String_CaselessStarts(&key, &prefix)) continue;
Int32 keySplit = String_IndexOf(&key, '&', prefix.length);
if (keySplit < 0) continue; /* invalid key */
String strKey = String_UNSAFE_Substring(&key, prefix.length, keySplit - prefix.length);
String strFlags = String_UNSAFE_SubstringAt(&key, keySplit + 1);
String value = StringsBuffer_UNSAFE_Get(&Options_Values, i);
Int32 valueSplit = String_IndexOf(&value, '&', 0);
if (valueSplit < 0) continue; /* invalid value */
String strMoreInput = String_UNSAFE_Substring(&value, 0, valueSplit - 0);
String strText = String_UNSAFE_SubstringAt(&value, valueSplit + 1);
/* Then try to parse the key and value */
Key hotkey = Utils_ParseEnum(&strKey, Key_Unknown, Key_Names, Array_Elems(Key_Names));
UInt8 flags; bool moreInput;
if (hotkey == Key_Unknown || strText.length == 0 || !Convert_TryParseUInt8(&strFlags, &flags)
|| !Convert_TryParseBool(&strMoreInput, &moreInput)) { continue; }
Hotkeys_Add(hotkey, flags, &strText, moreInput);
}
}
void Hotkeys_UserRemovedHotkey(Key baseKey, UInt8 flags) {
UInt8 keyBuffer[String_BufferSize(STRING_SIZE)];
String key = String_InitAndClearArray(keyBuffer);
String_AppendConst(&key, "hotkey-"); String_AppendConst(&key, Key_Names[baseKey]);
String_Append(&key, '&'); String_AppendInt32(&key, flags);
Options_Set(key.buffer, NULL);
}
void Hotkeys_UserAddedHotkey(Key baseKey, UInt8 flags, bool moreInput, STRING_PURE String* text) {
UInt8 keyBuffer[String_BufferSize(STRING_SIZE)];
String key = String_InitAndClearArray(keyBuffer);
UInt8 valueBuffer[String_BufferSize(STRING_SIZE * 2)];
String value = String_InitAndClearArray(valueBuffer);
String_AppendConst(&key, "hotkey-"); String_AppendConst(&key, Key_Names[baseKey]);
String_Append(&key, '&'); String_AppendInt32(&key, flags);
String_AppendBool(&value, moreInput); String_Append(&value, '&');
String_AppendString(&value, text);
Options_Set(key.buffer, &value);
}

View File

@ -1,6 +1,7 @@
#ifndef CC_INPUT_H
#define CC_INPUT_H
#include "Typedefs.h"
#include"String.h"
/* Manages the keyboard, and raises events when keys are pressed etc.
Copyright 2017 ClassicalSharp | Licensed under BSD-3 | Based on OpenTK code
*/
@ -114,4 +115,27 @@ bool KeyBind_IsPressed(KeyBind binding);
void KeyBind_Set(KeyBind binding, Key key);
/* Initalises and loads key bindings. */
void KeyBind_Init(void);
extern UInt8 Hotkeys_LWJGL[256];
typedef struct HotkeyData_ {
UInt32 TextIndex; /* contents to copy directly into the input bar */
UInt8 BaseKey; /* Member of Key enumeration */
UInt8 Flags; /* ctrl 1, shift 2, alt 4 */
bool StaysOpen; /* whether the user is able to enter further input */
} HotkeyData;
#define HOTKEYS_MAX_COUNT 256
HotkeyData HotkeysList[HOTKEYS_MAX_COUNT];
StringsBuffer HotkeysText;
#define HOTKEYS_FLAG_CTRL 1
#define HOTKEYS_FLAG_SHIFT 2
#define HOTKEYS_FLAT_ALT 4
void Hotkeys_Add(Key baseKey, UInt8 flags, STRING_PURE String* text, bool more);
bool Hotkeys_Remove(Key baseKey, UInt8 flags);
bool Hotkeys_IsHotkey(Key key, STRING_TRANSIENT String* text, bool* moreInput);
void Hotkeys_Init(void);
void Hotkeys_UserRemovedHotkey(Key baseKey, UInt8 flags);
void Hotkeys_UserAddedHotkey(Key baseKey, UInt8 flags, bool moreInput, STRING_PURE String* text);
#endif

View File

@ -54,7 +54,7 @@ UInt16 PingList_NextPingData(void) {
PingList_Entries[i] = PingList_Entries[i + 1];
}
Int32 j = Array_Elems(PingList_Entries) - 1;
return PingList_SetTwoWayPing(j, PingList_Entries[j].Data);
return PingList_Set(j, PingList_Entries[j].Data);
}
void PingList_Update(UInt16 data) {