diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..f897e99
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,56 @@
+
+
+ 4.0.0
+
+ nl.andrewl.
+ randomhotbar
+ 1.0.0
+
+
+ 17
+ 17
+
+
+
+
+ com.formdev
+ flatlaf
+ 2.0.2
+
+
+ com.github.kwhat
+ jnativehook
+ 2.2.1
+
+
+
+
+
+
+ maven-assembly-plugin
+
+
+
+ nl.andrewl.randomhotbar.RandomHotbar
+
+
+
+ jar-with-dependencies
+
+
+
+
+ make-assembly
+ package
+
+ single
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/nl/andrewl/randomhotbar/BlockPlaceListener.java b/src/main/java/nl/andrewl/randomhotbar/BlockPlaceListener.java
new file mode 100644
index 0000000..872a010
--- /dev/null
+++ b/src/main/java/nl/andrewl/randomhotbar/BlockPlaceListener.java
@@ -0,0 +1,72 @@
+package nl.andrewl.randomhotbar;
+
+import com.github.kwhat.jnativehook.GlobalScreen;
+import com.github.kwhat.jnativehook.mouse.NativeMouseEvent;
+import com.github.kwhat.jnativehook.mouse.NativeMouseInputListener;
+import com.github.kwhat.jnativehook.mouse.NativeMouseWheelEvent;
+
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+public class BlockPlaceListener implements NativeMouseInputListener {
+ private final Random rand = new Random();
+ private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
+ private final List settings;
+ private float randSum;
+ private int currentSlot = 1;
+
+ public BlockPlaceListener(List settings) {
+ randSum = 0;
+ for (var v : settings) {
+ randSum += v.chance();
+ }
+ this.settings = settings;
+ for (var v : settings) {
+ float percent = (v.chance() / randSum) * 100.0f;
+ System.out.printf("Will use slot %d, %.1f%% of the time.\n", v.slot(), percent);
+ }
+ System.out.printf("Starting at slot %d. Please select this slot if it is not selected already, then start right-clicking. Do not hold right-click.\n", currentSlot);
+ }
+
+ private int getNextSlot() {
+ float idx = rand.nextFloat(randSum);
+ float sum = 0;
+ int i = 0;
+ while (sum < idx) {
+ sum += settings.get(i++).chance();
+ }
+ return settings.get(Math.max(0, i - 1)).slot();
+ }
+
+ private void moveToSlot(int slot) {
+ final int dir = slot < currentSlot ? 1 : -1;
+ int n = Math.abs(currentSlot - slot);
+ for (int i = 0; i < n; i++) {
+ executor.schedule(() -> {
+ GlobalScreen.postNativeEvent(new NativeMouseWheelEvent(
+ 2505,
+ 0,
+ 500,
+ 500,
+ 1,
+ NativeMouseWheelEvent.WHEEL_UNIT_SCROLL,
+ 1,
+ dir,
+ NativeMouseWheelEvent.WHEEL_VERTICAL_DIRECTION
+ ));
+ }, i * 50L, TimeUnit.MILLISECONDS);
+ }
+ currentSlot = slot;
+ }
+
+ @Override
+ public void nativeMouseClicked(NativeMouseEvent nativeEvent) {
+ if (nativeEvent.getButton() == 2) {
+ int newSlot = getNextSlot();
+ moveToSlot(newSlot);
+ }
+ }
+}
diff --git a/src/main/java/nl/andrewl/randomhotbar/RandomHotbar.java b/src/main/java/nl/andrewl/randomhotbar/RandomHotbar.java
new file mode 100644
index 0000000..75fbec7
--- /dev/null
+++ b/src/main/java/nl/andrewl/randomhotbar/RandomHotbar.java
@@ -0,0 +1,45 @@
+package nl.andrewl.randomhotbar;
+
+import com.github.kwhat.jnativehook.GlobalScreen;
+import com.github.kwhat.jnativehook.NativeHookException;
+
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class RandomHotbar {
+ public static void main(String[] args) {
+ try {
+ GlobalScreen.registerNativeHook();
+ } catch (NativeHookException e) {
+ e.printStackTrace();
+ }
+ var settings = parseSettings(String.join(",", args));
+ var listener = new BlockPlaceListener(settings);
+ GlobalScreen.addNativeMouseListener(listener);
+ }
+
+ public static final Pattern SETTINGS_PATTERN = Pattern.compile("([1-9])\\s*:\\s*(\\d*\\.\\d+|\\d+)%?");
+
+ public static List parseSettings(String s) {
+ List settings = new ArrayList<>(9);
+ Matcher m = SETTINGS_PATTERN.matcher(s);
+ while (m.find()) {
+ int slot = Integer.parseInt(m.group(1));
+ float value = Float.parseFloat(m.group(2));
+ for (var setting : settings) {
+ if (setting.slot() == slot) {
+ throw new IllegalArgumentException("A setting for slot " + slot + " is already defined.");
+ }
+ }
+ settings.add(new SlotSetting(slot, value));
+ }
+ settings.sort(Comparator.comparing(SlotSetting::slot));
+ if (settings.isEmpty()) {
+ for (int i = 1; i <= 9; i++) {
+ settings.add(new SlotSetting(i, 1));
+ }
+ }
+ return settings;
+ }
+}
diff --git a/src/main/java/nl/andrewl/randomhotbar/SlotSetting.java b/src/main/java/nl/andrewl/randomhotbar/SlotSetting.java
new file mode 100644
index 0000000..63fd094
--- /dev/null
+++ b/src/main/java/nl/andrewl/randomhotbar/SlotSetting.java
@@ -0,0 +1,4 @@
+package nl.andrewl.randomhotbar;
+
+public record SlotSetting(int slot, float chance) {
+}