diff --git a/workspaces/dotnet/galaxy-unleashed-runtime/src/Dispose.cs b/workspaces/dotnet/galaxy-unleashed-runtime/src/Dispose.cs index 4ffdcfc..4cdedf9 100644 --- a/workspaces/dotnet/galaxy-unleashed-runtime/src/Dispose.cs +++ b/workspaces/dotnet/galaxy-unleashed-runtime/src/Dispose.cs @@ -22,6 +22,10 @@ public void Dispose() using (new ProcessingScope()) { + _jetpackBooster.Dispose(); + + _jumpBooster.Dispose(); + foreach (var npcSpawner in _npcSpawners.ToList()) { npcSpawner.Dispose(); diff --git a/workspaces/dotnet/galaxy-unleashed-runtime/src/JetpackBooster.cs b/workspaces/dotnet/galaxy-unleashed-runtime/src/JetpackBooster.cs new file mode 100644 index 0000000..95f728e --- /dev/null +++ b/workspaces/dotnet/galaxy-unleashed-runtime/src/JetpackBooster.cs @@ -0,0 +1,217 @@ +using System; +using System.Numerics; +using System.Runtime.InteropServices; +using OMP.LSWTSS.CApi1; + +namespace OMP.LSWTSS; + +public partial class GalaxyUnleashed +{ + readonly JetpackBooster _jetpackBooster = new(); + + class JetpackBooster : IDisposable + { + public bool IsDisposed { get; private set; } + + public JetpackBoosterState State { get; private set; } + + readonly InputHook1.Client _jetpackInputHookClient; + + struct JetpackState + { + public EP9JetpackContext.NativeHandle EP9JetpackContext; + + public int EP9JetpackContextAmountOfBursts; + + public float EP9JetpackContextFuelDepletionMultiplier; + } + + JetpackState? _jetpackSavedState; + + bool _isTurboKeyPressed; + + bool _isFlyUpKeyPressed; + + bool _isFlyDownKeyPressed; + + public JetpackBooster() + { + IsDisposed = false; + + State = new JetpackBoosterState + { + IsEnabled = false, + Config = new() + { + IsUnlimitedFuelEnabled = true, + TurboSpeedMultiplier = 5 + } + }; + + _jetpackInputHookClient = new InputHook1.Client( + 0, + (in InputHook1.NativeMessage jetpackInputHookNativeMessage) => + { + if (jetpackInputHookNativeMessage.WParam == (int)PInvoke.User32.VirtualKey.VK_SHIFT) + { + if (jetpackInputHookNativeMessage.Type == (int)PInvoke.User32.WindowMessage.WM_KEYDOWN) + { + _isTurboKeyPressed = true; + } + else if (jetpackInputHookNativeMessage.Type == (int)PInvoke.User32.WindowMessage.WM_KEYUP) + { + _isTurboKeyPressed = false; + } + } + else if (jetpackInputHookNativeMessage.WParam == (int)PInvoke.User32.VirtualKey.VK_C) + { + if (jetpackInputHookNativeMessage.Type == (int)PInvoke.User32.WindowMessage.WM_KEYDOWN) + { + _isFlyUpKeyPressed = true; + } + else if (jetpackInputHookNativeMessage.Type == (int)PInvoke.User32.WindowMessage.WM_KEYUP) + { + _isFlyUpKeyPressed = false; + } + } + else if (jetpackInputHookNativeMessage.WParam == (int)PInvoke.User32.VirtualKey.VK_X) + { + if (jetpackInputHookNativeMessage.Type == (int)PInvoke.User32.WindowMessage.WM_KEYDOWN) + { + _isFlyDownKeyPressed = true; + } + else if (jetpackInputHookNativeMessage.Type == (int)PInvoke.User32.WindowMessage.WM_KEYUP) + { + _isFlyDownKeyPressed = false; + } + } + + return false; + } + ); + + _jetpackSavedState = null; + } + + void ThrowIfDisposed() + { + if (IsDisposed) + { + throw new InvalidOperationException(); + } + } + + void SaveJetpackState(EP9JetpackContext.NativeHandle ep9JetpackContext) + { + _jetpackSavedState = new JetpackState + { + EP9JetpackContext = ep9JetpackContext, + EP9JetpackContextAmountOfBursts = ep9JetpackContext.AmountOfBursts, + EP9JetpackContextFuelDepletionMultiplier = ep9JetpackContext.FuelDepletionMultiplier + }; + } + + void RestoreJetpackState() + { + if (!_jetpackSavedState.HasValue) + { + return; + } + + var ep9JetpackContext = _jetpackSavedState.Value.EP9JetpackContext; + + if (ep9JetpackContext.IsActive()) + { + ep9JetpackContext.AmountOfBursts = _jetpackSavedState.Value.EP9JetpackContextAmountOfBursts; + ep9JetpackContext.FuelDepletionMultiplier = _jetpackSavedState.Value.EP9JetpackContextFuelDepletionMultiplier; + } + + _jetpackSavedState = null; + } + + public void Update() + { + ThrowIfDisposed(); + + RestoreJetpackState(); + + if (State.IsEnabled) + { + var playerEntity = _instance!.FetchPlayerEntity(); + + if (playerEntity != nint.Zero) + { + var ep9JetpackContext = (EP9JetpackContext.NativeHandle)playerEntity.FindComponentByTypeNameRecursive( + EP9JetpackContext.Info.ApiClassName, + false + ); + + if (ep9JetpackContext != nint.Zero) + { + SaveJetpackState(ep9JetpackContext); + + ep9JetpackContext.AmountOfBursts = 99999; + if (State.Config.IsUnlimitedFuelEnabled) + { + ep9JetpackContext.FuelDepletionMultiplier = 0f; + } + + var horizontalVelocityX = BitConverter.ToSingle(BitConverter.GetBytes(Marshal.ReadInt32(ep9JetpackContext.NativeDataRawPtr + 0x3e0))); + var horizontalVelocityY = BitConverter.ToSingle(BitConverter.GetBytes(Marshal.ReadInt32(ep9JetpackContext.NativeDataRawPtr + 0x3e8))); + + var horizontalVelocity = new Vector2(horizontalVelocityX, horizontalVelocityY); + + if (_isTurboKeyPressed) + { + if (horizontalVelocity.Length() > 0.5f) + { + horizontalVelocity = Vector2.Normalize(horizontalVelocity) * State.Config.TurboSpeedMultiplier; + Marshal.WriteInt32(ep9JetpackContext.NativeDataRawPtr + 0x3e0, BitConverter.ToInt32(BitConverter.GetBytes(horizontalVelocity.X))); + Marshal.WriteInt32(ep9JetpackContext.NativeDataRawPtr + 0x3e8, BitConverter.ToInt32(BitConverter.GetBytes(horizontalVelocity.Y))); + } + } + else + { + if (horizontalVelocity.Length() > 1f) + { + horizontalVelocity = Vector2.Normalize(horizontalVelocity); + Marshal.WriteInt32(ep9JetpackContext.NativeDataRawPtr + 0x3e0, BitConverter.ToInt32(BitConverter.GetBytes(horizontalVelocity.X))); + Marshal.WriteInt32(ep9JetpackContext.NativeDataRawPtr + 0x3e8, BitConverter.ToInt32(BitConverter.GetBytes(horizontalVelocity.Y))); + } + } + + if (_isFlyUpKeyPressed || _isFlyDownKeyPressed) + { + var verticalVelocity = BitConverter.ToSingle(BitConverter.GetBytes(Marshal.ReadInt32(ep9JetpackContext.NativeDataRawPtr + 0x414))); + + if (_isFlyUpKeyPressed) + { + verticalVelocity = Math.Min(2f, verticalVelocity + 0.1f); + } + else if (_isFlyDownKeyPressed) + { + verticalVelocity = Math.Max(-2f, verticalVelocity - 0.1f); + } + + Marshal.WriteInt32(ep9JetpackContext.NativeDataRawPtr + 0x414, BitConverter.ToInt32(BitConverter.GetBytes(verticalVelocity))); + } + } + } + } + } + + public void Dispose() + { + if (IsDisposed) + { + return; + } + + _jetpackInputHookClient.Dispose(); + + RestoreJetpackState(); + + IsDisposed = true; + } + } +} \ No newline at end of file diff --git a/workspaces/dotnet/galaxy-unleashed-runtime/src/JetpackBoosterConfig.cs b/workspaces/dotnet/galaxy-unleashed-runtime/src/JetpackBoosterConfig.cs new file mode 100644 index 0000000..2dfaf70 --- /dev/null +++ b/workspaces/dotnet/galaxy-unleashed-runtime/src/JetpackBoosterConfig.cs @@ -0,0 +1,11 @@ +namespace OMP.LSWTSS; + +public partial class GalaxyUnleashed +{ + class JetpackBoosterConfig + { + public required bool IsUnlimitedFuelEnabled; + + public required int TurboSpeedMultiplier; + } +} \ No newline at end of file diff --git a/workspaces/dotnet/galaxy-unleashed-runtime/src/JetpackBoosterState.cs b/workspaces/dotnet/galaxy-unleashed-runtime/src/JetpackBoosterState.cs new file mode 100644 index 0000000..a0f5d3e --- /dev/null +++ b/workspaces/dotnet/galaxy-unleashed-runtime/src/JetpackBoosterState.cs @@ -0,0 +1,11 @@ +namespace OMP.LSWTSS; + +public partial class GalaxyUnleashed +{ + class JetpackBoosterState + { + public required bool IsEnabled; + + public required JetpackBoosterConfig Config; + } +} \ No newline at end of file diff --git a/workspaces/dotnet/galaxy-unleashed-runtime/src/JumpBooster.cs b/workspaces/dotnet/galaxy-unleashed-runtime/src/JumpBooster.cs new file mode 100644 index 0000000..6eaf950 --- /dev/null +++ b/workspaces/dotnet/galaxy-unleashed-runtime/src/JumpBooster.cs @@ -0,0 +1,155 @@ +using System; +using OMP.LSWTSS.CApi1; + +namespace OMP.LSWTSS; + +public partial class GalaxyUnleashed +{ + readonly JumpBooster _jumpBooster = new(); + + class JumpBooster : IDisposable + { + public bool IsDisposed { get; private set; } + + public JumpBoosterState State { get; private set; } + + struct JumpState + { + public JumpContext.NativeHandle JumpContext; + + public float JumpContextJumpHeight; + + public DoubleJumpContext.NativeHandle DoubleJumpContext; + + public int DoubleJumpContextNumberOfDoubleJumps; + + public float DoubleJumpContextJumpHeight; + } + + JumpState? _jumpSavedState; + + public JumpBooster() + { + IsDisposed = false; + + State = new JumpBoosterState + { + IsEnabled = false, + Config = new() + { + IsUnlimitedDoubleJumpsEnabled = true, + JumpHeightMultiplier = 2 + } + }; + + _jumpSavedState = null; + } + + void ThrowIfDisposed() + { + if (IsDisposed) + { + throw new InvalidOperationException(); + } + } + + void SaveJumpState(JumpContext.NativeHandle jumpContext, DoubleJumpContext.NativeHandle doubleJumpContext) + { + _jumpSavedState = new JumpState + { + JumpContext = jumpContext, + JumpContextJumpHeight = jumpContext != nint.Zero ? jumpContext.JumpData.JumpHeight : 0f, + DoubleJumpContext = doubleJumpContext, + DoubleJumpContextNumberOfDoubleJumps = doubleJumpContext != nint.Zero ? doubleJumpContext.NumberOfDoubleJumps : 0, + DoubleJumpContextJumpHeight = doubleJumpContext != nint.Zero ? doubleJumpContext.DoubleJumpData.JumpHeight : 0f + }; + } + + void RestoreJumpState() + { + if (!_jumpSavedState.HasValue) + { + return; + } + + var jumpContext = _jumpSavedState.Value.JumpContext; + var doubleJumpContext = _jumpSavedState.Value.DoubleJumpContext; + + if (jumpContext != nint.Zero && jumpContext.IsActive()) + { + var jumpContextJumpData = jumpContext.JumpData; + + jumpContextJumpData.JumpHeight = _jumpSavedState.Value.JumpContextJumpHeight; + } + + if (doubleJumpContext != nint.Zero && doubleJumpContext.IsActive()) + { + doubleJumpContext.NumberOfDoubleJumps = _jumpSavedState.Value.DoubleJumpContextNumberOfDoubleJumps; + + var doubleJumpContextDoubleJumpData = doubleJumpContext.DoubleJumpData; + + doubleJumpContextDoubleJumpData.JumpHeight = _jumpSavedState.Value.DoubleJumpContextJumpHeight; + } + + _jumpSavedState = null; + } + + public void Update() + { + ThrowIfDisposed(); + + RestoreJumpState(); + + if (State.IsEnabled) + { + var playerEntity = _instance!.FetchPlayerEntity(); + + if (playerEntity != nint.Zero) + { + var jumpContext = (JumpContext.NativeHandle)playerEntity.FindComponentByTypeNameRecursive( + JumpContext.Info.ApiClassName, + false + ); + + var doubleJumpContext = (DoubleJumpContext.NativeHandle)playerEntity.FindComponentByTypeNameRecursive( + DoubleJumpContext.Info.ApiClassName, + false + ); + + SaveJumpState(jumpContext, doubleJumpContext); + + if (jumpContext != nint.Zero) + { + var jumpContextJumpData = jumpContext.JumpData; + + jumpContextJumpData.JumpHeight *= State.Config.JumpHeightMultiplier; + } + + if (doubleJumpContext != nint.Zero) + { + if (State.Config.IsUnlimitedDoubleJumpsEnabled) + { + doubleJumpContext.NumberOfDoubleJumps = 0; + } + + var doubleJumpContextDoubleJumpData = doubleJumpContext.DoubleJumpData; + + doubleJumpContextDoubleJumpData.JumpHeight *= State.Config.JumpHeightMultiplier; + } + } + } + } + + public void Dispose() + { + if (IsDisposed) + { + return; + } + + RestoreJumpState(); + + IsDisposed = true; + } + } +} \ No newline at end of file diff --git a/workspaces/dotnet/galaxy-unleashed-runtime/src/JumpBoosterConfig.cs b/workspaces/dotnet/galaxy-unleashed-runtime/src/JumpBoosterConfig.cs new file mode 100644 index 0000000..968967b --- /dev/null +++ b/workspaces/dotnet/galaxy-unleashed-runtime/src/JumpBoosterConfig.cs @@ -0,0 +1,11 @@ +namespace OMP.LSWTSS; + +public partial class GalaxyUnleashed +{ + class JumpBoosterConfig + { + public required bool IsUnlimitedDoubleJumpsEnabled; + + public required int JumpHeightMultiplier; + } +} \ No newline at end of file diff --git a/workspaces/dotnet/galaxy-unleashed-runtime/src/JumpBoosterState.cs b/workspaces/dotnet/galaxy-unleashed-runtime/src/JumpBoosterState.cs new file mode 100644 index 0000000..cf4941c --- /dev/null +++ b/workspaces/dotnet/galaxy-unleashed-runtime/src/JumpBoosterState.cs @@ -0,0 +1,11 @@ +namespace OMP.LSWTSS; + +public partial class GalaxyUnleashed +{ + class JumpBoosterState + { + public required bool IsEnabled; + + public required JumpBoosterConfig Config; + } +} \ No newline at end of file diff --git a/workspaces/dotnet/galaxy-unleashed-runtime/src/LoadOverlay.cs b/workspaces/dotnet/galaxy-unleashed-runtime/src/LoadOverlay.cs index 79ed587..f31610c 100644 --- a/workspaces/dotnet/galaxy-unleashed-runtime/src/LoadOverlay.cs +++ b/workspaces/dotnet/galaxy-unleashed-runtime/src/LoadOverlay.cs @@ -1,9 +1,45 @@ using System; +using System.Diagnostics; +using CefSharp; namespace OMP.LSWTSS; public partial class GalaxyUnleashed : IDisposable { + class OverlayChromieumWebBrowserLifeSpanHandler : ILifeSpanHandler + { + public bool DoClose(IWebBrowser chromiumWebBrowser, IBrowser browser) + { + return false; + } + + public void OnAfterCreated(IWebBrowser chromiumWebBrowser, IBrowser browser) + { + } + + public void OnBeforeClose(IWebBrowser chromiumWebBrowser, IBrowser browser) + { + } + + public bool OnBeforePopup(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, string targetUrl, string targetFrameName, WindowOpenDisposition targetDisposition, bool userGesture, IPopupFeatures popupFeatures, IWindowInfo windowInfo, IBrowserSettings browserSettings, ref bool noJavascriptAccess, out IWebBrowser? newBrowser) + { + try + { + Process.Start(new ProcessStartInfo + { + FileName = "explorer", + Arguments = "\"" + targetUrl + "\"" + }); + } + catch + { + } + + newBrowser = null; + return true; + } + } + void LoadOverlay() { _overlay.ChromiumWebBrowser.JavascriptObjectRepository.NameConverter = @@ -15,6 +51,8 @@ void LoadOverlay() options: CefSharp.BindingOptions.DefaultBinder ); + _overlay.ChromiumWebBrowser.LifeSpanHandler = new OverlayChromieumWebBrowserLifeSpanHandler(); + string overlayUrl; if (Environment.GetEnvironmentVariable("DEV_GALAXY_UNLEASHED") == "1") diff --git a/workspaces/dotnet/galaxy-unleashed-runtime/src/RuntimeApi.cs b/workspaces/dotnet/galaxy-unleashed-runtime/src/RuntimeApi.cs index d8bf1ac..9a61153 100644 --- a/workspaces/dotnet/galaxy-unleashed-runtime/src/RuntimeApi.cs +++ b/workspaces/dotnet/galaxy-unleashed-runtime/src/RuntimeApi.cs @@ -106,6 +106,64 @@ public void SetIsBattleActive(string argsAsJson) _instance!._battle.State.IsActive = args.IsBattleActive; } + public string FetchJetpackBoosterState(string argsAsJson) + { + return JsonConvert.SerializeObject(_instance!._jetpackBooster.State, _jsonSerializerSettings); + } + + struct SetIsJetpackBoosterEnabledArgs + { + public bool IsJetpackBoosterEnabled; + } + + public void SetIsJetpackBoosterEnabled(string argsAsJson) + { + var args = JsonConvert.DeserializeObject(argsAsJson, _jsonSerializerSettings); + + _instance!._jetpackBooster.State.IsEnabled = args.IsJetpackBoosterEnabled; + } + + struct SetJetpackBoosterConfigArgs + { + public JetpackBoosterConfig JetpackBoosterConfig; + } + + public void SetJetpackBoosterConfig(string argsAsJson) + { + var args = JsonConvert.DeserializeObject(argsAsJson, _jsonSerializerSettings); + + _instance!._jetpackBooster.State.Config = args.JetpackBoosterConfig; + } + + public string FetchJumpBoosterState(string argsAsJson) + { + return JsonConvert.SerializeObject(_instance!._jumpBooster.State, _jsonSerializerSettings); + } + + struct SetIsJumpBoosterEnabledArgs + { + public bool IsJumpBoosterEnabled; + } + + public void SetIsJumpBoosterEnabled(string argsAsJson) + { + var args = JsonConvert.DeserializeObject(argsAsJson, _jsonSerializerSettings); + + _instance!._jumpBooster.State.IsEnabled = args.IsJumpBoosterEnabled; + } + + struct SetJumpBoosterConfigArgs + { + public JumpBoosterConfig JumpBoosterConfig; + } + + public void SetJumpBoosterConfig(string argsAsJson) + { + var args = JsonConvert.DeserializeObject(argsAsJson, _jsonSerializerSettings); + + _instance!._jumpBooster.State.Config = args.JumpBoosterConfig; + } + public string FetchModeState(string argsAsJson) { return JsonConvert.SerializeObject(_instance!._modeState, _jsonSerializerSettings); diff --git a/workspaces/dotnet/galaxy-unleashed-runtime/src/Update.cs b/workspaces/dotnet/galaxy-unleashed-runtime/src/Update.cs index 04f3377..6291617 100644 --- a/workspaces/dotnet/galaxy-unleashed-runtime/src/Update.cs +++ b/workspaces/dotnet/galaxy-unleashed-runtime/src/Update.cs @@ -17,6 +17,10 @@ void Update() using (new ProcessingScope()) { + _jetpackBooster.Update(); + + _jumpBooster.Update(); + UpdateCharactersInfo(); _playerEntityLastPosition = FetchPlayerEntityPosition(); diff --git a/workspaces/js/galaxy-unleashed-overlay/src/lib/runtime-shared-api.ts b/workspaces/js/galaxy-unleashed-overlay/src/lib/runtime-shared-api.ts index f6f9d59..fac4312 100644 --- a/workspaces/js/galaxy-unleashed-overlay/src/lib/runtime-shared-api.ts +++ b/workspaces/js/galaxy-unleashed-overlay/src/lib/runtime-shared-api.ts @@ -41,6 +41,16 @@ export interface NpcSpawnerConfig { areNpcsBattleParticipants: boolean; } +export interface JetpackBoosterConfig { + isUnlimitedFuelEnabled: boolean; + turboSpeedMultiplier: number; +} + +export interface JumpBoosterConfig { + isUnlimitedDoubleJumpsEnabled: boolean; + jumpHeightMultiplier: number; +} + export interface MenuModeNavigateParams { to: string; search: object | null; @@ -69,6 +79,16 @@ export interface BattleState { isActive: boolean; } +export interface JetpackBoosterState { + isEnabled: boolean; + config: JetpackBoosterConfig; +} + +export interface JumpBoosterState { + isEnabled: boolean; + config: JumpBoosterConfig; +} + export enum ModeKind { PlayMode, MenuMode, diff --git a/workspaces/js/galaxy-unleashed-overlay/src/lib/runtime-true-api.ts b/workspaces/js/galaxy-unleashed-overlay/src/lib/runtime-true-api.ts index 8606c05..e049bd9 100644 --- a/workspaces/js/galaxy-unleashed-overlay/src/lib/runtime-true-api.ts +++ b/workspaces/js/galaxy-unleashed-overlay/src/lib/runtime-true-api.ts @@ -5,6 +5,10 @@ import { BattleState, CharacterInfo, CreateNpcSpawnersModeConfig, + JetpackBoosterConfig, + JetpackBoosterState, + JumpBoosterConfig, + JumpBoosterState, MenuModeConfig, ModeState, NpcSpawnerConfig, @@ -21,6 +25,12 @@ interface RuntimeApi { destroyNpcSpawner: (argsAsString: string) => Promise; fetchBattleState: (argsAsString: string) => Promise; setIsBattleActive: (argsAsString: string) => Promise; + fetchJetpackBoosterState: (argsAsString: string) => Promise; + setIsJetpackBoosterEnabled: (argsAsString: string) => Promise; + setJetpackBoosterConfig: (argsAsString: string) => Promise; + fetchJumpBoosterState: (argsAsString: string) => Promise; + setIsJumpBoosterEnabled: (argsAsString: string) => Promise; + setJumpBoosterConfig: (argsAsString: string) => Promise; fetchModeState: (argsAsString: string) => Promise; switchToPlayMode: (argsAsString: string) => Promise; switchToMenuMode: (argsAsString: string) => Promise; @@ -154,6 +164,80 @@ export async function setIsBattleActive( await getRuntimeApi().setIsBattleActive(JSON.stringify(args)); } +export const fetchJetpackBoosterState = async ( + args: {}, +) => { + return JSON.parse( + await getRuntimeApi().fetchJetpackBoosterState(JSON.stringify(args)), + ) as JetpackBoosterState; +}; + +export function useJetpackBoosterState() { + return useSuspenseQuery({ + queryKey: [`GalaxyUnleashed.JetpackBoosterState`], + queryFn: fetchJetpackBoosterState, + networkMode: `always`, + retry: true, + retryDelay: 100, + staleTime: 100, + refetchInterval: 100, + refetchIntervalInBackground: true, + }).data; +} + +export async function setIsJetpackBoosterEnabled( + args: { + isJetpackBoosterEnabled: boolean; + }, +) { + await getRuntimeApi().setIsJetpackBoosterEnabled(JSON.stringify(args)); +} + +export async function setJetpackBoosterConfig( + args: { + jetpackBoosterConfig: JetpackBoosterConfig; + }, +) { + await getRuntimeApi().setJetpackBoosterConfig(JSON.stringify(args)); +} + +export const fetchJumpBoosterState = async ( + args: {}, +) => { + return JSON.parse( + await getRuntimeApi().fetchJumpBoosterState(JSON.stringify(args)), + ) as JumpBoosterState; +}; + +export function useJumpBoosterState() { + return useSuspenseQuery({ + queryKey: [`GalaxyUnleashed.JumpBoosterState`], + queryFn: fetchJumpBoosterState, + networkMode: `always`, + retry: true, + retryDelay: 100, + staleTime: 100, + refetchInterval: 100, + refetchIntervalInBackground: true, + }).data; +} + +export async function setIsJumpBoosterEnabled( + args: { + isJumpBoosterEnabled: boolean; + }, +) { + await getRuntimeApi().setIsJumpBoosterEnabled(JSON.stringify(args)); +} + +export async function setJumpBoosterConfig( + args: { + jumpBoosterConfig: JumpBoosterConfig; + }, +) { + await getRuntimeApi().setJumpBoosterConfig(JSON.stringify(args)); +} + export const fetchModeState = async ( args: {}, ) => { diff --git a/workspaces/js/galaxy-unleashed-overlay/src/routes/menu-mode/menu/boosters/index.tsx b/workspaces/js/galaxy-unleashed-overlay/src/routes/menu-mode/menu/boosters/index.tsx new file mode 100644 index 0000000..f061b97 --- /dev/null +++ b/workspaces/js/galaxy-unleashed-overlay/src/routes/menu-mode/menu/boosters/index.tsx @@ -0,0 +1,246 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { + useEffect, + useMemo, + useState, +} from "react"; + +import { Form } from "@/components/form"; +import { FormSliderField } from "@/components/form-slider-field"; +import { FormSwitchField } from "@/components/form-switch-field"; +import { + Card, + CardContent, + CardFooter, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { + Table, + TableBody, + TableCell, + TableRow, +} from "@/components/ui/table"; +import { + Tabs, + TabsContent, + TabsList, + TabsTrigger, +} from "@/components/ui/tabs"; +import { + JetpackBoosterConfig, + JumpBoosterConfig, + setIsJetpackBoosterEnabled, + setIsJumpBoosterEnabled, + setJetpackBoosterConfig, + setJumpBoosterConfig, + useJetpackBoosterState, + useJumpBoosterState, +} from "@/lib/runtime-api"; + +export const Route = createFileRoute("/menu-mode/menu/boosters/")({ + component: RouteComponent, + staticData: { + menuPage: { + name: "Boosters", + prevPageFullPath: "/menu-mode/menu", + }, + }, +}); + +function JetpackBoosterTab() { + const jetpackBoosterState = useJetpackBoosterState(); + + const [isUnlimitedFuelEnabled, setIsUnlimitedFuelEnabled] = useState(jetpackBoosterState.config.isUnlimitedFuelEnabled); + const [turboSpeedMultiplier, setTurboSpeedMultiplier] = useState(jetpackBoosterState.config.turboSpeedMultiplier); + + const jetpackBoosterConfig = useMemo( + () => ({ + isUnlimitedFuelEnabled, + turboSpeedMultiplier, + }), + [ + isUnlimitedFuelEnabled, + turboSpeedMultiplier, + ], + ); + + useEffect( + () => { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + setJetpackBoosterConfig({ + jetpackBoosterConfig, + }); + }, + [ + jetpackBoosterConfig, + ], + ); + + return ( + + + + Jetpack Booster + + + +
+ { + await setIsJetpackBoosterEnabled({ + isJetpackBoosterEnabled: checked, + }); + }} + /> + { + !jetpackBoosterState.isEnabled + ? <> + : ( + <> + + `${String(value)}x`} + /> + + ) + } + +
+ + + + + Shift (hold) + + Activate Turbo + + + + C + + Fly Upwards + + + + X + + Fly Downwards + + + +
+
+
+ ); +} + +function JumpBoosterTab() { + const jumpBoosterState = useJumpBoosterState(); + + const [isUnlimitedDoubleJumpsEnabled, setIsUnlimitedDoubleJumpsEnabled] = useState(jumpBoosterState.config.isUnlimitedDoubleJumpsEnabled); + const [jumpHeightMultiplier, setJumpHeightMultiplier] = useState(jumpBoosterState.config.jumpHeightMultiplier); + + const jumpBoosterConfig = useMemo( + () => ({ + isUnlimitedDoubleJumpsEnabled, + jumpHeightMultiplier, + }), + [ + isUnlimitedDoubleJumpsEnabled, + jumpHeightMultiplier, + ], + ); + + useEffect( + () => { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + setJumpBoosterConfig({ + jumpBoosterConfig, + }); + }, + [ + jumpBoosterConfig, + ], + ); + + return ( + + + + Jump Booster + + + +
+ { + await setIsJumpBoosterEnabled({ + isJumpBoosterEnabled: checked, + }); + }} + /> + { + !jumpBoosterState.isEnabled + ? <> + : ( + <> + + `${String(value)}x`} + /> + + ) + } + +
+
+ ); +} +function RouteComponent() { + return ( + + + Jetpack Booster + Jump Booster + + + + + + + + + ); +} diff --git a/workspaces/js/galaxy-unleashed-overlay/src/routes/menu-mode/menu/index.tsx b/workspaces/js/galaxy-unleashed-overlay/src/routes/menu-mode/menu/index.tsx index ab9b114..4da1a00 100644 --- a/workspaces/js/galaxy-unleashed-overlay/src/routes/menu-mode/menu/index.tsx +++ b/workspaces/js/galaxy-unleashed-overlay/src/routes/menu-mode/menu/index.tsx @@ -106,9 +106,10 @@ function RouteComponent() { /> navigate({ to: "/menu-mode/menu/boosters" })} />