Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added assets/failsafes/sounds/Player Failsafe.ogg
Binary file not shown.
Binary file added assets/failsafes/sounds/Tave Check.ogg
Binary file not shown.
Binary file added assets/failsafes/sounds/metal Pipe.ogg
Binary file not shown.
165 changes: 53 additions & 112 deletions failsafes/AlertUtils.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,21 @@
import { drawRect, drawText } from '../gui/Utils';
import { getSetting } from '../gui/GuiSave';
import { Chat } from '../utils/Chat';
import { File, globalAssetsDir } from '../utils/Constants';
import { Utils } from '../utils/Utils';
import FailsafeUtils from './FailsafeUtils';
import { getSeverity } from './FailsafeUtils';

let failsafeSound = 'Tave Check.wav';

const AudioSystem = javax.sound.sampled.AudioSystem;
const FloatControl = javax.sound.sampled.FloatControl;

// todo
// touchen up colours rn they ugly
// touch up code
// rewrite some stuff!
// allow edit of failsafe sound
let failsafeSound = 'Tave Check.ogg';
const playerNotificationSound = 'Player Failsafe.ogg';

class AlertUtilsClass {
constructor() {
this.clip = null;
this.audioStream = null;
this.gainControl = null;
this.sound = null;
this.savedSound = null;
this.isAlerting = false;

this.cancelKeyBind = null;
this.cancelKey = null;

this.render = null;
this.tracker = null;
this.cancelHandler = null;

this._makeFailsafeKeybind();

Expand All @@ -36,10 +24,13 @@ class AlertUtilsClass {
}).setName('trigger');
}

