package org.saturnclient.mod.mods; import org.saturnclient.common.feature.PlayerFeature; import org.saturnclient.common.provider.Providers; import org.saturnclient.config.property.BoolProperty; import org.saturnclient.config.property.ColorProperty; import org.saturnclient.config.property.Property; import org.saturnclient.mod.HudMod; import org.saturnclient.mod.Mod; import org.saturnclient.mod.ModLayout; import org.saturnclient.mod.ModSpec; import org.saturnclient.ui.RenderScope; /** * KeystrokesMod renders the WASD / mouse / space key states as an * on-screen overlay. */ public class KeystrokesMod extends Mod implements HudMod { // --------------------------------------------------------------- // Configuration // --------------------------------------------------------------- private static final BoolProperty enabled = Property.bool(false); private static final BoolProperty showMouse = Property.bool(true); private static final BoolProperty showSpace = Property.bool(false); private static final ColorProperty clickBg = Property.color(0xFFCCCCCC); private static final ColorProperty clickFg = Property.color(0xFFFFFFFF); private static final ModLayout layout = new ModLayout(78, 54); // --------------------------------------------------------------- // Layout constants // --------------------------------------------------------------- private static final int KEY_SIZE = 24; private static final int KEY_SPACING = 3; private static final int MOUSE_WIDTH = 38; private static final int MOUSE_H = 24; private static final int SPACE_H = 19; // --------------------------------------------------------------- // Cached key states (updated in tick) // --------------------------------------------------------------- private boolean w, a, s, d, lmb, rmb, space; public KeystrokesMod() { super( new ModSpec("Keystrokes", "keystrokes") .description("Displays movement keystrokes") .version("v0.2.0") .tags("Utility") .requires(Providers.feature::player), enabled.named("Enabled"), showMouse.named("Show mouse clicks").description("Show the left and right mouse buttons"), showSpace.named("Show space").description("Show the space bar"), layout.prop(), clickFg.named("Clicked fg").description("Text color of a pressed key"), clickBg.named("Clicked bg").description("Background of a pressed key")); layout.renderBackground = false; } // --------------------------------------------------------------- // Mod contract // --------------------------------------------------------------- @Override public void tick() { PlayerFeature player = Providers.feature.player(); w = player.isForwardPressed(); a = player.isLeftPressed(); s = player.isBackPressed(); d = player.isRightPressed(); lmb = player.isAttackPressed(); rmb = player.isUsePressed(); space = player.isJumpPressed(); refreshHeight(); } @Override public void renderHud(RenderScope scope) { render(scope, true); } @Override public void renderDummy(RenderScope scope) { render(scope, false); } @Override public ModLayout getDimensions() { return layout; } @Override public boolean isEnabled() { return enabled.value; } @Override public void onEnabled(boolean e) { enabled.value = e; } // --------------------------------------------------------------- // Rendering // --------------------------------------------------------------- private void render(RenderScope scope, boolean live) { int yOffset = 0; // W (top centre) renderKey(scope, live && w, 'W', KEY_SIZE + KEY_SPACING, yOffset); yOffset += KEY_SIZE + KEY_SPACING; // A S D renderKey(scope, live && a, 'A', 0, yOffset); renderKey(scope, live && s, 'S', KEY_SIZE + KEY_SPACING, yOffset); renderKey(scope, live && d, 'D', (KEY_SIZE + KEY_SPACING) * 2, yOffset); yOffset += KEY_SIZE + KEY_SPACING; // Spacebar (optional) if (showSpace.value) { renderSpaceKey(scope, live && space, 0, yOffset); yOffset += SPACE_H + KEY_SPACING; } // Mouse buttons (optional) if (showMouse.value) { renderMouseKey(scope, live && lmb, "LMB", 0, yOffset); renderMouseKey(scope, live && rmb, "RMB", MOUSE_WIDTH + KEY_SPACING, yOffset); } } private void renderKey(RenderScope scope, boolean pressed, char c, int x, int y) { int bg = pressed ? clickBg.value : layout.bgColor.value; int fg = pressed ? clickFg.value : layout.fgColor.value; scope.drawRoundedRectangle(x, y, KEY_SIZE, KEY_SIZE, layout.radius.value, bg); scope.drawText(0.6f, String.valueOf(c), x + 9, y + 7, layout.font.value, fg); } private void renderMouseKey(RenderScope scope, boolean pressed, String label, int x, int y) { int bg = pressed ? clickBg.value : layout.bgColor.value; int fg = pressed ? clickFg.value : layout.fgColor.value; scope.drawRoundedRectangle(x, y, MOUSE_WIDTH, MOUSE_H, layout.radius.value, bg); scope.drawText(0.6f, label, x + 9, y + 7, layout.font.value, fg); } private void renderSpaceKey(RenderScope scope, boolean pressed, int x, int y) { int bg = pressed ? clickBg.value : layout.bgColor.value; int fg = pressed ? clickFg.value : layout.fgColor.value; scope.drawRoundedRectangle(x, y, layout.width, SPACE_H, layout.radius.value, bg); int lineY = y + SPACE_H / 2; scope.drawRectangle(x + (layout.width - 30) / 2, lineY, 30, 1, fg); } private void refreshHeight() { int h = KEY_SIZE * 2 + KEY_SPACING; if (showSpace.value) h += SPACE_H + KEY_SPACING; if (showMouse.value) h += MOUSE_H + KEY_SPACING; layout.height = h; } }