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
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# SleepStrap 6.9
# SleepStrap 6.9.1

![SleepStrap icon](SleepStrap/SleepStrap.png)

SleepStrap is a purple Windows launcher for Roblox with skyboxes, texture presets, visual modes, fonts, and Rivals display tools.

[Download SleepStrap 6.9](https://github.com/SleepyDebug/SleepStrap/releases/tag/sleepstrap-6.9) · [Discord](https://discord.gg/W3CMjx8C7s) · [Report an issue](https://github.com/SleepyDebug/SleepStrap/issues)
[Download SleepStrap 6.9.1](https://github.com/SleepyDebug/SleepStrap/releases/tag/sleepstrap-6.9.1) · [Discord](https://discord.gg/W3CMjx8C7s) · [Report an issue](https://github.com/SleepyDebug/SleepStrap/issues)

## Repository layout

Expand All @@ -25,7 +25,7 @@ SleepStrap is a purple Windows launcher for Roblox with skyboxes, texture preset
- Montserrat-first selector for Roblox GUI and direct in-game text fonts
- PC display stretching and Roblox FPS presets
- Replay-buffer clipping with configurable capture devices, audio, duration, and hotkey
- RIVALS loadout macro with missing-weapon calibration, automatic actions, and hourly Auto Rejoin
- RIVALS loadout macro with missing-weapon calibration, a hidden hotkey-driven Quick Loadout, automatic actions, and hourly Auto Rejoin
- Automatic GitHub release checks with a confirmation prompt before updating
- Other page with Discord, version, attribution, and terms

Expand Down
6 changes: 6 additions & 0 deletions SleepStrap/Models/Persistable/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,12 @@ public class Settings
public string MacroSecondaryWeapon { get; set; } = "Warper";
public string MacroMeleeWeapon { get; set; } = "Maul";
public string MacroUtilityWeapon { get; set; } = "Grappler";
public string MacroQuickLoadoutPrimaryWeapon { get; set; } = "Distortion";
public string MacroQuickLoadoutSecondaryWeapon { get; set; } = "Warper";
public string MacroQuickLoadoutMeleeWeapon { get; set; } = "Maul";
public string MacroQuickLoadoutUtilityWeapon { get; set; } = "Grappler";
public int MacroQuickLoadoutHotkeyModifiers { get; set; } = 3; // Ctrl + Alt
public int MacroQuickLoadoutHotkeyVirtualKey { get; set; } = 0x51; // Q
public bool MacroQuickRespawn { get; set; } = false;
public bool MacroAutoUtility { get; set; } = false;
public bool MacroAutoInspect { get; set; } = false;
Expand Down
17 changes: 12 additions & 5 deletions SleepStrap/Services/ReplayBufferService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Windows.Interop;

using ScreenRecorderLib;
Expand Down Expand Up @@ -34,6 +35,7 @@ public void Start()
Directory.CreateDirectory(Paths.Playbacks);
Directory.CreateDirectory(GetBufferDirectory());
RegisterHotkey();
App.Logger.WriteLine("ReplayBufferService::Start", "Starting the replay capture loop");
_captureTask = Task.Run(() => CaptureLoopAsync(_stopToken.Token));
}

Expand All @@ -44,7 +46,7 @@ public void SaveReplay()

Interlocked.Exchange(ref _saveRequested, 1);
try { _rotateSignal.Release(); } catch (SemaphoreFullException) { }
Frontend.ShowBalloonTip("SleepStrap Clipping", "Saving replay…");
App.Logger.WriteLine("ReplayBufferService::SaveReplay", "Replay save requested");
}

private async Task CaptureLoopAsync(CancellationToken cancellationToken)
Expand Down Expand Up @@ -204,7 +206,7 @@ private async Task RenderReplayAsync(IReadOnlyList<ReplaySegment> availableSegme

if (selected.Count == 0)
{
Frontend.ShowBalloonTip("SleepStrap Clipping", "The replay buffer is still warming up.");
App.Logger.WriteLine("ReplayBufferService::SaveReplay", "Replay buffer is still warming up");
return;
}

Expand Down Expand Up @@ -242,12 +244,11 @@ private async Task RenderReplayAsync(IReadOnlyList<ReplaySegment> availableSegme
if (result != TranscodeFailureReason.None)
throw new InvalidOperationException($"Windows could not render the replay ({result}).");

Frontend.ShowBalloonTip("SleepStrap Clipping", $"Saved {Path.GetFileName(output.Path)}");
App.Logger.WriteLine("ReplayBufferService::SaveReplay", $"Saved {output.Path}");
}
catch (Exception ex)
{
App.Logger.WriteException("ReplayBufferService::SaveReplay", ex);
Frontend.ShowBalloonTip("SleepStrap Clipping", "The replay could not be saved.", System.Windows.Forms.ToolTipIcon.Error);
}
}

