mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-07-04 05:55:47 -07:00
Rewrite FPS/Realtime/Gametime/Ceasefire counters to use object semantics using class notation, refs #5387.
Rebuild the counters every 250ms instead of every frame and minimize object creation. Differential Revision: https://code.wildfiregames.com/D2391 Comments By: Stan This was SVN commit r23096.
This commit is contained in:
parent
abe2ec9c75
commit
38e06fce7e
17 changed files with 327 additions and 127 deletions
|
|
@ -169,6 +169,7 @@ fps.toggle = "Alt+F" ; Toggle frame counter
|
|||
realtime.toggle = "Alt+T" ; Toggle current display of computer time
|
||||
session.devcommands.toggle = "Alt+D" ; Toggle developer commands panel
|
||||
timeelapsedcounter.toggle = "F12" ; Toggle time elapsed counter
|
||||
ceasefirecounter.toggle = unused ; Toggle ceasefire counter
|
||||
session.showstatusbars = Tab ; Toggle display of status bars
|
||||
session.highlightguarding = PgDn ; Toggle highlight of guarding units
|
||||
session.highlightguarded = PgUp ; Toggle highlight of guarded units
|
||||
|
|
|
|||
47
binaries/data/mods/public/gui/common/OverlayCounter.js
Normal file
47
binaries/data/mods/public/gui/common/OverlayCounter.js
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
* This is an abstract base class managing one counter shown.
|
||||
* Classes implementing this class require a Config property and may have a Hotkey property.
|
||||
*/
|
||||
class OverlayCounter
|
||||
{
|
||||
constructor(overlayCounterManager)
|
||||
{
|
||||
this.overlayCounterManager = overlayCounterManager;
|
||||
this.updateEnabled();
|
||||
|
||||
registerConfigChangeHandler(this.onConfigChange.bind(this));
|
||||
|
||||
if (this.Hotkey)
|
||||
Engine.SetGlobalHotkey(this.Hotkey, this.toggle.bind(this));
|
||||
}
|
||||
|
||||
onConfigChange(changes)
|
||||
{
|
||||
if (changes.has(this.Config))
|
||||
this.updateEnabled();
|
||||
}
|
||||
|
||||
isEnabled()
|
||||
{
|
||||
return Engine.ConfigDB_GetValue("user", this.Config) == "true";
|
||||
}
|
||||
|
||||
updateEnabled()
|
||||
{
|
||||
this.overlayCounterManager.setCounterEnabled(this, this.isEnabled());
|
||||
}
|
||||
|
||||
toggle()
|
||||
{
|
||||
Engine.ConfigDB_CreateValue("user", this.Config, String(!this.isEnabled()));
|
||||
this.updateEnabled();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The properties of this prototype are defined in other files. Each of them is a class
|
||||
* managing a counter shown on the current page and may extend the OverlayCounter class.
|
||||
*/
|
||||
class OverlayCounterTypes
|
||||
{
|
||||
}
|
||||
32
binaries/data/mods/public/gui/common/OverlayCounterFPS.js
Normal file
32
binaries/data/mods/public/gui/common/OverlayCounterFPS.js
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
* This counter displays the current framerate in the screen corner.
|
||||
*/
|
||||
OverlayCounterTypes.prototype.FPS = class extends OverlayCounter
|
||||
{
|
||||
constructor(overlayCounterManager)
|
||||
{
|
||||
super(overlayCounterManager);
|
||||
|
||||
// Tiny performance improvement
|
||||
this.caption = translate(this.Caption);
|
||||
|
||||
// Minimize object construction
|
||||
this.fpsObject = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called frequently and thus minimized.
|
||||
*/
|
||||
get()
|
||||
{
|
||||
this.fpsObject.fps = Engine.GetFPS();
|
||||
return sprintf(this.caption, this.fpsObject);
|
||||
}
|
||||
};
|
||||
|
||||
// dennis-ignore: *
|
||||
OverlayCounterTypes.prototype.FPS.prototype.Caption = markForTranslation("FPS: %(fps)4s");
|
||||
|
||||
OverlayCounterTypes.prototype.FPS.prototype.Config = "overlay.fps";
|
||||
|
||||
OverlayCounterTypes.prototype.FPS.prototype.Hotkey = "fps.toggle";
|
||||
119
binaries/data/mods/public/gui/common/OverlayCounterManager.js
Normal file
119
binaries/data/mods/public/gui/common/OverlayCounterManager.js
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
/**
|
||||
* Since every GUI page can display the FPS or realtime counter,
|
||||
* this manager is initialized for every GUI page.
|
||||
*/
|
||||
var g_OverlayCounterManager;
|
||||
|
||||
class OverlayCounterManager
|
||||
{
|
||||
constructor(dataCounter)
|
||||
{
|
||||
this.dataCounter = dataCounter;
|
||||
this.lineHeight = dataCounter.size.bottom - dataCounter.size.top;
|
||||
this.counters = [];
|
||||
this.enabledCounters = [];
|
||||
this.lastTick = undefined;
|
||||
this.lastLineCount = 0;
|
||||
this.resizeHandlers = [];
|
||||
|
||||
for (let name of this.availableCounterNames())
|
||||
{
|
||||
let counter = new OverlayCounterTypes.prototype[name](this);
|
||||
this.counters.push(counter);
|
||||
counter.updateEnabled();
|
||||
}
|
||||
|
||||
this.dataCounter.onTick = this.onTick.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mods may overwrite this to change the order of the counters shown.
|
||||
*/
|
||||
availableCounterNames()
|
||||
{
|
||||
return Object.keys(OverlayCounterTypes.prototype);
|
||||
}
|
||||
|
||||
deleteCounter(counter)
|
||||
{
|
||||
let filter = count => count != counter;
|
||||
this.counters = this.counters.filter(filter);
|
||||
this.enabledCounters = this.enabledCounters.filter(filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function allows enabling and disabling of timers while preserving the counter order.
|
||||
*/
|
||||
setCounterEnabled(counter, enabled)
|
||||
{
|
||||
if (enabled)
|
||||
this.enabledCounters = this.counters.filter(count =>
|
||||
this.enabledCounters.indexOf(count) != -1 || count == counter);
|
||||
else
|
||||
this.enabledCounters = this.enabledCounters.filter(count => count != counter);
|
||||
|
||||
// Update instantly
|
||||
this.lastTick = undefined;
|
||||
this.onTick();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handlers subscribed here will be informed then the dimension of the overlay changed.
|
||||
* This allows placing the buttons below the counter.
|
||||
*/
|
||||
registerResizeHandler(handler)
|
||||
{
|
||||
this.resizeHandlers.push(handler);
|
||||
}
|
||||
|
||||
onTick()
|
||||
{
|
||||
// Don't rebuild the caption every frame
|
||||
let now = Date.now();
|
||||
if (now < this.lastTick + this.Delay)
|
||||
return;
|
||||
|
||||
this.lastTick = now;
|
||||
|
||||
let lineCount = 0;
|
||||
let txt = "";
|
||||
|
||||
for (let counter of this.enabledCounters)
|
||||
{
|
||||
let newTxt = counter.get();
|
||||
if (!newTxt)
|
||||
continue;
|
||||
|
||||
++lineCount;
|
||||
txt += newTxt + "\n";
|
||||
}
|
||||
|
||||
if (lineCount)
|
||||
this.dataCounter.caption = txt;
|
||||
|
||||
// The caption changes more often than not,
|
||||
// but adding or removing lines happens rarely.
|
||||
if (this.lastLineCount == lineCount)
|
||||
return;
|
||||
|
||||
let offset = this.lineHeight * lineCount;
|
||||
|
||||
if (lineCount)
|
||||
{
|
||||
let size = this.dataCounter.size;
|
||||
size.bottom = size.top + offset;
|
||||
this.dataCounter.size = size;
|
||||
}
|
||||
|
||||
this.dataCounter.hidden = !lineCount;
|
||||
|
||||
for (let handler of this.resizeHandlers)
|
||||
handler(offset);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* To minimize the computation performed every frame, this duration
|
||||
* in milliseconds determines how often the caption is rebuilt.
|
||||
*/
|
||||
OverlayCounterManager.prototype.Delay = 250;
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
/**
|
||||
* Shows the current time to the player in their current timezone.
|
||||
*/
|
||||
OverlayCounterTypes.prototype.Realtime = class extends OverlayCounter
|
||||
{
|
||||
constructor(overlayCounterManager)
|
||||
{
|
||||
super(overlayCounterManager);
|
||||
this.date = new Date();
|
||||
}
|
||||
|
||||
get()
|
||||
{
|
||||
this.date.setTime(Date.now());
|
||||
return this.date.toLocaleTimeString();
|
||||
}
|
||||
};
|
||||
|
||||
OverlayCounterTypes.prototype.Realtime.prototype.Config = "overlay.realtime";
|
||||
|
||||
OverlayCounterTypes.prototype.Realtime.prototype.Hotkey = "realtime.toggle";
|
||||
|
|
@ -1,29 +1,3 @@
|
|||
function updateCounters()
|
||||
{
|
||||
let counters = [];
|
||||
|
||||
if (Engine.ConfigDB_GetValue("user", "overlay.fps") === "true")
|
||||
// dennis-ignore: *
|
||||
counters.push(sprintf(translate("FPS: %(fps)4s"), { "fps": Engine.GetFPS() }));
|
||||
|
||||
if (Engine.ConfigDB_GetValue("user", "overlay.realtime") === "true")
|
||||
counters.push((new Date()).toLocaleTimeString());
|
||||
|
||||
// If game has been started
|
||||
if (typeof appendSessionCounters != "undefined")
|
||||
appendSessionCounters(counters);
|
||||
|
||||
let dataCounter = Engine.GetGUIObjectByName("dataCounter");
|
||||
dataCounter.caption = counters.join("\n") + "\n";
|
||||
dataCounter.hidden = !counters.length;
|
||||
dataCounter.size = sprintf("%(left)s %(top)s %(right)s %(bottom)s", {
|
||||
"left": "100%%-100",
|
||||
"top": "40",
|
||||
"right": "100%%-5",
|
||||
"bottom": 40 + 14 * counters.length
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the overlay with the most recent network warning of each client.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -8,6 +8,27 @@ var g_SoundNotifications = {
|
|||
"gamesetup.join": { "soundfile": "audio/interface/ui/gamesetup_join.ogg", "threshold": 0 }
|
||||
};
|
||||
|
||||
/**
|
||||
* These events are fired when the user has closed the options page.
|
||||
* The handlers are provided a Set storing which config values have changed.
|
||||
* TODO: This should become a GUI event sent by the engine.
|
||||
*/
|
||||
var g_ConfigChangeHandlers = new Set();
|
||||
|
||||
function registerConfigChangeHandler(handler)
|
||||
{
|
||||
g_ConfigChangeHandlers.add(handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param changes - a Set of config names
|
||||
*/
|
||||
function fireConfigChangeHandlers(changes)
|
||||
{
|
||||
for (let handler of g_ConfigChangeHandlers)
|
||||
handler(changes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns translated history and gameplay data of all civs, optionally including a mock gaia civ.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -39,43 +39,15 @@
|
|||
type="text"
|
||||
ghost="true"
|
||||
z="199"
|
||||
size="100%-90 40 100%-5 40"
|
||||
size="100%-100 40 100%-5 54"
|
||||
font="mono-10"
|
||||
textcolor="white"
|
||||
text_align="right"
|
||||
text_valign="top"
|
||||
sprite="color: 0 0 0 100"
|
||||
>
|
||||
<action on="Tick">
|
||||
updateCounters();
|
||||
</action>
|
||||
</object>
|
||||
|
||||
<object name="fpsCounter"
|
||||
type="text"
|
||||
ghost="true"
|
||||
hidden="true"
|
||||
hotkey="fps.toggle"
|
||||
>
|
||||
<action on="Press">
|
||||
Engine.ConfigDB_CreateValue("user", "overlay.fps", ""+(Engine.ConfigDB_GetValue("user", "overlay.fps")!== "true"));
|
||||
</action>
|
||||
</object>
|
||||
|
||||
<!--
|
||||
==========================================
|
||||
- TIME COUNTER
|
||||
==========================================
|
||||
-->
|
||||
|
||||
<object name="timeCounter"
|
||||
type="text"
|
||||
ghost="true"
|
||||
hidden="true"
|
||||
hotkey="realtime.toggle"
|
||||
>
|
||||
<action on="Press">
|
||||
Engine.ConfigDB_CreateValue("user", "overlay.realtime", ""+(Engine.ConfigDB_GetValue("user", "overlay.realtime") !== "true"));
|
||||
<action on="Load">
|
||||
g_OverlayCounterManager = new OverlayCounterManager(this);
|
||||
</action>
|
||||
</object>
|
||||
|
||||
|
|
|
|||
|
|
@ -243,6 +243,7 @@ function displayOptions()
|
|||
Engine.ConfigDB_SetChanges("user", true);
|
||||
|
||||
g_ChangedKeys.add(option.config);
|
||||
fireConfigChangeHandlers(new Set([option.config]));
|
||||
|
||||
if (option.function)
|
||||
Engine[option.function](value);
|
||||
|
|
|
|||
|
|
@ -141,7 +141,10 @@ var g_MainMenuItems = [
|
|||
"caption": translate("Options"),
|
||||
"tooltip": translate("Adjust game settings."),
|
||||
"onPress": () => {
|
||||
Engine.PushGuiPage("page_options.xml");
|
||||
Engine.PushGuiPage(
|
||||
"page_options.xml",
|
||||
{},
|
||||
fireConfigChangeHandlers);
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ class DiplomacyColors
|
|||
|
||||
registerPlayersInitHandler(this.onPlayersInit.bind(this));
|
||||
registerConfigChangeHandler(this.onConfigChange.bind(this));
|
||||
registerCeasefireEndedHandler(this.onCeasefireEnded.bind(this));
|
||||
}
|
||||
|
||||
registerDiplomacyColorsChangeHandler(handler)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
/**
|
||||
* This class shows the simulated match time below the FPS counter.
|
||||
*/
|
||||
OverlayCounterTypes.prototype.ElapsedTime = class extends OverlayCounter
|
||||
{
|
||||
constructor(overlayCounterManager)
|
||||
{
|
||||
super(overlayCounterManager);
|
||||
|
||||
// Performance optimization
|
||||
this.caption = translate(this.Caption);
|
||||
this.sprintfData = {};
|
||||
}
|
||||
|
||||
get()
|
||||
{
|
||||
if (!g_SimState)
|
||||
return "";
|
||||
|
||||
let time = timeToString(g_SimState.timeElapsed);
|
||||
|
||||
let speed = Engine.GetSimRate();
|
||||
if (speed == 1)
|
||||
return time;
|
||||
|
||||
this.sprintfData.time = time;
|
||||
this.sprintfData.speed = Engine.FormatDecimalNumberIntoString(speed);
|
||||
return sprintf(this.caption, this.sprintfData);
|
||||
}
|
||||
};
|
||||
|
||||
// Translation: The "x" means "times", with the mathematical meaning of multiplication.
|
||||
OverlayCounterTypes.prototype.ElapsedTime.prototype.Caption = markForTranslation("%(time)s (%(speed)sx)");
|
||||
|
||||
OverlayCounterTypes.prototype.ElapsedTime.prototype.Config = "gui.session.timeelapsedcounter";
|
||||
|
||||
OverlayCounterTypes.prototype.ElapsedTime.prototype.Hotkey = "timeelapsedcounter.toggle";
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
* Adds the ceasefire counter to the global FPS and
|
||||
* realtime counters shown in the top right corner.
|
||||
*/
|
||||
OverlayCounterTypes.prototype.RemainingCeasefire = class extends OverlayCounter
|
||||
{
|
||||
constructor(overlayCounterManager)
|
||||
{
|
||||
super(overlayCounterManager);
|
||||
registerCeasefireEndedHandler(this.onCeasefireEnded.bind(this));
|
||||
}
|
||||
|
||||
onCeasefireEnded()
|
||||
{
|
||||
this.overlayCounterManager.deleteCounter(this);
|
||||
}
|
||||
|
||||
get()
|
||||
{
|
||||
if (!g_SimState)
|
||||
return "";
|
||||
return timeToString(g_SimState.ceasefireTimeRemaining);
|
||||
}
|
||||
};
|
||||
|
||||
OverlayCounterTypes.prototype.RemainingCeasefire.prototype.Config = "gui.session.ceasefirecounter";
|
||||
|
||||
OverlayCounterTypes.prototype.RemainingCeasefire.prototype.Hotkey = "ceasefirecounter.toggle";
|
||||
|
|
@ -18,6 +18,11 @@ var g_TutorialNewMessageTags = { "color": "yellow" };
|
|||
*/
|
||||
var g_PlayerAssignmentsChangeHandlers = new Set();
|
||||
|
||||
/**
|
||||
* These handlers are called when the ceasefire time has run out.
|
||||
*/
|
||||
var g_CeasefireEndedHandlers = new Set();
|
||||
|
||||
/**
|
||||
* Handle all netmessage types that can occur.
|
||||
*/
|
||||
|
|
@ -151,7 +156,8 @@ var g_NotificationsTypes =
|
|||
"ceasefire-ended": function(notification, player)
|
||||
{
|
||||
updatePlayerData();
|
||||
g_DiplomacyColors.OnCeasefireEnded();
|
||||
for (let handler of g_CeasefireEndedHandlers)
|
||||
handler();
|
||||
},
|
||||
"tutorial": function(notification, player)
|
||||
{
|
||||
|
|
@ -291,6 +297,11 @@ function registerPlayerAssignmentsChangeHandler(handler)
|
|||
g_PlayerAssignmentsChangeHandlers.add(handler);
|
||||
}
|
||||
|
||||
function registerCeasefireEndedHandler(handler)
|
||||
{
|
||||
g_CeasefireEndedHandlers.add(handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all known cheat commands.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -159,12 +159,6 @@ var g_EntitySelectionChangeHandlers = new Set();
|
|||
*/
|
||||
var g_HotkeyChangeHandlers = new Set();
|
||||
|
||||
/**
|
||||
* These events are fired when the user has closed the options page.
|
||||
* The handlers are provided a Set storing which config values have changed.
|
||||
*/
|
||||
var g_ConfigChangeHandlers = new Set();
|
||||
|
||||
/**
|
||||
* List of additional entities to highlight.
|
||||
*/
|
||||
|
|
@ -353,20 +347,6 @@ function registerHotkeyChangeHandler(handler)
|
|||
g_HotkeyChangeHandlers.add(handler);
|
||||
}
|
||||
|
||||
function registerConfigChangeHandler(handler)
|
||||
{
|
||||
g_ConfigChangeHandlers.add(handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param changes - a Set of config names
|
||||
*/
|
||||
function fireConfigChangeHandlers(changes)
|
||||
{
|
||||
for (let handler of g_ConfigChangeHandlers)
|
||||
handler(changes);
|
||||
}
|
||||
|
||||
function updatePlayerData()
|
||||
{
|
||||
let simState = GetSimState();
|
||||
|
|
@ -870,30 +850,3 @@ function playAmbient()
|
|||
{
|
||||
Engine.PlayAmbientSound(pickRandom(g_Ambient), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the ingame time and ceasefire counter to the global FPS and
|
||||
* realtime counters shown in the top right corner.
|
||||
*/
|
||||
function appendSessionCounters(counters)
|
||||
{
|
||||
let simState = GetSimState();
|
||||
|
||||
if (Engine.ConfigDB_GetValue("user", "gui.session.timeelapsedcounter") === "true")
|
||||
{
|
||||
let currentSpeed = Engine.GetSimRate();
|
||||
if (currentSpeed != 1.0)
|
||||
// Translation: The "x" means "times", with the mathematical meaning of multiplication.
|
||||
counters.push(sprintf(translate("%(time)s (%(speed)sx)"), {
|
||||
"time": timeToString(simState.timeElapsed),
|
||||
"speed": Engine.FormatDecimalNumberIntoString(currentSpeed)
|
||||
}));
|
||||
else
|
||||
counters.push(timeToString(simState.timeElapsed));
|
||||
}
|
||||
|
||||
if (simState.ceasefireActive && Engine.ConfigDB_GetValue("user", "gui.session.ceasefirecounter") === "true")
|
||||
counters.push(timeToString(simState.ceasefireTimeRemaining));
|
||||
|
||||
g_ResearchProgress.setTopOffset(14 * counters.length);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,20 +41,6 @@
|
|||
<!-- Hotkeys won't work properly unless outside menu -->
|
||||
<include directory="gui/session/hotkeys/"/>
|
||||
|
||||
<!-- Time elapsed counter -->
|
||||
<object size="100%-250 45 100%-140 65" type="text" name="timeElapsedCounter" style="SettingsText" hotkey="timeelapsedcounter.toggle" hidden="true">
|
||||
<action on="Press">
|
||||
Engine.ConfigDB_CreateValue("user", "gui.session.timeelapsedcounter", String(Engine.ConfigDB_GetValue("user", "gui.session.timeelapsedcounter") != "true"));
|
||||
</action>
|
||||
</object>
|
||||
|
||||
<!-- Ceasefire counter -->
|
||||
<object size="100%-250 80 100%-140 100" type="text" name="ceasefireCounter" style="SettingsText" hotkey="ceasefirecounter.toggle" hidden="true">
|
||||
<action on="Press">
|
||||
Engine.ConfigDB_CreateValue("user", "gui.session.ceasefirecounter", String(Engine.ConfigDB_GetValue("user", "gui.session.ceasefirecounter") != "true"));
|
||||
</action>
|
||||
</object>
|
||||
|
||||
<!-- Network status -->
|
||||
<object name="netStatus" type="text" style="netStatus" hidden="true">
|
||||
<object type="button"
|
||||
|
|
|
|||
|
|
@ -164,13 +164,6 @@
|
|||
ghost="true"
|
||||
/>
|
||||
|
||||
<style name="SettingsText"
|
||||
font="sans-stroke-16"
|
||||
textcolor="white"
|
||||
text_align="right"
|
||||
text_valign="center"
|
||||
/>
|
||||
|
||||
<style name="dialogTitleText"
|
||||
font="sans-bold-18"
|
||||
textcolor="white"
|
||||
|
|
|
|||
Loading…
Reference in a new issue