Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: CPS for Keystrokes (HUD) #4192

Open
wants to merge 2 commits into
base: nextgen
Choose a base branch
from
Open
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
11 changes: 11 additions & 0 deletions src-theme/src/integration/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,17 @@ export interface KeyEvent {
mods: number;
}

export interface KeyBindingEvent {
key: string;
action: number;
mods: number;
}

export interface KeyBindingCPSEvent {
key: string;
cps: number;
}

export interface TargetChangeEvent {
target: PlayerData | null;
}
Expand Down
30 changes: 25 additions & 5 deletions src-theme/src/routes/hud/elements/keystrokes/Key.svelte
Original file line number Diff line number Diff line change
@@ -1,24 +1,43 @@
<script lang="ts">
import {listen} from "../../../../integration/ws";
import type {KeyEvent} from "../../../../integration/events";
import type {KeyBindingEvent, KeyBindingCPSEvent} from "../../../../integration/events";
import type {MinecraftKeybind} from "../../../../integration/types";

export let gridArea: string;
export let flexBasis: string = '50px';
export let key: MinecraftKeybind | undefined;
export let showName: boolean = false;
export let showCPS: boolean = false;

let active = false;

listen("key", (e: KeyEvent) => {
let cps = 0;

listen("keybinding", (e: KeyBindingEvent) => {
if (e.key !== key?.key.translationKey) {
return;
}

active = e.action === 1 || e.action === 2;
});

if (showCPS) {
listen("keybindingCPS", (e: KeyBindingCPSEvent) => {
if (e.key !== key?.key.translationKey) {
return;
}

cps = e.cps;
});
}
</script>

<div class="key" style="grid-area: {gridArea};" class:active>
{key?.key.localized ?? "???"}
<div class="key" style="flex-basis: {flexBasis};" class:active>
{#if showName}
<span>{key?.key.localized ?? "???"}</span>
{/if}
{#if showCPS}
<span>{cps}</span>
{/if}
</div>

<style lang="scss">
Expand All @@ -29,6 +48,7 @@
background-color: rgba($keystrokes-base-color, .68);
color: $keystrokes-text-color;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border-radius: 5px;
Expand Down
45 changes: 30 additions & 15 deletions src-theme/src/routes/hud/elements/keystrokes/Keystrokes.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
let keyLeft: MinecraftKeybind | undefined;
let keyRight: MinecraftKeybind | undefined;
let keyJump: MinecraftKeybind | undefined;
let keyAttack: MinecraftKeybind | undefined;
let keyUse: MinecraftKeybind | undefined;
let keySprint: MinecraftKeybind | undefined;
let keySneak: MinecraftKeybind | undefined;

async function updateKeybinds() {
const keybinds = await getMinecraftKeybinds();
Expand All @@ -19,6 +23,10 @@
keyLeft = keybinds.find(k => k.bindName === "key.left");
keyRight = keybinds.find(k => k.bindName === "key.right");
keyJump = keybinds.find(k => k.bindName === "key.jump");
keyAttack = keybinds.find(k => k.bindName === "key.attack");
keyUse = keybinds.find(k => k.bindName === "key.use");
keySprint = keybinds.find(k => k.bindName === "key.sprint");
keySneak = keybinds.find(k => k.bindName === "key.sneak");
}

onMount(updateKeybinds);
Expand All @@ -27,21 +35,28 @@
</script>

<div class="keystrokes">
<Key key={keyForward} gridArea="a" />
<Key key={keyLeft} gridArea="b" />
<Key key={keyBack} gridArea="c" />
<Key key={keyRight} gridArea="d" />
<Key key={keyJump} gridArea="e" />
<div class="nil"></div>
<Key key={keyForward} showName/>
<div class="nil"></div>
<Key key={keyLeft} showName/>
<Key key={keyBack} showName/>
<Key key={keyRight} showName/>
<Key key={keyJump} flexBasis="100%" showName/>
<Key key={keyAttack} flexBasis="calc(50% - 2.5px)" showCPS/>
<Key key={keyUse} flexBasis="calc(50% - 2.5px)" showCPS/>
<Key key={keySprint} flexBasis="calc(50% - 2.5px)" showName/>
<Key key={keySneak} flexBasis="calc(50% - 2.5px)" showName/>
</div>

<style lang="scss">
.keystrokes {
display: grid;
grid-template-areas:
". a ."
"b c d"
"e e e";
grid-template-columns: repeat(3, 50px);
gap: 5px;
}
</style>
.keystrokes {
display: flex;
flex-wrap: wrap;
width: calc(50px * 3 + 5px * 2);
gap: 5px;
}

.nil {
width: 50px;
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ object OAuthClient {
private var authCodeContinuation: Continuation<String>? = null

fun runWithScope(block: suspend CoroutineScope.() -> Unit) {
scope.launch { block() }
scope.launch(block = block)
}

suspend fun startAuth(onUrl: (String) -> Unit): ClientAccount {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ val ALL_EVENT_CLASSES: Array<KClass<out Event>> = arrayOf(
KeyEvent::class,
MouseRotationEvent::class,
KeybindChangeEvent::class,
KeyBindingEvent::class,
KeyBindingCPSEvent::class,
AttackEvent::class,
SessionEvent::class,
ScreenEvent::class,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,15 @@ class MouseRotationEvent(var cursorDeltaX: Double, var cursorDeltaY: Double) : C

@Nameable("keybindChange")
@WebSocketEvent
class KeybindChangeEvent: Event()
class KeybindChangeEvent : Event()

@Nameable("keybinding")
@WebSocketEvent
class KeyBindingEvent(val key: InputUtil.Key, val action: Int, val mods: Int) : Event()

@Nameable("keybindingCPS")
@WebSocketEvent
class KeyBindingCPSEvent(val key: InputUtil.Key, val cps: Int) : Event()

@Nameable("useCooldown")
class UseCooldownEvent(var cooldown: Int) : Event()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@

package net.ccbluex.liquidbounce.utils.input

import net.ccbluex.liquidbounce.event.EventManager
import net.ccbluex.liquidbounce.event.Listenable
import net.ccbluex.liquidbounce.event.events.MouseButtonEvent
import net.ccbluex.liquidbounce.event.events.*
import net.ccbluex.liquidbounce.event.handler
import net.ccbluex.liquidbounce.utils.client.mc
import net.minecraft.client.option.KeyBinding
import net.minecraft.client.util.InputUtil
import net.minecraft.client.util.InputUtil.Type.KEYSYM
import net.minecraft.client.util.InputUtil.Type.MOUSE
import org.lwjgl.glfw.GLFW

/**
Expand All @@ -34,8 +37,73 @@ import org.lwjgl.glfw.GLFW
*/
object InputTracker : Listenable {

// Tracks the state of each mouse button (pressed or not).
private val mouseStates = mutableMapOf<Int, Boolean>()
private val trackers = listOf(
KeyBindingTracker(mc.options.forwardKey),
KeyBindingTracker(mc.options.backKey),
KeyBindingTracker(mc.options.leftKey),
KeyBindingTracker(mc.options.rightKey),
KeyBindingTracker(mc.options.jumpKey),
KeyBindingTracker(mc.options.attackKey),
KeyBindingTracker(mc.options.useKey),
KeyBindingTracker(mc.options.sprintKey),
KeyBindingTracker(mc.options.sneakKey),
)

override fun children(): List<Listenable> = trackers

// Tracks CPS
class KeyBindingTracker internal constructor(val keyBinding: KeyBinding) : Listenable {
// Records clicks in latest 20 ticks (1 sec)
private val countByTick = IntArray(20)
private var tickIndex = 0
private var currentCount = 0

// Sum of countByTick
var cps = 0
private set

var pressed = false
private set(value) {
if (value) {
currentCount++
}
field = value
}

@Suppress("NOTHING_TO_INLINE")
private inline fun setPressed(action: Int) {
when (action) {
GLFW.GLFW_RELEASE -> pressed = false
GLFW.GLFW_PRESS -> pressed = true
}
}

val keyHandler = handler<KeyboardKeyEvent> {
if (keyBinding.boundKey.category == KEYSYM && keyBinding.boundKey.code == it.key.code) {
setPressed(it.action)
EventManager.callEvent(KeyBindingEvent(keyBinding.boundKey, it.action, it.mods))
}
}

val mouseHandler = handler<MouseButtonEvent> {
if (keyBinding.boundKey.category == MOUSE && keyBinding.boundKey.code == it.button) {
setPressed(it.action)
EventManager.callEvent(KeyBindingEvent(keyBinding.boundKey, it.action, it.mods))
}
}

val tickHandler = handler<PlayerTickEvent> {
cps -= countByTick[tickIndex]
countByTick[tickIndex] = currentCount
cps += currentCount
currentCount = 0
tickIndex = (tickIndex + 1) % countByTick.size
EventManager.callEvent(KeyBindingCPSEvent(keyBinding.boundKey, cps))
}
}

// Tracks the state of each mouse button.
private val mouseStates = IntArray(32)

/**
* Extension property that checks if a key binding is pressed on either the keyboard or mouse.
Expand Down Expand Up @@ -68,7 +136,7 @@ object InputTracker : Listenable {
*/
@Suppress("unused")
private val handleMouseAction = handler<MouseButtonEvent> {
mouseStates[it.button] = it.action == GLFW.GLFW_PRESS
mouseStates[it.button] = it.action
}

/**
Expand All @@ -77,5 +145,5 @@ object InputTracker : Listenable {
* @param button The GLFW code of the mouse button.
* @return True if the mouse button is pressed, false otherwise.
*/
fun isMouseButtonPressed(button: Int): Boolean = mouseStates.getOrDefault(button, false)
fun isMouseButtonPressed(button: Int): Boolean = mouseStates[button] == GLFW.GLFW_PRESS
}
Loading