Skip to content

Commit 4a550c2

Browse files
committed
FPS counter
1 parent fb11200 commit 4a550c2

File tree

15 files changed

+175
-35
lines changed

15 files changed

+175
-35
lines changed

Intersect.Client.Core/Interface/Debugging/DebugWindow.cs

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System.Diagnostics;
22
using Intersect.Client.Core;
33
using Intersect.Client.Framework.Content;
4+
using Intersect.Client.Framework.File_Management;
45
using Intersect.Client.Framework.GenericClasses;
56
using Intersect.Client.Framework.Graphics;
67
using Intersect.Client.Framework.Gwen;
@@ -452,9 +453,9 @@ private LabeledCheckBox CreateInfoCheckboxDrawDebugOutlines(Base parent)
452453
return checkbox;
453454
}
454455

455-
private void CheckboxDrawDebugOutlinesOnCheckChanged(ICheckbox sender, EventArgs eventArgs)
456+
private void CheckboxDrawDebugOutlinesOnCheckChanged(ICheckbox sender, ValueChangedEventArgs<bool> eventArgs)
456457
{
457-
_drawDebugOutlinesEnabled = sender.IsChecked;
458+
_drawDebugOutlinesEnabled = eventArgs.Value;
458459
if (Root is { } root)
459460
{
460461
root.DrawDebugOutlines = _drawDebugOutlinesEnabled;
@@ -480,9 +481,9 @@ private LabeledCheckBox CreateInfoCheckboxEnableLayoutHotReloading(Base parent)
480481
return checkbox;
481482
}
482483

483-
private static void CheckboxEnableLayoutHotReloadOnCheckChanged(ICheckbox sender, EventArgs _)
484+
private static void CheckboxEnableLayoutHotReloadOnCheckChanged(ICheckbox sender, ValueChangedEventArgs<bool> args)
484485
{
485-
Globals.ContentManager.ContentWatcher.Enabled = sender.IsChecked;
486+
Current.ContentWatcher.Enabled = args.Value;
486487
}
487488

488489
private LabeledCheckBox CreateInfoCheckboxIncludeTextNodesInHover(Base parent)
@@ -500,15 +501,15 @@ private LabeledCheckBox CreateInfoCheckboxIncludeTextNodesInHover(Base parent)
500501
return checkbox;
501502
}
502503

503-
private void CheckboxIncludesTextNodesInHoverOnCheckChanged(ICheckbox checkbox, EventArgs eventArgs)
504+
private void CheckboxIncludesTextNodesInHoverOnCheckChanged(ICheckbox checkbox, ValueChangedEventArgs<bool> eventArgs)
504505
{
505-
if (_nodeUnderCursorProvider.Filter.HasFlag(NodeFilter.IncludeText))
506+
if (eventArgs.Value)
506507
{
507-
_nodeUnderCursorProvider.Filter &= ~NodeFilter.IncludeText;
508+
_nodeUnderCursorProvider.Filter |= NodeFilter.IncludeText;
508509
}
509510
else
510511
{
511-
_nodeUnderCursorProvider.Filter |= NodeFilter.IncludeText;
512+
_nodeUnderCursorProvider.Filter &= ~NodeFilter.IncludeText;
512513
}
513514
}
514515

@@ -528,14 +529,19 @@ private LabeledCheckBox CreateInfoCheckboxViewClickedNodeInDebugger(Base parent)
528529
return checkbox;
529530
}
530531

531-
private void CheckboxViewClickedNodeInDebuggerOnCheckChanged(ICheckbox checkbox, EventArgs eventArgs)
532+
private void CheckboxViewClickedNodeInDebuggerOnCheckChanged(ICheckbox checkbox, ValueChangedEventArgs<bool> eventArgs)
532533
{
533-
_viewClickedNodeInDebugger = !_viewClickedNodeInDebugger;
534+
var wasClicked = _viewClickedNodeInDebugger;
535+
536+
_viewClickedNodeInDebugger = eventArgs.Value;
534537
if (_viewClickedNodeInDebugger)
535538
{
536-
AddIntercepts();
539+
if (!wasClicked)
540+
{
541+
AddIntercepts();
542+
}
537543
}
538-
else
544+
else if (wasClicked)
539545
{
540546
RemoveIntercepts();
541547
}

Intersect.Client.Core/Interface/Game/Admin/AdminWindow.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,7 @@ private void MuteButtonOnClicked(Base sender, MouseButtonState arguments)
495495
);
496496
}
497497

