Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ English (US) release notes, mirroring CHANGELOG.md (Brazilian Portuguese). Befor

## [Unreleased]

## [1.6.0-beta.7]
### Heads-up: beta version, not the stable one
- This is a test version of 1.6. The stable version is still 1.5.1, and people on it don't get this update automatically: only those who turned on Settings → "Receive test versions (alpha and beta)" or are already on an alpha/beta. If something breaks, go back to 1.5.1 and report it with the feedback button (attach `consolemode.log`).

### What's new
- FPS counter over the game, through RivaTuner (RTSS), in Console Mode's style: pick it in Settings or cycle it with A on the new "FPS counter" row of the session menu. Styles: Afterburner (default; changes nothing), Off (nothing on screen), Compact (FPS only), Detailed (API, FPS and frame time) and Custom, where you pick the items, whether they share one line and the number color. Except on "Afterburner", MSI Afterburner's OSD is hidden during the session and comes back by itself when you go back to the PC; Afterburner's settings are not changed. (#138)

## [1.6.0-beta.6]
### Heads-up: beta version, not the stable one
- This is a test version of 1.6. The stable version is still 1.5.1, and people on it don't get this update automatically: only those who turned on Settings → "Receive test versions (alpha and beta)" or are already on an alpha/beta. If something breaks, go back to 1.5.1 and report it with the feedback button (attach `consolemode.log`).
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ Notas em português do Brasil; a versão em inglês (Estados Unidos) fica em `CH

## [Unreleased]

## [1.6.0-beta.7]
### Atenção: versão beta, não é a estável
- Esta é uma versão de teste da 1.6. A versão estável continua sendo a 1.5.1, e quem está nela não recebe esta atualização automaticamente: só quem ligou Ajustes → "Receber versões de teste (alpha e beta)" ou já está numa alpha/beta. Se algo falhar, volte para a 1.5.1 e conte pelo botão de feedback (anexe o `consolemode.log`).

### Novidades
- Contador de FPS sobre o jogo, pelo RivaTuner (RTSS), no estilo do Console Mode: escolha em Ajustes ou alterne com A na nova linha "Contador de FPS" do menu da sessão. Estilos: Afterburner (padrão; não mexe em nada), Desligado (nada na tela), Compacto (só o FPS), Detalhado (API, FPS e tempo de quadro) e Personalizado, em que você escolhe os itens, se ficam numa linha só e a cor dos números. Fora de "Afterburner", o OSD do MSI Afterburner fica escondido durante a sessão e volta sozinho ao voltar ao PC; a configuração do Afterburner não é alterada. (#138)

## [1.6.0-beta.6]
### Atenção: versão beta, não é a estável
- Esta é uma versão de teste da 1.6. A versão estável continua sendo a 1.5.1, e quem está nela não recebe esta atualização automaticamente: só quem ligou Ajustes → "Receber versões de teste (alpha e beta)" ou já está numa alpha/beta. Se algo falhar, volte para a 1.5.1 e conte pelo botão de feedback (anexe o `consolemode.log`).
Expand Down
17 changes: 17 additions & 0 deletions docs/TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -376,3 +376,20 @@ Pré-condições: 1.6 instalada por cima da 1.5, com a configuração da 1.5 (te
- [ ] Tente usar uma combinação já atribuída e confirme que a mensagem de conflito aparece inteira e não corta os botões.
- [ ] Reduza a altura da janela e confirme que o editor rola até **Voltar**, sem esconder os cartões.
- [ ] Feche o editor durante uma captura e confirme que ela para; reabra-o e confirme que nenhum botão fica preso em captura.

## Contador de FPS (RTSS)

Pré-requisito: RivaTuner Statistics Server instalado, com "Show On-Screen Display" ligado; MSI Afterburner aberto com o OSD dele ligado.

- [ ] Sem o RTSS instalado, a linha "Contador de FPS" não aparece no menu da sessão e o cartão em Ajustes fica desabilitado.
- [ ] Na prévia (menu aberto fora de uma sessão), a linha não aparece.
- [ ] Config nova: o estilo é "Afterburner (não mexer)" e o OSD do Afterburner aparece normal na sessão.
- [ ] Em sessão, A na linha alterna Afterburner → Desligado → Compacto → Detalhado → Personalizado → Afterburner, e o jogo muda na hora.
- [ ] Desligado: nada na tela, nem o nosso nem o do Afterburner (no máximo um piscar rápido do Afterburner de vez em quando).
- [ ] Compacto / Detalhado / Personalizado: só o nosso aparece; o do Afterburner fica escondido.
- [ ] Afterburner: o nosso some e o do Afterburner volta em até 1 s.
- [ ] Ajustes → Contador de FPS → Personalizado: marcar/desmarcar API, FPS e tempo de quadro, "Tudo em uma linha" e a cor muda o contador no jogo na hora (com a sessão ativa).
- [ ] Personalizado sem nenhum item marcado ainda mostra o FPS.
- [ ] Com o RTSS fechado, ligar Compacto abre o RTSS e o contador aparece.
- [ ] Voltar ao PC: o nosso some e o do Afterburner volta.
- [ ] A escolha e o layout ficam salvos para a próxima sessão.
4 changes: 2 additions & 2 deletions src/ConsoleMode/ConsoleMode.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>latest</LangVersion>
<Platform Condition="'$(Platform)' == ''">x64</Platform>
<Version>1.6.0-beta.6</Version>
<Version>1.6.0-beta.7</Version>
<AssemblyVersion>1.6.0.0</AssemblyVersion>
<FileVersion>1.6.0.0</FileVersion>
<InformationalVersion>1.6.0-beta.6</InformationalVersion>
<InformationalVersion>1.6.0-beta.7</InformationalVersion>
<AssemblyTitle>Console Mode</AssemblyTitle>
<Product>Console Mode</Product>
<Authors>lippdev</Authors>
Expand Down
3 changes: 3 additions & 0 deletions src/ConsoleMode/Models/Models.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ public sealed class AppConfig
public string AudioDeviceName { get; set; } = "";
public bool AudioAutoSwitch { get; set; }
public int FpsLimit { get; set; }
/// <summary>RtssOverlay style: "external" | "off" | "compact" | "detailed" | "custom". Applied over the game during a session.</summary>
public string FpsOverlay { get; set; } = RtssOverlay.External;
public FpsOverlayLayout FpsOverlayLayout { get; set; } = new();
public Dictionary<string, SavedDisplayMode> MonitorModes { get; set; } = new(StringComparer.OrdinalIgnoreCase);
public bool HdrEnable { get; set; }
public bool VrrEnable { get; set; }
Expand Down
18 changes: 18 additions & 0 deletions src/ConsoleMode/Resources/Strings.en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,24 @@
"PlaynitePathInvalid": "Could not find Playnite.FullscreenApp.exe at {0}.",
"PlaynitePathPickError": "Could not open the file picker: {0}",
"LaunchXbox": "Xbox mode (experimental)",
"FpsOverlayCard": "FPS counter",
"FpsOverlayExternal": "Afterburner (leave as is)",
"FpsOverlayOff": "Off (hide everything)",
"FpsOverlayCustom": "Custom",
"FpsOverlayDescription": "Shows the FPS over the game during a session, through RTSS. Except on \"Afterburner\", MSI Afterburner's OSD is hidden while console mode is on.",
"FpsOverlayItems": "Items",
"FpsOverlayShowApi": "API (D3D/Vulkan)",
"FpsOverlayShowFps": "FPS",
"FpsOverlayShowFrameTime": "Frame time (ms)",
"FpsOverlaySingleLine": "All on one line",
"FpsOverlayColor": "Number color",
"FpsOverlayColorWhite": "White",
"FpsOverlayColorBlue": "Blue",
"FpsOverlayColorGreen": "Green",
"FpsOverlayColorYellow": "Yellow",
"FpsOverlayColorOrange": "Orange",
"FpsOverlayCompact": "Compact",
"FpsOverlayDetailed": "Detailed",
"FpsNoLimit": "No limit",
"FpsCustom": "Custom",
"FpsAvailable": "Applies to all games while console mode is active. Uses RTSS.",
Expand Down
18 changes: 18 additions & 0 deletions src/ConsoleMode/Resources/Strings.es-ES.json
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,24 @@
"PlaynitePathInvalid": "No se encontró Playnite.FullscreenApp.exe en {0}.",
"PlaynitePathPickError": "No se pudo abrir el selector de archivos: {0}",
"LaunchXbox": "Modo Xbox (experimental)",
"FpsOverlayCard": "Contador de FPS",
"FpsOverlayExternal": "Afterburner (no tocar)",
"FpsOverlayOff": "Desactivado (oculta todo)",
"FpsOverlayCustom": "Personalizado",
"FpsOverlayDescription": "Muestra los FPS sobre el juego durante la sesión, mediante RTSS. Salvo en \"Afterburner\", el OSD de MSI Afterburner se oculta mientras el modo consola esté activo.",
"FpsOverlayItems": "Elementos",
"FpsOverlayShowApi": "API (D3D/Vulkan)",
"FpsOverlayShowFps": "FPS",
"FpsOverlayShowFrameTime": "Tiempo de fotograma (ms)",
"FpsOverlaySingleLine": "Todo en una línea",
"FpsOverlayColor": "Color de los números",
"FpsOverlayColorWhite": "Blanco",
"FpsOverlayColorBlue": "Azul",
"FpsOverlayColorGreen": "Verde",
"FpsOverlayColorYellow": "Amarillo",
"FpsOverlayColorOrange": "Naranja",
"FpsOverlayCompact": "Compacto",
"FpsOverlayDetailed": "Detallado",
"FpsNoLimit": "Sin límite",
"FpsCustom": "Personalizado",
"FpsAvailable": "Se aplica a todos los juegos mientras el modo consola está activo. Usa RTSS.",
Expand Down
18 changes: 18 additions & 0 deletions src/ConsoleMode/Resources/Strings.pt-BR.json
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,24 @@
"PlaynitePathInvalid": "Não achei o Playnite.FullscreenApp.exe em {0}.",
"PlaynitePathPickError": "Não foi possível abrir o seletor de arquivos: {0}",
"LaunchXbox": "Modo Xbox (experimental)",
"FpsOverlayCard": "Contador de FPS",
"FpsOverlayExternal": "Afterburner (não mexer)",
"FpsOverlayOff": "Desligado (esconde tudo)",
"FpsOverlayCustom": "Personalizado",
"FpsOverlayDescription": "Mostra o FPS sobre o jogo durante a sessão, pelo RTSS. Fora de \"Afterburner\", o OSD do MSI Afterburner fica escondido enquanto o modo console estiver ativo.",
"FpsOverlayItems": "Itens",
"FpsOverlayShowApi": "API (D3D/Vulkan)",
"FpsOverlayShowFps": "FPS",
"FpsOverlayShowFrameTime": "Tempo de quadro (ms)",
"FpsOverlaySingleLine": "Tudo em uma linha",
"FpsOverlayColor": "Cor dos números",
"FpsOverlayColorWhite": "Branco",
"FpsOverlayColorBlue": "Azul",
"FpsOverlayColorGreen": "Verde",
"FpsOverlayColorYellow": "Amarelo",
"FpsOverlayColorOrange": "Laranja",
"FpsOverlayCompact": "Compacto",
"FpsOverlayDetailed": "Detalhado",
"FpsNoLimit": "Sem limite",
"FpsCustom": "Personalizado",
"FpsAvailable": "Vale para todos os jogos enquanto o modo console estiver ativo. Usa o RTSS.",
Expand Down
6 changes: 6 additions & 0 deletions src/ConsoleMode/Services/ConsoleEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,10 @@ public void Start(AppConfig config, MonitorInfo? focusInfo, Func<ScreenRect?, bo
AppLog.Write(rtss.Message);
}

if (RtssOverlay.HidesOthers(config.FpsOverlay) && Rtss.IsInstalled
&& !Rtss.ApplyOverlay(config.FpsOverlay, config.FpsOverlayLayout))
AppLog.Write("RTSS: o contador de FPS não pôde ser exibido");

switch (config.FullscreenMode)
{
case "bigPicture":
Expand Down Expand Up @@ -282,6 +286,7 @@ public void Stop()
{
OnUi(BlackCurtain.Close);
Rtss.Restore(State);
Rtss.SetOverlay("", hideOthers: false);
return;
}

Expand All @@ -302,6 +307,7 @@ public void Stop()
}
Audio.Restore(State.BackupAudioId);
Rtss.Restore(State);
Rtss.SetOverlay("", hideOthers: false);
Monitors.ClearCache();
Audio.ClearCache();
if (State.Tv is { IsEnabled: true, TurnOffOnRestore: true } tv) Tv.TurnOff(tv);
Expand Down
7 changes: 7 additions & 0 deletions src/ConsoleMode/Services/LocalizationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,13 @@ internal void NotifyAll()
public string VrrCard => LocalizationService.Get(nameof(VrrCard));
public string VrrDescription => LocalizationService.Get(nameof(VrrDescription));
public string FpsCard => LocalizationService.Get(nameof(FpsCard));
public string FpsOverlayCard => LocalizationService.Get(nameof(FpsOverlayCard));
public string FpsOverlayItems => LocalizationService.Get(nameof(FpsOverlayItems));
public string FpsOverlayShowApi => LocalizationService.Get(nameof(FpsOverlayShowApi));
public string FpsOverlayShowFps => LocalizationService.Get(nameof(FpsOverlayShowFps));
public string FpsOverlayShowFrameTime => LocalizationService.Get(nameof(FpsOverlayShowFrameTime));
public string FpsOverlaySingleLine => LocalizationService.Get(nameof(FpsOverlaySingleLine));
public string FpsOverlayColor => LocalizationService.Get(nameof(FpsOverlayColor));
public string FpsPlaceholder => LocalizationService.Get(nameof(FpsPlaceholder));
public string AppSection => LocalizationService.Get(nameof(AppSection));
public string StartupCard => LocalizationService.Get(nameof(StartupCard));
Expand Down
88 changes: 88 additions & 0 deletions src/ConsoleMode/Services/RtssOverlay.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
using System.Text.RegularExpressions;

namespace ConsoleMode.Services;

/// <summary>What the custom FPS counter shows and how (Settings → FPS counter → Custom).</summary>
public sealed class FpsOverlayLayout
{
public bool ShowApi { get; set; } = true;
public bool ShowFps { get; set; } = true;
public bool ShowFrameTime { get; set; } = true;
/// <summary>Everything on one line instead of one item per line.</summary>
public bool SingleLine { get; set; }
/// <summary>RRGGBB of the numbers; one of <see cref="RtssOverlay.Colors"/>.</summary>
public string Color { get; set; } = RtssOverlay.Colors[0];
}

/// <summary>
/// Our FPS counter on the game, drawn by RTSS in its own OSD slot (<see cref="Owner"/>).
/// Every style except <see cref="External"/> takes the screen: MSI Afterburner's OSD is hidden
/// while it is on, so "Off" really means nothing on screen. External leaves Afterburner/RTSS alone.
/// </summary>
public static partial class RtssOverlay
{
public const string External = "external";
public const string Off = "off";
public const string Compact = "compact";
public const string Detailed = "detailed";
public const string Custom = "custom";

/// <summary>szOSDOwner of our slot.</summary>
public const string Owner = "ConsoleMode";

/// <summary>Menu order; External first, the default, so nobody's Afterburner disappears unasked.</summary>
public static readonly string[] Styles = [External, Off, Compact, Detailed, Custom];

/// <summary>White, blue, green, yellow, orange.</summary>
public static readonly string[] Colors = ["FFFFFF", "4CC2FF", "6FE07A", "FFD54A", "FF8A3D"];

public static string Normalize(string? style) =>
Styles.FirstOrDefault(s => string.Equals(s, style, StringComparison.OrdinalIgnoreCase)) ?? External;

/// <summary>A on the session menu row walks <see cref="Styles"/> and wraps around.</summary>
public static string Next(string? style) => Styles[(Array.IndexOf(Styles, Normalize(style)) + 1) % Styles.Length];

/// <summary>Whether this style keeps Afterburner's OSD off the screen.</summary>
public static bool HidesOthers(string? style) => Normalize(style) != External;

/// <summary>A color from the config, back to white if it isn't plain RRGGBB (it goes inside an RTSS tag).</summary>
public static string NormalizeColor(string? color) =>
color is not null && HexColor().IsMatch(color) ? color.ToUpperInvariant() : Colors[0];

// RTSS hypertext: <Cn=RRGGBB> / <Sn=size> define, <Cn>…<C> / <Sn>…<S> use; <FR> framerate,
// <FT> frametime and <APP> 3D API are filled in by RTSS for the game being drawn.
private const string Api = "<C2><APP><C>";
private const string Fps = "<C0><FR><C><C1><S0> FPS<S><C>";
private const string FrameTime = "<C0><FT><C><C1><S0> ms<S><C>";

/// <summary>The OSD text for a style; empty for Off and External (nothing of ours on screen).</summary>
public static string Text(string? style, FpsOverlayLayout? layout = null)
{
string[] items;
var color = Colors[0];
var separator = "\n";
switch (Normalize(style))
{
case Compact:
items = [Fps];
break;
case Detailed:
items = [Api, Fps, FrameTime];
break;
case Custom:
layout ??= new FpsOverlayLayout();
items = [.. new[] { (layout.ShowApi, Api), (layout.ShowFps, Fps), (layout.ShowFrameTime, FrameTime) }
.Where(i => i.Item1).Select(i => i.Item2)];
if (items.Length == 0) items = [Fps]; // nothing ticked still shows something
color = NormalizeColor(layout.Color);
if (layout.SingleLine) separator = " ";
break;
default:
return "";
}
return $"<C0={color}><C1=9AA4B2><C2=4CC2FF><S0=-55>" + string.Join(separator, items);
}

[GeneratedRegex("^[0-9A-Fa-f]{6}$")]
private static partial Regex HexColor();
}
Loading
Loading