Expand Down Expand Up @@ -278,14 +279,20 @@ private void RegisterHotkey()
uint modifiers = (uint)App.Settings.Prop.ClippingHotkeyModifiers | 0x4000; // MOD_NOREPEAT
uint virtualKey = (uint)App.Settings.Prop.ClippingHotkeyVirtualKey;
if (!RegisterHotKey(_hotkeyWindow.Handle, HotkeyId, modifiers, virtualKey))
App.Logger.WriteLine("ReplayBufferService::Hotkey", "The configured replay hotkey is already in use");
{
int error = Marshal.GetLastWin32Error();
throw new Win32Exception(error, "The configured replay hotkey could not be registered");
}

App.Logger.WriteLine("ReplayBufferService::Hotkey", $"Registered global replay hotkey modifiers=0x{modifiers:X} key=0x{virtualKey:X}");
}

private IntPtr HotkeyWindowHook(IntPtr hwnd, int message, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (message == 0x0312 && wParam.ToInt32() == HotkeyId)
{
handled = true;
App.Logger.WriteLine("ReplayBufferService::Hotkey", "Global replay hotkey pressed");
SaveReplay();
}

Expand Down
8 changes: 6 additions & 2 deletions SleepStrap/SleepStrap.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,16 @@
<UseWPF>true</UseWPF>
<UseWindowsForms>True</UseWindowsForms>
<ApplicationIcon>SleepStrap.ico</ApplicationIcon>
<Version>6.9.0.0</Version>
<FileVersion>6.9.0.0</FileVersion>
<Version>6.9.1.0</Version>
<FileVersion>6.9.1.0</FileVersion>
<ApplicationManifest>app.manifest</ApplicationManifest>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Platforms>x64</Platforms>
<PlatformTarget>x64</PlatformTarget>
<!-- ScreenRecorderLib is a mixed-mode C++/CLI assembly and must be loaded
from disk. Keep the public download as one EXE, but extract all bundled
runtime files before startup so the clipping host cannot native-crash. -->
<IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
<AssemblyName>SleepStrap</AssemblyName>
<Product>$(AssemblyName)</Product>
Expand Down
3 changes: 2 additions & 1 deletion SleepStrap/UI/Elements/Settings/Pages/ClippingPage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ public ClippingPage()
_viewModel = new ClippingViewModel();
DataContext = _viewModel;
InitializeComponent();
Unloaded += (_, _) => _viewModel.Dispose();
Loaded += (_, _) => _viewModel.StartLiveUpdates();
Unloaded += (_, _) => _viewModel.StopLiveUpdates();
}

private void HotkeyBox_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
Expand Down
41 changes: 40 additions & 1 deletion SleepStrap/UI/Elements/Settings/Pages/MacroPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
xmlns:dmodels="clr-namespace:SleepStrap.UI.ViewModels.Settings"
mc:Ignorable="d" d:DataContext="{d:DesignInstance dmodels:MacroViewModel, IsDesignTimeCreatable=False}"
d:DesignHeight="700" d:DesignWidth="800" Title="Macro" Scrollable="True">
d:DesignHeight="700" d:DesignWidth="800" Title="Macro" Scrollable="True"
PreviewKeyDown="Page_PreviewKeyDown">
<ui:UiPage.Resources>
<DataTemplate x:Key="WeaponChoiceTemplate">
<StackPanel Orientation="Horizontal" Margin="0,3">
Expand Down Expand Up @@ -145,5 +146,43 @@
Appearance="Primary" HorizontalAlignment="Stretch" Padding="16,10" />
</StackPanel>
</ui:CardExpander>

