87ddf1499d
Cross-platform Krunker.io game client forked from Krunker Police Client with all KPD/moderator features stripped: no KPD auth, OBS recording, evidence uploads, yt-dlp, bytenode, or code obfuscation. Retained: unlimited FPS (custom Electron 42), ad blocking, resource swapper, matchmaker, userscripts, chat translator, Discord RPC, alt account manager, configurable keybinds, and advanced Chromium flags. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
76 lines
2.3 KiB
TypeScript
76 lines
2.3 KiB
TypeScript
// ── Shared preload utilities ──
|
|
// Common types, helpers, and constants used across preload modules.
|
|
|
|
// ── Shared interfaces ──
|
|
|
|
export interface SavedConsole {
|
|
log: (...args: unknown[]) => void;
|
|
warn: (...args: unknown[]) => void;
|
|
error: (...args: unknown[]) => void;
|
|
}
|
|
|
|
export interface KeybindDef {
|
|
key: string;
|
|
ctrl: boolean;
|
|
shift: boolean;
|
|
alt: boolean;
|
|
}
|
|
|
|
// ── HTML escaping ──
|
|
|
|
const HTML_ESCAPE_MAP: Record<string, string> = {
|
|
'&': '&', '<': '<', '>': '>', '"': '"', "'": ''',
|
|
};
|
|
|
|
export function escapeHtml(s: string): string {
|
|
return s.replace(/[&<>"']/g, c => HTML_ESCAPE_MAP[c]);
|
|
}
|
|
|
|
// ── Chat message injection ──
|
|
// Creates messages in #chatHolder inside a persistent #kpcMessageHolder div.
|
|
// timeout=0 means the message is persistent (not auto-removed).
|
|
|
|
export function genChatMsg(text: string, timeout = 2.25): HTMLElement | null {
|
|
const chatHolder = document.getElementById('chatHolder');
|
|
if (!chatHolder) return null;
|
|
if (!document.getElementById('kpcMessageHolder')) {
|
|
chatHolder.insertAdjacentHTML('afterbegin', '<div id="kpcMessageHolder"></div>');
|
|
}
|
|
const holder = document.getElementById('kpcMessageHolder')!;
|
|
holder.insertAdjacentHTML('beforeend',
|
|
'<div class="chatHolder_kpc"><div class="chatItem_kpc"><span class="chatMsg_kpc">' +
|
|
escapeHtml(text) + '</span></div></div>');
|
|
const elem = holder.lastElementChild as HTMLElement;
|
|
if (timeout !== 0) {
|
|
setTimeout(() => { elem.remove(); }, timeout * 1000);
|
|
}
|
|
return elem;
|
|
}
|
|
|
|
// ── Filename sanitisation ──
|
|
|
|
export function sanitizeFilename(name: string): string {
|
|
return name.replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
}
|
|
|
|
// ── Shared CSS constants ──
|
|
|
|
export const DEATH_ANIM_BLOCK_ID = 'kpc-animationBlock';
|
|
export const DEATH_ANIM_BLOCK_CSS =
|
|
'.death-ui-bottom, .death-ui-bottom-empty { animation: none !important; transition: none !important; }';
|
|
|
|
/** Inject or remove the death screen animation block style element. */
|
|
export function setDeathAnimBlock(enabled: boolean): void {
|
|
let el = document.getElementById(DEATH_ANIM_BLOCK_ID);
|
|
if (enabled) {
|
|
if (!el) {
|
|
el = document.createElement('style');
|
|
el.id = DEATH_ANIM_BLOCK_ID;
|
|
el.textContent = DEATH_ANIM_BLOCK_CSS;
|
|
document.head.appendChild(el);
|
|
}
|
|
} else if (el) {
|
|
el.remove();
|
|
}
|
|
}
|