306 lines
10 KiB
C#
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");
|
|
}
|
|
}
|
|
}
|
|
}
|