<ui:CardExpander Margin="0,10,0,0" IsExpanded="True" Visibility="{Binding QuickLoadoutVisibility}">
<ui:CardExpander.Header>
<TextBlock Text="Quick loadout" FontSize="17" FontWeight="SemiBold" />
</ui:CardExpander.Header>
<StackPanel>
<UniformGrid Columns="2">
<StackPanel Margin="0,0,8,12">
<TextBlock Text="Primary" Margin="0,0,0,5" FontWeight="SemiBold" />
<ComboBox ItemsSource="{Binding AvailablePrimary}" SelectedItem="{Binding QuickSelectedPrimary, Mode=TwoWay}"
ItemTemplate="{StaticResource WeaponChoiceTemplate}" />
</StackPanel>
<StackPanel Margin="8,0,0,12">
<TextBlock Text="Secondary" Margin="0,0,0,5" FontWeight="SemiBold" />
<ComboBox ItemsSource="{Binding AvailableSecondary}" SelectedItem="{Binding QuickSelectedSecondary, Mode=TwoWay}"
ItemTemplate="{StaticResource WeaponChoiceTemplate}" />
</StackPanel>
<StackPanel Margin="0,0,8,12">
<TextBlock Text="Melee" Margin="0,0,0,5" FontWeight="SemiBold" />
<ComboBox ItemsSource="{Binding AvailableMelee}" SelectedItem="{Binding QuickSelectedMelee, Mode=TwoWay}"
ItemTemplate="{StaticResource WeaponChoiceTemplate}" />
</StackPanel>
<StackPanel Margin="8,0,0,12">
<TextBlock Text="Utility" Margin="0,0,0,5" FontWeight="SemiBold" />
<ComboBox ItemsSource="{Binding AvailableUtility}" SelectedItem="{Binding QuickSelectedUtility, Mode=TwoWay}"
ItemTemplate="{StaticResource WeaponChoiceTemplate}" />
</StackPanel>
</UniformGrid>

<TextBlock Text="Quick loadout hotkey" Margin="0,2,0,5" FontWeight="SemiBold" />
<TextBox x:Name="QuickHotkeyBox" Height="38" IsReadOnly="True" Cursor="Hand"
HorizontalContentAlignment="Center" VerticalContentAlignment="Center"
FontWeight="SemiBold" Text="{Binding QuickLoadoutHotkeyDisplay, Mode=OneWay}"
PreviewMouseLeftButtonDown="QuickHotkeyBox_PreviewMouseLeftButtonDown"
PreviewKeyDown="QuickHotkeyBox_PreviewKeyDown"
LostKeyboardFocus="QuickHotkeyBox_LostKeyboardFocus" />
</StackPanel>
</ui:CardExpander>
</StackPanel>
</ui:UiPage>
92 changes: 91 additions & 1 deletion SleepStrap/UI/Elements/Settings/Pages/MacroPage.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,103 @@
using System.Windows.Controls;
using System.Windows.Input;

using SleepStrap.UI.ViewModels.Settings;

namespace SleepStrap.UI.Elements.Settings.Pages
{
public partial class MacroPage
{
private readonly MacroViewModel _viewModel;
private bool _capturingQuickHotkey;
private int _pendingModifiers;
private int _pendingVirtualKey;

public MacroPage()
{
DataContext = new MacroViewModel();
_viewModel = new MacroViewModel();
DataContext = _viewModel;
InitializeComponent();
}

private void Page_PreviewKeyDown(object sender, KeyEventArgs e)
{
Key key = e.Key == Key.System ? e.SystemKey : e.Key;
bool sevenDown = Keyboard.IsKeyDown(Key.D7) || Keyboard.IsKeyDown(Key.NumPad7);
bool revealChord = ((key == Key.D7 || key == Key.NumPad7) && Keyboard.IsKeyDown(Key.U)) ||
(key == Key.U && sevenDown);
if (!revealChord)
return;

_viewModel.RevealQuickLoadout();
e.Handled = true;
}

private void QuickHotkeyBox_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
_capturingQuickHotkey = true;
_viewModel.SetQuickHotkeyCaptureActive(true);
_pendingModifiers = 0;
_pendingVirtualKey = 0;
QuickHotkeyBox.Text = "Press keys, then Enter";
QuickHotkeyBox.Focus();
Keyboard.Focus(QuickHotkeyBox);
e.Handled = true;
}

private void QuickHotkeyBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (!_capturingQuickHotkey)
return;

e.Handled = true;
Key key = e.Key == Key.System ? e.SystemKey : e.Key;
if (key == Key.Enter)
{
if (_pendingVirtualKey != 0)
_viewModel.SetQuickLoadoutHotkey(_pendingModifiers, _pendingVirtualKey);
FinishQuickHotkeyCapture();
return;
}
if (key == Key.Escape)
{
FinishQuickHotkeyCapture();
return;
}
if (key is Key.LeftAlt or Key.RightAlt or Key.LeftCtrl or Key.RightCtrl or Key.LeftShift or Key.RightShift or Key.LWin or Key.RWin)
return;

ModifierKeys modifiers = Keyboard.Modifiers;
_pendingModifiers = 0;
if (modifiers.HasFlag(ModifierKeys.Alt)) _pendingModifiers |= 1;
if (modifiers.HasFlag(ModifierKeys.Control)) _pendingModifiers |= 2;
if (modifiers.HasFlag(ModifierKeys.Shift)) _pendingModifiers |= 4;
if (modifiers.HasFlag(ModifierKeys.Windows)) _pendingModifiers |= 8;
_pendingVirtualKey = KeyInterop.VirtualKeyFromKey(key);
QuickHotkeyBox.Text = FormatHotkey(key, modifiers) + " • press Enter";
}