498-
private void MapSortCheckboxOnCheckChanged(ICheckbox sender, EventArgs eventArgs)
498+
private void MapSortCheckboxOnCheckChanged(ICheckbox sender, ValueChangedEventArgs<bool> eventArgs)
499499
{
500500
UpdateMapList();
501501
}

Intersect.Client.Core/Interface/Interface.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ namespace Intersect.Client.Interface;
1616

1717
public static partial class Interface
1818
{
19+
private static FPSPanel? _fpsPanel;
1920
private static readonly ConcurrentQueue<Alert> PendingErrorMessages = new();
2021

2122
private static bool _initialized;
@@ -75,6 +76,26 @@ public static MenuGuiBase MenuUi
7576
public static MutableInterface CurrentInterface => NullableCurrentInterface ??
7677
throw new InvalidOperationException("No current UI initialized");
7778

79+
private static bool _showFPSPanel;
80+
81+
public static bool ShowFPSPanel
82+
{
83+
get => _showFPSPanel;
84+
set
85+
{
86+
if (_showFPSPanel == value)
87+
{
88+
return;
89+
}
90+
91+
_showFPSPanel = value;
92+
if (_fpsPanel is { } fpsPanel)
93+
{
94+
fpsPanel.IsVisibleInParent = _showFPSPanel;
95+
}
96+
}
97+
}
98+
7899
private static bool HasCurrentInterface => NullableCurrentInterface is not null;
79100

80101
public static TexturedBase Skin
@@ -193,6 +214,12 @@ public static void InitGwen()
193214
_uiMainMenu = null;
194215
}
195216

217+
_showFPSPanel = Globals.Database?.ShowFPSCounter ?? false;
218+
_fpsPanel = new FPSPanel(CurrentInterface.Root)
219+
{
220+
IsVisibleInParent = _showFPSPanel,
221+
};
222+
196223
Globals.OnLifecycleChangeState();
197224

198225
_initialized = true;
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
using Intersect.Client.Core;
2+
using Intersect.Client.Framework.File_Management;
3+
using Intersect.Client.Framework.GenericClasses;
4+
using Intersect.Client.Framework.Gwen;
5+
using Intersect.Client.Framework.Gwen.Control;
6+
using Intersect.Client.Framework.Gwen.Control.EventArguments;
7+
using Intersect.Client.Framework.Gwen.Control.Layout;
8+
using Intersect.Client.General;
9+
using Intersect.Client.Interface.Data;
10+
using Intersect.Client.Localization;
11+
using Intersect.Core;
12+
13+
namespace Intersect.Client.Interface.Shared;
14+
15+
public partial class FPSPanel : Panel
16+
{
17+
private readonly Label _label;
18+
19+
public FPSPanel(Base parent, string name = nameof(FPSPanel)) : base(parent: parent, name: name)
20+
{
21+
Alignment = [Alignments.Top, Alignments.Right];
22+
BackgroundColor = new Color(0x7f, 0, 0, 0);
23+
RestrictToParent = true;
24+
// TODO: Remove this when showing a game version is added
25+
IsVisibleInTree = ApplicationContext.CurrentContext.IsDeveloper;
26+
27+
var font = GameContentManager.Current.GetFont("sourcesansproblack", 10);
28+
29+
_label = new Label(this, name: nameof(_label))
30+
{
31+
AutoSizeToContents = false,
32+
Dock = Pos.Fill,
33+
Font = font,
34+
Padding = new Padding(8, 4),
35+
Text = ApplicationContext.CurrentContext.VersionName,
36+
TextAlign = Pos.Center,
37+
IsVisibleInParent = Globals.Database?.ShowFPSCounter ?? false,
38+
};
39+
40+
MinimumSize = Graphics.Renderer.MeasureText(Strings.General.FpsLabelFormat.ToString(10_000), font) + new Pointf(16, 8);
41+
42+
DelegateDataProvider<int> fpsProvider = new(() => Graphics.Renderer.Fps)
43+
{
44+
UserData = _label,
45+
};
46+
AddDataProvider(fpsProvider);
47+
fpsProvider.ValueChanged += OnFPSChanged;
48+
}
49+
50+
private static void OnFPSChanged(IDataProvider dataProvider, ValueChangedEventArgs<int> args)
51+
{
52+
if (dataProvider is not DataProvider<int> typedProvider)
53+
{
54+
throw new InvalidOperationException("Received event from invalid data provider");
55+
}
56+
57+
if (typedProvider.UserData is not Label label)
58+
{
59+
throw new InvalidOperationException("Data provider's user data is not a label as expected");
60+
}
61+
62+
label.Text = Strings.General.FpsLabelFormat.ToString(args.Value);
63+
}
64+
65+
protected override void Layout(Framework.Gwen.Skin.Base skin)
66+
{
67+
base.Layout(skin);
68+
69+
SizeToChildren();
70+
}
71+
}

