Files
Lithium/Lithium/MainWindow.xaml.cs
T
2025-11-22 22:24:21 -05:00

306 lines
10 KiB
C#

using System;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using Lua;
namespace Lithium
{
public partial class MainWindow : Window
{
private bool customSetEnabled = false;
// Hotkey debounce flags
private bool nextSetHeld = false;
private bool prevSetHeld = false;
private bool refreshHeld = false;
private bool switchSideHeld = false;
// CapsLock recoil toggle
private bool recoilEnabled = true;
private bool capsHeld = false;
// NEW: cooldown timestamps
private DateTime nextSetAllowed = DateTime.MinValue;
private DateTime prevSetAllowed = DateTime.MinValue;
public MainWindow()
{
InitializeComponent();
AppendConsole("Initializing Lithium...");
ConfigLoader.LoadInitConfig();
OperatorSets.LoadOperatorSets();
AppendConsole("Loaded Operators | Current Set: " + OperatorSets.CurrentSet);
string url = OperatorSets.ConfigExportUrl;
Browser.Source = !string.IsNullOrEmpty(url)
? new Uri(url)
: new Uri("https://jj.giggity.gay/exindex.html");
// Start hotkey watcher
Thread hotkeyThread = new Thread(HotkeyLoop);
hotkeyThread.IsBackground = true;
hotkeyThread.Start();
// Start recoil worker
Thread recoilThread = new Thread(RecoilLoop);
recoilThread.IsBackground = true;
recoilThread.Start();
}
// ============================================================
// RECOIL ENGINE (CapsLock toggle + both mouse buttons required)
// ============================================================
private void RecoilLoop()
{
const int RIGHT_MOUSE = 0x02;
while (true)
{
if (!recoilEnabled)
{
Thread.Sleep(1);
continue;
}
bool leftPressed = Utils.IsPressed(ConfigLoader.shootKey);
bool rightPressed = Utils.IsPressed(RIGHT_MOUSE);
bool shouldFire = leftPressed && rightPressed;
if (shouldFire)
{
var recoil = OperatorSets.GetCurrentRecoil();
if (recoil.recoilX != 0 || recoil.recoilY != 0)
{
Utils.MoveMouse(
(int)Math.Round(recoil.recoilX),
(int)Math.Round(recoil.recoilY)
);
}
}
Thread.Sleep(1);
}
}
// ============================================================
// HOTKEY THREAD (debounced + cooldowns + CapsLock toggle)
// ============================================================
private void HotkeyLoop()
{
const int CAPSLOCK = 0x14;
while (true)
{
// -------------------------------
// CAPSLOCK → Toggle recoil
// -------------------------------
bool capsDown = Utils.IsPressed(CAPSLOCK);
if (capsDown && !capsHeld)
{
capsHeld = true;
recoilEnabled = !recoilEnabled;
AppendConsole(recoilEnabled ? "Recoil Enabled" : "Recoil Disabled");
}
if (!capsDown) capsHeld = false;
// -------------------------------
// NEXT SET (cooldown)
// -------------------------------
bool nextDown = Utils.IsPressed(ConfigLoader.nextSetKey);
if (nextDown && !nextSetHeld && DateTime.Now >= nextSetAllowed)
{
nextSetHeld = true;
nextSetAllowed = DateTime.Now.AddMilliseconds(200);
OperatorSets.NextSet();
AppendConsole("Next Set → " + OperatorSets.CurrentSet);
Utils.SafeSpeak(OperatorSets.CurrentSet);
}
if (!nextDown) nextSetHeld = false;
// -------------------------------
// PREVIOUS SET (cooldown)
// -------------------------------
bool prevDown = Utils.IsPressed(ConfigLoader.prevSetKey);
if (prevDown && !prevSetHeld && DateTime.Now >= prevSetAllowed)
{
prevSetHeld = true;
prevSetAllowed = DateTime.Now.AddMilliseconds(200);
OperatorSets.PreviousSet();
AppendConsole("Previous Set → " + OperatorSets.CurrentSet);
Utils.SafeSpeak(OperatorSets.CurrentSet);
}
if (!prevDown) prevSetHeld = false;
// -------------------------------
// RELOAD CONFIG
// -------------------------------
bool refreshDown = Utils.IsPressed(ConfigLoader.refreshKey);
if (refreshDown && !refreshHeld)
{
refreshHeld = true;
OperatorSets.LoadOperatorSets();
AppendConsole("Reloaded config.");
}
if (!refreshDown) refreshHeld = false;
// -------------------------------
// SWITCH SIDE
// -------------------------------
bool switchDown = Utils.IsPressed(ConfigLoader.switchSideKey);
if (switchDown && !switchSideHeld)
{
switchSideHeld = true;
OperatorSets.SwitchSide();
AppendConsole("Switched side → " + (OperatorSets.onAttackers ? "Attackers" : "Defenders"));
}
if (!switchDown) switchSideHeld = false;
Thread.Sleep(8);
}
}
// ============================================================
// UI CONSOLE
// ============================================================
public void AppendConsole(string msg)
{
Dispatcher.Invoke(() =>
{
ConsoleOutput.Text += msg + Environment.NewLine;
ConsoleScroll.ScrollToBottom();
});
}
public void UpdateCustomSetConsole(string msg)
{
Dispatcher.Invoke(() =>
{
CustomSetConsole.Text = msg;
});
}
// ============================================================
// CUSTOM SET BUILDER
// ============================================================
private void ToggleCustomSet_Click(object sender, RoutedEventArgs e)
{
customSetEnabled = !customSetEnabled;
UpdateCustomSetConsole(customSetEnabled ? "Set is ON" : "Set is OFF");
}
private async void PublishSet_Click(object sender, RoutedEventArgs e)
{
string name = OperatorNameTextBox.Text.Trim();
if (string.IsNullOrEmpty(name))
{
UpdateCustomSetConsole("Error: Operator name required");
return;
}
if (!double.TryParse(RecoilXTextBox.Text, out var x)) x = 0;
if (!double.TryParse(RecoilYTextBox.Text, out var y)) y = 0;
string type = AttackerRadioButton.IsChecked == true ? "attackers" : "defenders";
var payload = new
{
type,
name,
recoilX = x,
recoilY = y
};
try
{
HttpClient client = new HttpClient();
string json = JsonSerializer.Serialize(payload);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync("https://jj.giggity.gay/api/global/add", content);
if (response.IsSuccessStatusCode)
{
UpdateCustomSetConsole($"Successfully published: {name} ({type}) X:{x} Y:{y}");
}
else
{
string errorText = await response.Content.ReadAsStringAsync();
UpdateCustomSetConsole($"Failed: {response.StatusCode} - {errorText}");
}
client.Dispose();
}
catch (Exception ex)
{
UpdateCustomSetConsole("Error publishing set: " + ex.Message);
}
}
private void SaveSet_Click(object sender, RoutedEventArgs e)
{
try
{
File.WriteAllText("custom_set.txt",
$"{OperatorNameTextBox.Text}|{RecoilXTextBox.Text}|{RecoilYTextBox.Text}|{(AttackerRadioButton.IsChecked == true ? "attacker" : "defender")}");
UpdateCustomSetConsole("Custom set saved");
}
catch
{
UpdateCustomSetConsole("Failed to save custom set");
}
}
private void LoadSet_Click(object sender, RoutedEventArgs e)
{
try
{
if (!File.Exists("custom_set.txt"))
{
UpdateCustomSetConsole("No saved set found");
return;
}
string[] parts = File.ReadAllText("custom_set.txt").Split('|');
if (parts.Length != 4) throw new Exception("Invalid file");
OperatorNameTextBox.Text = parts[0];
RecoilXTextBox.Text = parts[1];
RecoilYTextBox.Text = parts[2];
if (parts[3].Equals("attacker", StringComparison.OrdinalIgnoreCase))
AttackerRadioButton.IsChecked = true;
else
DefenderRadioButton.IsChecked = true;
UpdateCustomSetConsole("Custom set loaded");
}
catch
{
UpdateCustomSetConsole("Failed to load custom set");
}
}
}
}