private void QuickHotkeyBox_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
if (_capturingQuickHotkey)
FinishQuickHotkeyCapture();
}

private void FinishQuickHotkeyCapture()
{
_capturingQuickHotkey = false;
_viewModel.SetQuickHotkeyCaptureActive(false);
QuickHotkeyBox.GetBindingExpression(TextBox.TextProperty)?.UpdateTarget();
}

private static string FormatHotkey(Key key, ModifierKeys modifiers)
{
var parts = new List<string>();
if (modifiers.HasFlag(ModifierKeys.Control)) parts.Add("Ctrl");
if (modifiers.HasFlag(ModifierKeys.Alt)) parts.Add("Alt");
if (modifiers.HasFlag(ModifierKeys.Shift)) parts.Add("Shift");
if (modifiers.HasFlag(ModifierKeys.Windows)) parts.Add("Win");
parts.Add(key.ToString());
return String.Join(" + ", parts);
}
}
}
4 changes: 2 additions & 2 deletions SleepStrap/UI/Elements/Settings/Pages/OtherPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@

<Run FontWeight="SemiBold" Foreground="{DynamicResource TextFillColorPrimaryBrush}" Text="2. Fork and attribution." />
<LineBreak />
<Run Text="SleepStrap is a fork derived from Fishstrap and Bloxstrap and also uses code, libraries, concepts, and assets from the wider open-source software community. Fishstrap, Bloxstrap, their contributors, and included third-party projects remain separate projects owned by their respective authors. Their retained license notices apply to the portions of software they cover. SleepStrap does not claim ownership of Roblox, Fishstrap, Bloxstrap, or third-party intellectual property." />
<Run Text="SleepStrap is a fork derived from upstream open-source Roblox launcher projects and also uses code, libraries, concepts, and assets from the wider open-source software community. Those projects, their contributors, and included third-party projects remain separate works owned by their respective authors. Their retained license notices apply to the portions of software they cover. SleepStrap does not claim ownership of Roblox or third-party intellectual property." />
<LineBreak /><LineBreak />

<Run FontWeight="SemiBold" Foreground="{DynamicResource TextFillColorPrimaryBrush}" Text="3. Account enforcement and bans." />
Expand Down Expand Up @@ -125,7 +125,7 @@

<Run FontWeight="SemiBold" Foreground="{DynamicResource TextFillColorPrimaryBrush}" Text="8. Limitation of responsibility." />
<LineBreak />
<Run Text="To the fullest extent allowed by applicable law, the SleepStrap maintainers, distributors, contributors, Fishstrap contributors, Bloxstrap contributors, and third-party component authors are not liable for direct, indirect, incidental, special, consequential, exemplary, or punitive losses arising from SleepStrap. This includes account penalties, lost data, lost revenue, lost purchases, lost opportunities, interruption, device problems, and claims by other people, even if someone was told such harm could occur." />
<Run Text="To the fullest extent allowed by applicable law, the SleepStrap maintainers, distributors, contributors, upstream project contributors, and third-party component authors are not liable for direct, indirect, incidental, special, consequential, exemplary, or punitive losses arising from SleepStrap. This includes account penalties, lost data, lost revenue, lost purchases, lost opportunities, interruption, device problems, and claims by other people, even if someone was told such harm could occur." />
<LineBreak /><LineBreak />

<Run FontWeight="SemiBold" Foreground="{DynamicResource TextFillColorPrimaryBrush}" Text="9. Continuing to use SleepStrap." />
Expand Down
Loading
Loading