Intersect.Client.Core/Interface/Shared/SettingsWindow.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ public partial class SettingsWindow : Window
7474
private readonly ScrollControl _videoContainer;
7575
private readonly LabeledComboBox _resolutionList;
7676
private readonly LabeledComboBox _fpsList;
77+
private readonly LabeledCheckBox _showFPSCounterCheckbox;
7778
private readonly LabeledSlider _worldScale;
7879
private readonly LabeledCheckBox _fullscreenCheckbox;
7980
private readonly LabeledCheckBox _lightingEnabledCheckbox;
@@ -397,6 +398,14 @@ public SettingsWindow(Base parent) : base(parent: parent, title: Strings.Setting
397398
_ = _fpsList.AddItem(label: Strings.Settings.Fps120);
398399
_ = _fpsList.AddItem(label: Strings.Settings.UnlimitedFps);
399400

401+
_showFPSCounterCheckbox = new LabeledCheckBox(parent: _videoContainer, name: nameof(_showFPSCounterCheckbox))
402+
{
403+
Dock = Pos.Top,
404+
Font = _defaultFont,
405+
Text = Strings.Settings.ShowFPSCounter,
406+
};
407+
_showFPSCounterCheckbox.CheckChanged += ShowFPSCounterCheckboxOnCheckChanged;
408+
400409
// Video Settings - Fullscreen Checkbox.
401410
_fullscreenCheckbox = new LabeledCheckBox(parent: _videoContainer, name: nameof(_fullscreenCheckbox))
402411
{
@@ -548,6 +557,11 @@ public SettingsWindow(Base parent) : base(parent: parent, title: Strings.Setting
548557
CreateBottomBar(this);
549558
}
550559

560+
private static void ShowFPSCounterCheckboxOnCheckChanged(ICheckbox fpsCounterCheckbox, ValueChangedEventArgs<bool> args)
561+
{
562+
Interface.ShowFPSPanel = args.Value;
563+
}
564+
551565
protected override void EnsureInitialized()
552566
{
553567
LoadJsonUi(stage: UI.Shared, resolution: Graphics.Renderer?.GetResolutionString());
@@ -934,6 +948,8 @@ public void Show(Base? returnTo)
934948
}
935949
}
936950

951+
_showFPSCounterCheckbox.IsChecked = Globals.Database.ShowFPSCounter;
952+
937953
switch (Globals.Database.TargetFps)
938954
{
939955
case -1: // Unlimited.
@@ -1136,6 +1152,8 @@ private void SettingsApplyBtn_Clicked(Base sender, MouseButtonState arguments)
11361152
Globals.Database.TargetFps = newFps;
11371153
}
11381154

1155+
Globals.Database.ShowFPSCounter = _showFPSCounterCheckbox.IsChecked;
1156+
11391157
// Audio Settings.
11401158
Globals.Database.MusicVolume = (int)_musicSlider.Value;
11411159
Globals.Database.SoundVolume = (int)_soundEffectsSlider.Value;

Intersect.Client.Core/Interface/Shared/VersionPanel.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using Intersect.Client.Framework.File_Management;
2+
using Intersect.Client.Framework.Graphics;
23
using Intersect.Client.Framework.Gwen;
34
using Intersect.Client.Framework.Gwen.Control;
5+
using Intersect.Client.General;
46
using Intersect.Core;
57

68
namespace Intersect.Client.Interface.Shared;

Intersect.Client.Core/Localization/Strings.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1245,6 +1245,9 @@ public partial struct General
12451245

12461246
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
12471247
public static LocalizedString None = @"None";
1248+
1249+
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
1250+
public static LocalizedString FpsLabelFormat = @"{0}fps";
12481251
}
12491252

12501253
public partial struct Guilds
@@ -2089,6 +2092,9 @@ public partial struct Settings
20892092
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
20902093
public static LocalizedString Fps90 = @"90";
20912094