/**
* Combines all internal methods to create a failsafe alert
*/
triggerReaction() {
triggerReaction(severity = 'high') {
const next = getSeverity(severity);
if (this.isAlerting && next.rank < getSeverity(this.alertSeverity).rank) return;

this.alertSeverity = severity;
this.alertLine = next.line;
this.alertColor = next.alertColor;
if (this.isAlerting) return;

Chat.messageFailsafe('Suspicious activity detected, reaction occuring!');
Expand All @@ -49,7 +40,6 @@ class AlertUtilsClass {
this.playSound();
this._grabWindowOnFailsafe();

const line1 = 'V5 BELIEVES YOU HAVE BEEN MACRO CHECKED!';
const key = this.cancelKey;
const line2Start = 'PRESS ';
const line2End = ' TO DISABLE THE REACTION';
Expand All @@ -60,11 +50,12 @@ class AlertUtilsClass {
const fontSize = 20;
const lineSpacing = 8;
const yOffset = 100;
const redColor = Math.trunc(0xffff0000); // change this
const highlightColor = Math.trunc(0xffffffff); // this too
const highlightColor = 0xffffffff;

this.render = register('renderOverlay', () => {
const scale = fontSize / 10;
const line1 = this.alertLine;
const redColor = this.alertColor;
const x1 = screenW / 2 - (Renderer.getStringWidth(line1) * scale) / 2;
const totalLine2Width = (Renderer.getStringWidth(line2Start) + Renderer.getStringWidth(key) + Renderer.getStringWidth(line2End)) * scale;
let currentX2 = screenW / 2 - totalLine2Width / 2;
Expand All @@ -86,96 +77,58 @@ class AlertUtilsClass {
});
}

/**
* Disables the reaction & nulls all registers included
*/
setCancelHandler(callback) {
this.cancelHandler = typeof callback === 'function' ? callback : null;
}

disableReaction() {
this.isAlerting = false;
this.stopSound();
const handler = this.cancelHandler;
this.cancelHandler = null;
if (handler) {
try {
handler();
} catch (e) {
console.error('V5 Caught error' + e + e.stack);
}
}

if (this.render) {
this.render.unregister();
this.render = null;
}
}

if (this.tracker) {
this.tracker.unregister();
this.tracker = null;
playSound(soundName = failsafeSound) {
if (!(getSetting('Failsafes', 'Play sound on check') ?? true)) return;

try {
if (!this.sound || this.savedSound !== soundName) {
this.sound?.destroy();
this.sound = new Sound({ source: `failsafes/sounds/${soundName}` });
this.savedSound = soundName;
}
this.sound.rewind();
} catch (e) {
this.sound = null;
console.error('V5 Caught error' + e + e.stack);
}
}

/**
* Plays a sound if the player has the setting toggled
*/
playSound() {
if (!FailsafeUtils.getFailsafeSettings('Play sound on check').playSoundOnCheck) return;
const currentSound = failsafeSound;
if (!this.clip || this.savedSound !== currentSound) this._loadsoundFile();

if (this.clip) {
this.clip.stop();
this.clip.setFramePosition(0);
this.clip.start();
}
playQuietNotification() {
if (this.isAlerting) return;
this.playSound(playerNotificationSound);
}

/**
* Stops any sounds from playing
*/
stopSound() {
if (this.clip && this.clip.isRunning()) this.clip.stop();
if (this.sound && World.isLoaded()) this.sound.stop();
}

setFailsafeSound(fileName) {
failsafeSound = fileName;
}

/**
* Loads a sound file using Java methods
*/
_loadsoundFile() {
if (this.clip) {
try {
this.clip.stop();
this.clip.close();
} catch (e) {
console.error('V5 Caught error' + e + e.stack);
}
this.clip = null;
}

if (this.audioStream) {
try {
this.audioStream.close();
} catch (e) {
console.error('V5 Caught error' + e + e.stack);
}
this.audioStream = null;
}

const currentSound = failsafeSound;
this.savedSound = currentSound || 'Tave Check.wav';
if ((currentSound || '').includes('undefined')) this.savedSound = 'Tave Check.wav';

this.soundFile = new File(globalAssetsDir, `failsafes/sounds/${this.savedSound}`);
if (!this.soundFile.exists()) return;

try {
this.audioStream = AudioSystem.getAudioInputStream(this.soundFile);
this.clip = AudioSystem.getClip();
this.clip.open(this.audioStream);
if (this.clip.isControlSupported(FloatControl.Type.MASTER_GAIN)) {
this.gainControl = this.clip.getControl(FloatControl.Type.MASTER_GAIN);
}
} catch (e) {
this.clip = null;
console.error('V5 Caught error' + e + e.stack);
}
}

/**
* Uses NVG to draw a overlay over the whole screen
*/
_renderAlertScreen() {
if (Client.isInChat()) return;
try {
Expand All @@ -187,7 +140,7 @@ class AlertUtilsClass {
y: 0,
width: Renderer.screen.getWidth(),
height: Renderer.screen.getHeight(),
color: Math.trunc((120 << 24) | (255 << 16) | (0 << 8)), // change this too pls
color: 0x78ff0000,
});

NVG.restore();
Expand All @@ -202,36 +155,24 @@ class AlertUtilsClass {
}
}

/**
* Creates a keybind for canceling the reaction
*/
_makeFailsafeKeybind() {
const keyName = 'Cancel Reaction';
const existingKeybinds = Utils.getConfigFile('keybinds.json') || {};
let savedKeycode = existingKeybinds[keyName];

if (savedKeycode === undefined || savedKeycode === 0 || savedKeycode === -1 || savedKeycode === 75) savedKeycode = Keyboard.KEY_K;

this.cancelKey = Keyboard.getKeyName(savedKeycode);
this.cancelKeyBind = new KeyBind(keyName, savedKeycode, 'v5_core');
const cancelKeyBind = new KeyBind(keyName, Keyboard.KEY_K, 'v5_core');
this.cancelKey = Keyboard.getKeyName(cancelKeyBind.getKeyCode());

this.cancelKeyBind.registerKeyPress(() => {
cancelKeyBind.registerKeyPress(() => {
if (!this.isAlerting) return;
Chat.messageFailsafe('Reaction disabled due to keybind being pressed');
this.disableReaction();
});

register('gameUnload', () => {
this.disableReaction();
let allKeybinds = Utils.getConfigFile('keybinds.json') || {};
allKeybinds[keyName] = this.cancelKeyBind.getKeyCode();
Utils.writeConfigFile('keybinds.json', allKeybinds);
if (this.sound && World.isLoaded()) this.sound.destroy();
this.sound = null;
});
}

/**
* Uses GLFW to grab the window on a failsafe if they have the setting toggled (WIP)
*/
_grabWindowOnFailsafe() {
try {
const GLFW = org.lwjgl.glfw.GLFW;
Expand Down
72 changes: 36 additions & 36 deletions failsafes/Failsafe.js
Original file line number Diff line number Diff line change
@@ -1,58 +1,58 @@
import { manager } from '../utils/SkyblockEvents';
import { MacroState } from '../utils/MacroState';
import { manager } from '../utils/SkyblockEvents';
import { finiteNumber } from '../utils/NumberUtils';

const DEFAULT_DISABLE_MS = 3000;
const PICKONIMBUS_DISABLE_MS = 5000;
let globalDisabledUntil = 0;

const disableAll = (durationMs) => {
globalDisabledUntil = Math.max(globalDisabledUntil, Date.now() + durationMs);
};

register('worldLoad', () => disableAll(DEFAULT_DISABLE_MS));
['serverchange', 'death', 'warp'].forEach((event) => manager.subscribe(event, () => disableAll(1000)));
manager.subscribe('limbo', () => disableAll(DEFAULT_DISABLE_MS));
manager.subscribe('pickonimbusbroke', () => disableAll(PICKONIMBUS_DISABLE_MS));

export class Failsafe {
registered = false;
disabled = false;
_disabledUntil = 0;
_disabledTimer = null;

constructor() {
this._registerListeners();
get disabled() {
return Date.now() < this._getDisabledUntil();
}

shouldTrigger() {
return true;
}
isActive() {
return MacroState.isFailsafeMacroRunning();
}
onTrigger() {}

reset() {
this.disabled = false;
this._disabledUntil = 0;
if (this._disabledTimer) {
clearTimeout(this._disabledTimer);
this._disabledTimer = null;
}
}

_setDisabled(durationMs) {
const now = Date.now();
const end = now + durationMs;

if (end <= this._disabledUntil && this.disabled) return;
_scheduleTrigger(fireFn, settings, validateFn = null) {
const scheduledAt = Date.now();
const delay = this._getReactionDelay(settings);

this._disabledUntil = end;
this.disabled = true;
setTimeout(() => {
if (this.disabled || scheduledAt < this._getDisabledUntil()) return;
if (!MacroState.isFailsafeMacroRunning()) return;
if (validateFn && !validateFn()) return;
fireFn();
}, delay);
}

if (this._disabledTimer) clearTimeout(this._disabledTimer);
_reportFailsafe(payload) {
const FailsafeManager = require('./FailsafeManager').default;
FailsafeManager.report(payload);
}

this._disabledTimer = setTimeout(() => {
if (Date.now() >= this._disabledUntil) {
this.disabled = false;
this._disabledTimer = null;
}
}, durationMs);
_setDisabled(durationMs) {
this._disabledUntil = Math.max(this._disabledUntil, Date.now() + durationMs);
}

_registerListeners() {
if (this.registered) return;
this.registered = true;
register('worldLoad', () => {
this._setDisabled(1000);
});
['serverchange', 'death', 'warp'].forEach((event) => manager.subscribe(event, () => this._setDisabled(1000)));
_getDisabledUntil() {
return Math.max(globalDisabledUntil, this._disabledUntil);
}

_getReactionDelay(settings) {
Expand Down
Loading
Loading