mirror of
https://github.com/TiagoVal97/cheatspecter.git
synced 2026-10-23 07:35:54 +02:00
- Find: text search, grouped search, undo, went up/down by, where to search, before/after compare - Debug tab: breakpoints, stepping, registers, stack, threads, what code touches, structure compare, pointer re-check - Engine tab: Unreal, Unity, Godot, GameMaker and C++ class names; hidden settings and switches - Code cheats with labels, variables, references and shared code; rule builder; script commands - Cheats kept on by the PS5 without the browser - Learn section with twelve lessons and an in-page practice game - Section (master code) community cheats; SHN and MC4 export - Groups, dropdowns, hotkeys, first-cheat guide, re-find after update, restore everything - MCP server: 25 tools - Quick start, wiki, contributor and security guides, changelog
60 lines
2.4 KiB
TypeScript
60 lines
2.4 KiB
TypeScript
// Which loaded module an offset is into: the game's own executable (the
|
|
// usual case, and the default) or one of the libraries it loads. Shows
|
|
// nothing at all when the game has only the one, so most people never see it.
|
|
|
|
import { useEffect, useState } from 'react';
|
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
|
import { loadedModules } from '../lib/locations.ts';
|
|
import type { Location } from '../lib/locations.ts';
|
|
import { useWorkbench } from './workbench.tsx';
|
|
|
|
// Radix selects cannot hold an empty value, so the executable gets a stand-in.
|
|
const MAIN = ':main';
|
|
|
|
type InModule = Extract<Location, { kind: 'module' | 'pointer' }>;
|
|
|
|
/** For a location editor: the same location with the module set, or cleared for the executable. */
|
|
export function ModuleChoice(props: { loc: InModule; onChange: (loc: Location) => void }) {
|
|
const { ctx } = useWorkbench();
|
|
const value = props.loc.module;
|
|
const pick = (module: string | undefined) => {
|
|
const { module: _old, ...rest } = props.loc;
|
|
props.onChange(module === undefined ? rest : { ...rest, module });
|
|
};
|
|
const [names, setNames] = useState<string[]>([]);
|
|
|
|
useEffect(() => {
|
|
let canceled = false;
|
|
loadedModules(ctx)
|
|
.then((list) => !canceled && setNames(list.map((m) => m.module).filter((n): n is string => n !== undefined)))
|
|
.catch(() => {});
|
|
return () => {
|
|
canceled = true;
|
|
};
|
|
}, [ctx]);
|
|
|
|
// A module the cheat names but the game has not loaded (yet) must stay selectable, or opening the editor would silently change it.
|
|
const all = value !== undefined && !names.includes(value) ? [...names, value] : names;
|
|
if (all.length === 0) return null;
|
|
|
|
return (
|
|
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
|
<span className="shrink-0">Inside</span>
|
|
<Select value={value ?? MAIN} onValueChange={(v) => pick(v === MAIN ? undefined : v)}>
|
|
<SelectTrigger className="min-w-0 flex-1 text-foreground" aria-label="Which module the offset is into">
|
|
<SelectValue />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value={MAIN}>The game itself (main executable)</SelectItem>
|
|
{all.map((name) => (
|
|
<SelectItem key={name} value={name}>
|
|
{name}
|
|
{names.includes(name) ? '' : ' (not loaded right now)'}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
);
|
|
}
|