2095+
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
2096+
public static LocalizedString ShowFPSCounter = @"Show FPS Counter";
2097+
20922098
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
20932099
public static LocalizedString Fullscreen = @"Fullscreen";
20942100

Intersect.Client.Framework/Database/GameDatabase.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ public abstract partial class GameDatabase
1919

2020
public int SoundVolume { get; set; }
2121

22+
public bool ShowFPSCounter { get; set; }
23+
2224
public int TargetFps { get; set; }
2325

2426
public int TargetResolution { get; set; }
@@ -113,6 +115,7 @@ public virtual void LoadPreferences()
113115
MusicVolume = LoadPreference(nameof(MusicVolume), 10);
114116
SoundVolume = LoadPreference(nameof(SoundVolume), 15);
115117
TargetResolution = LoadPreference(nameof(TargetResolution), -1);
118+
ShowFPSCounter = LoadPreference(nameof(ShowFPSCounter), false);
116119
TargetFps = LoadPreference(nameof(TargetFps), 0);
117120
FullScreen = LoadPreference(nameof(FullScreen), false);
118121
EnableLighting = LoadPreference(nameof(EnableLighting), true);
@@ -153,6 +156,7 @@ public virtual void SavePreferences()
153156
SavePreference(nameof(TargetResolution), TargetResolution);
154157
SavePreference(nameof(TargetFps), TargetFps);
155158
SavePreference(nameof(FullScreen), FullScreen);
159+
SavePreference(nameof(ShowFPSCounter), ShowFPSCounter);
156160
SavePreference(nameof(EnableLighting), EnableLighting);
157161
SavePreference(nameof(HideOthersOnWindowOpen), HideOthersOnWindowOpen);
158162
SavePreference(nameof(AutoToggleChatLog), AutoToggleChatLog);

Intersect.Client.Framework/Graphics/GameRenderer.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,8 @@ public IGameRenderTexture CreateWhiteTexture()
145145

146146
public abstract IGameRenderTexture CreateRenderTexture(int width, int height);
147147

148+
public Pointf MeasureText(string text, GameFont? font) => MeasureText(text, font, 1);
149+
148150
public abstract Pointf MeasureText(string text, GameFont? gameFont, float fontScale);
149151

150152
public abstract void DrawString(

Intersect.Client.Framework/Gwen/Control/Checkbox.cs

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Intersect.Client.Framework.File_Management;
22
using Intersect.Client.Framework.Graphics;
3+
using Intersect.Client.Framework.Gwen.Control.EventArguments;
34
using Intersect.Client.Framework.Input;
45
using Intersect.Framework.Eventing;
56
using Newtonsoft.Json.Linq;
@@ -76,7 +77,7 @@ public bool IsChecked
7677
}
7778

7879
mChecked = value;
79-
OnCheckChanged();
80+
OnCheckChanged(value);
8081
}
8182
}
8283

@@ -183,32 +184,29 @@ public override void Toggle()
183184
/// <summary>
184185
/// Invoked when the checkbox state has been changed.
185186
/// </summary>
186-
public event EventHandler<ICheckbox, EventArgs>? CheckChanged;
187+
public event EventHandler<ICheckbox, ValueChangedEventArgs<bool>>? CheckChanged;
187188

188189
/// <summary>
189190
/// Handler for CheckChanged event.
190191
/// </summary>
191-
protected virtual void OnCheckChanged()
192+
protected virtual void OnCheckChanged(bool isChecked)
192193
{
193-
if (IsChecked)
194+
if (isChecked)
194195
{
195-
if (Checked != null)
196-
{
197-
Checked.Invoke(this, EventArgs.Empty);
198-
}
196+
Checked?.Invoke(this, EventArgs.Empty);
199197
}
200198
else
201199
{
202-
if (Unchecked != null)
203-
{
204-
Unchecked.Invoke(this, EventArgs.Empty);
205-
}
200+
Unchecked?.Invoke(this, EventArgs.Empty);
206201
}
207202

208-
if (CheckChanged != null)
209-
{
210-
CheckChanged.Invoke(this, EventArgs.Empty);
211-
}
203+
CheckChanged?.Invoke(
204+
this,
205+
new ValueChangedEventArgs<bool>
206+
{
207+
Value = isChecked, OldValue = !isChecked
208+
}
209+
);
212210
}
213211

214212
/// <summary>

0 commit comments

Comments
 (0)