();
+ private JPanel joystickPanel = new JPanel();
+
public ConfigWindow() {
Util.setUITheme();
eventQueueListener = createConfigWindowEventQueueListener();
@@ -392,6 +400,7 @@ public void mouseClicked(MouseEvent e) {
JScrollPane streamingScrollPane = new JScrollPane();
JScrollPane keybindScrollPane = new JScrollPane();
JScrollPane worldListScrollPane = new JScrollPane();
+ JScrollPane joystickScrollPane = new JScrollPane();
JScrollPane authorsScrollPane = new JScrollPane();
if (isUsingFlatLAFTheme()) {
@@ -424,6 +433,7 @@ public void mouseClicked(MouseEvent e) {
streamingScrollPane.setBorder(scrollPaneBorder);
keybindScrollPane.setBorder(scrollPaneBorder);
worldListScrollPane.setBorder(scrollPaneBorder);
+ joystickScrollPane.setBorder(scrollPaneBorder);
authorsScrollPane.setBorder(scrollPaneBorder);
}
@@ -441,6 +451,8 @@ public void mouseClicked(MouseEvent e) {
keybindPanel.setName("keybinds");
worldListPanel = new JPanel();
worldListPanel.setName("world_list");
+ joystickPanel = new JPanel();
+ joystickPanel.setName("Joystick");
JPanel authorsPanel = new JPanel();
authorsPanel.setName("authors");
@@ -459,6 +471,7 @@ public void mouseClicked(MouseEvent e) {
tabbedPane.addTab("Streaming & Privacy", null, streamingScrollPane, null);
tabbedPane.addTab("Keybinds", null, keybindScrollPane, null);
tabbedPane.addTab("World List", null, worldListScrollPane, null);
+ tabbedPane.addTab("Joystick", null, joystickScrollPane, null);
tabbedPane.addTab("Authors", null, authorsScrollPane, null);
presetsScrollPane.setViewportView(presetsPanel);
@@ -468,6 +481,7 @@ public void mouseClicked(MouseEvent e) {
streamingScrollPane.setViewportView(streamingPanel);
keybindScrollPane.setViewportView(keybindPanel);
worldListScrollPane.setViewportView(worldListPanel);
+ joystickScrollPane.setViewportView(joystickPanel);
authorsScrollPane.setViewportView(authorsPanel);
// Adding padding for aesthetics
@@ -495,6 +509,8 @@ public void mouseClicked(MouseEvent e) {
keybindPanel.setBorder(BorderFactory.createEmptyBorder(border10, border10, border10, border10));
worldListPanel.setBorder(
BorderFactory.createEmptyBorder(border10, border10, border10, border10));
+ joystickPanel.setBorder(
+ BorderFactory.createEmptyBorder(border10, border10, border10, border10));
authorsPanel.setBorder(BorderFactory.createEmptyBorder(border10, border10, border10, border10));
int verticalSpeed = osScaleMul(20);
@@ -507,6 +523,7 @@ public void mouseClicked(MouseEvent e) {
setScrollSpeed(streamingScrollPane, verticalSpeed, horizontalSpeed);
setScrollSpeed(keybindScrollPane, verticalSpeed, horizontalSpeed);
setScrollSpeed(worldListScrollPane, verticalSpeed, horizontalSpeed);
+ setScrollSpeed(joystickScrollPane, verticalSpeed, horizontalSpeed);
setScrollSpeed(authorsScrollPane, verticalSpeed, horizontalSpeed);
/*
@@ -2396,6 +2413,62 @@ public void actionPerformed(ActionEvent e) {
addPanelBottomGlue(authorsPanel);
+ // Joystick Tab
+
+ joystickPanel.setAlignmentY(Component.TOP_ALIGNMENT);
+ joystickPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
+ joystickPanel.setLayout(new BoxLayout(joystickPanel, BoxLayout.Y_AXIS));
+
+ addSettingsHeader(joystickPanel, "Explanation");
+
+ JLabel joystickExplanation =
+ new JLabel(
+ String.format(
+ ""
+ + "Currently, RSCx is compatible with only the 3DConnexion Space Navigator 3D Mouse.
"
+ + "It is used to enable a 5 degree of freedom camera (roll left/right is omitted).
"
+ + "This setting does not allow you to move the player with a joystick or perform in-game actions.
"
+ + "If you do not have a 3DConnexion Space Navigator 3D Mouse, you should not enable this setting."
+ + "
",
+ osScaleMul(10)));
+ joystickPanel.add(joystickExplanation);
+
+ addSettingsHeader(joystickPanel, "Joystick");
+ joystickPanelJoystickEnabledCheckbox =
+ addCheckbox(
+ "Enable Joystick polling (Performance decreased if not using joystick)", joystickPanel);
+ joystickPanelJoystickEnabledCheckbox.setToolTipText("Enable Joystick polling once every frame");
+ joystickPanelJoystickEnabledCheckbox.setBorder(
+ BorderFactory.createEmptyBorder(0, 0, osScaleMul(7), 0));
+
+ joystickInputJlabels.put("X Axis", new JLabel("X Axis"));
+ joystickInputJlabels.put("Y Axis", new JLabel("Y Axis"));
+ joystickInputJlabels.put("Z Axis", new JLabel("Z Axis"));
+ joystickInputJlabels.put("X Rotation", new JLabel("X Rotate"));
+ joystickInputJlabels.put("Y Rotation", new JLabel("Y Rotate"));
+ joystickInputJlabels.put("Z Rotation", new JLabel("Z Rotate"));
+ joystickInputJlabels.put("Button 0", new JLabel("Button 0"));
+ joystickInputJlabels.put("Button 1", new JLabel("Button 1"));
+
+ joystickInputValueJlabels.put("X Axis", new JLabel("No input"));
+ joystickInputValueJlabels.put("Y Axis", new JLabel("No input"));
+ joystickInputValueJlabels.put("Z Axis", new JLabel("No input"));
+ joystickInputValueJlabels.put("X Rotation", new JLabel("No input"));
+ joystickInputValueJlabels.put("Y Rotation", new JLabel("No input"));
+ joystickInputValueJlabels.put("Z Rotation", new JLabel("No input"));
+ joystickInputValueJlabels.put("Button 0", new JLabel("No input"));
+ joystickInputValueJlabels.put("Button 1", new JLabel("No input"));
+
+ joystickInputJlabels.forEach(
+ (key, value) -> {
+ joystickPanel.add(value);
+ joystickPanel.add(joystickInputValueJlabels.get(key));
+ JLabel joystickInputspacerLabel = new JLabel("
");
+ joystickPanel.add(joystickInputspacerLabel);
+ });
+
+ addPanelBottomGlue(joystickPanel);
+
//// End component creation ////
}
@@ -2928,6 +3001,10 @@ public void synchronizeGuiValues() {
// World List tab
synchronizeWorldTab();
+ // Joystick tab
+ joystickPanelJoystickEnabledCheckbox.setSelected(
+ Settings.JOYSTICK_ENABLED.get(Settings.currentProfile));
+
for (KeybindSet kbs : KeyboardHandler.keybindSetList) {
setKeybindButtonText(kbs);
}
@@ -3208,6 +3285,10 @@ public void saveSettings() {
if (Client.state == Client.STATE_GAME) Client.sortFriends();
+ //// joystick
+ Settings.JOYSTICK_ENABLED.put(
+ Settings.currentProfile, joystickPanelJoystickEnabledCheckbox.isSelected());
+
// Save Settings
Settings.save();
}
@@ -3542,6 +3623,16 @@ public void synchronizeWorldTab() {
}
}
}
+
+ public void updateJoystickInput(String compName) {
+ joystickInputValueJlabels
+ .get(compName)
+ .setText(
+ String.format(
+ "%d", (int) Math.floor(JoystickHandler.joystickInputReports.get(compName))));
+ joystickPanel.revalidate();
+ joystickPanel.repaint();
+ }
}
/** Implements ActionListener; to be used for the buttons in the keybinds tab. */
diff --git a/src/Client/JClassPatcher.java b/src/Client/JClassPatcher.java
index c9e251f..2a7e20d 100644
--- a/src/Client/JClassPatcher.java
+++ b/src/Client/JClassPatcher.java
@@ -140,6 +140,17 @@ private void patchGeneric(ClassNode node) {
hookClassVariable(
methodNode, "mudclient", "bz", "I", "Game/Client", "login_screen", "I", true, true);
+ hookClassVariable(
+ methodNode,
+ "jagex/client/j",
+ "dn",
+ "I",
+ "Game/Camera",
+ "pitch_internal",
+ "I",
+ true,
+ true);
+
hookConditionalClassVariable(
methodNode,
"jagex/client/j",
@@ -2261,6 +2272,35 @@ private void patchScene(ClassNode node) {
}
}
}
+
+ // Set camera routine
+ if (methodNode.name.equals("uh") && methodNode.desc.equals("(IIIIIII)V")) {
+ Logger.Info("patching setCamera()");
+
+ // offset_height hook
+ AbstractInsnNode start = methodNode.instructions.getFirst();
+ while (start != null) {
+ if (start.getOpcode() == Opcodes.PUTFIELD
+ && start.getPrevious().getOpcode() == Opcodes.ISUB) {
+ FieldInsnNode insnNode = (FieldInsnNode) start;
+ if (insnNode.name.equals("bn")) {
+ methodNode.instructions.insertBefore(
+ start, new FieldInsnNode(Opcodes.GETSTATIC, "Game/Camera", "offset_height", "I"));
+ methodNode.instructions.insertBefore(start, new InsnNode(Opcodes.ISUB));
+
+ break;
+ }
+ }
+
+ start = start.getNext();
+ }
+
+ // post-hook
+ AbstractInsnNode findNode = methodNode.instructions.getLast();
+ methodNode.instructions.insertBefore(
+ findNode,
+ new MethodInsnNode(Opcodes.INVOKESTATIC, "Game/Camera", "postSetCamera", "()V", false));
+ }
}
}
diff --git a/src/Client/Launcher.java b/src/Client/Launcher.java
index 09b31a0..c10093b 100644
--- a/src/Client/Launcher.java
+++ b/src/Client/Launcher.java
@@ -34,6 +34,8 @@
import java.awt.event.AWTEventListener;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@@ -118,6 +120,9 @@ public void init() {
}
}
+ // Extract libraries that only work outside the jar
+ extractJInputNatives();
+
// Set size
getContentPane().setPreferredSize(osScaleMul(new Dimension(280, 32)));
setTitle("RSCTimes Launcher");
@@ -587,6 +592,42 @@ public static void finishedLoading() {
Game.getInstance().getJConfig().changeWorld(1);
}
+ public static void extractJInputNatives() {
+ extractResource(
+ "/lib/jinput-natives/jinput-dx8_64.dll",
+ new File(Settings.Dir.JINPUTNATIVELIB + "/jinput-dx8_64.dll"));
+ extractResource(
+ "/lib/jinput-natives/jinput-raw_64.dll",
+ new File(Settings.Dir.JINPUTNATIVELIB + "/jinput-raw_64.dll"));
+ extractResource(
+ "/lib/jinput-natives/jinput-wintab.dll",
+ new File(Settings.Dir.JINPUTNATIVELIB + "/jinput-wintab.dll"));
+ extractResource(
+ "/lib/jinput-natives/libjinput-linux64.so",
+ new File(Settings.Dir.JINPUTNATIVELIB + "/libjinput-linux64.so"));
+ extractResource(
+ "/lib/jinput-natives/libjinput-osx.jnilib",
+ new File(Settings.Dir.JINPUTNATIVELIB + "/libjinput-osx.jnilib"));
+ }
+
+ public static void extractResource(String pathInJar, File destinationPath) {
+ try {
+ BufferedInputStream source = new BufferedInputStream(Launcher.getResourceAsStream(pathInJar));
+ BufferedOutputStream target = new BufferedOutputStream(new FileOutputStream(destinationPath));
+ byte[] buf = new byte[8192];
+ int length;
+ while ((length = source.read(buf)) > 0) {
+ target.write(buf, 0, length);
+ }
+ source.close();
+ target.close();
+ Logger.Info("Successfully extracted " + pathInJar);
+ } catch (Exception e) {
+ Logger.Error("Could not extract " + pathInJar);
+ e.printStackTrace();
+ }
+ }
+
/** @return the window */
public static ConfigWindow getConfigWindow() {
return configWindow;
diff --git a/src/Client/Settings.java b/src/Client/Settings.java
index ad9584e..bb1112f 100644
--- a/src/Client/Settings.java
+++ b/src/Client/Settings.java
@@ -181,7 +181,10 @@ public class Settings {
public static int WORLDS_TO_DISPLAY = 5;
public static boolean noWorldsConfigured = true;
- //// nogui
+ //// joystick
+ public static HashMap JOYSTICK_ENABLED = new HashMap();
+
+ //// no gui
public static HashMap COMBAT_STYLE = new HashMap();
public static HashMap WORLD = new HashMap();
public static HashMap FIRST_TIME = new HashMap();
@@ -1159,6 +1162,16 @@ public static void definePresets(Properties props) {
//// world list
initWorlds();
+ //// joystick
+ JOYSTICK_ENABLED.put("vanilla", false);
+ JOYSTICK_ENABLED.put("vanilla_resizable", false);
+ JOYSTICK_ENABLED.put("lite", false);
+ JOYSTICK_ENABLED.put("default", false);
+ JOYSTICK_ENABLED.put("heavy", false);
+ JOYSTICK_ENABLED.put("all", true);
+ JOYSTICK_ENABLED.put(
+ "custom", getPropBoolean(props, "joystick_enabled", JOYSTICK_ENABLED.get("default")));
+
COMBAT_STYLE.put("vanilla", Client.COMBAT_AGGRESSIVE);
COMBAT_STYLE.put("vanilla_resizable", Client.COMBAT_AGGRESSIVE);
COMBAT_STYLE.put("lite", Client.COMBAT_AGGRESSIVE);
@@ -1280,6 +1293,10 @@ public static void initDir() { // TODO: Consider moving to a more relevant place
Util.makeDirectory(Dir.REPLAY);
Dir.WORLDS = Dir.JAR + "/worlds";
Util.makeDirectory(Dir.WORLDS);
+ Dir.LIB = Dir.JAR + "/lib";
+ Util.makeDirectory(Dir.LIB);
+ Dir.JINPUTNATIVELIB = Dir.LIB + "/jinput-natives";
+ Util.makeDirectory(Dir.JINPUTNATIVELIB);
}
/**
@@ -2262,6 +2279,9 @@ public static void save(String preset) {
//// world urls
saveWorlds();
+ //// joystick
+ props.setProperty("joystick_enabled", Boolean.toString(JOYSTICK_ENABLED.get(preset)));
+
//// presets
props.setProperty("current_profile", currentProfile);
@@ -2468,6 +2488,8 @@ public static class Dir {
public static String SCREENSHOT;
public static String REPLAY;
public static String WORLDS;
+ public static String LIB;
+ public static String JINPUTNATIVELIB;
}
public static void updateInjectedVariables() {
diff --git a/src/Game/Camera.java b/src/Game/Camera.java
index 94c65a2..c9179d6 100644
--- a/src/Game/Camera.java
+++ b/src/Game/Camera.java
@@ -42,6 +42,10 @@ public class Camera {
public static int distance3; // This one is divided onto something to do with fog (it's usually 1)
public static int distance4; // This one seems to be fog distance
+ // This will offset the camera height
+ public static int offset_height = 0;
+
+ public static int pitch_internal;
public static float add_lookat_x;
public static float add_lookat_y;
public static int new_lookat_x;
@@ -51,6 +55,9 @@ public class Camera {
public static float delta_zoom = 0.0f;
public static float delta_rotation = 0.0f;
+ public static int pitch_rsctimes = 112;
+ public static boolean isUsing3DMouseControls = false;
+
private Camera() {
// Empty private constructor to prevent instantiation.
}
@@ -97,7 +104,7 @@ public static void update(float delta_time) {
else addZoom(8 * 50 * delta_time);
}
- if (!KeyboardHandler.keyShift) {
+ if (!KeyboardHandler.keyShift && !isUsing3DMouseControls) {
int tileX = ((int) add_lookat_x / 128) * 128;
int tileY = ((int) add_lookat_y / 128) * 128;
add_lookat_x = Util.lerp(add_lookat_x, tileX, 8.0f * delta_time);
@@ -116,9 +123,7 @@ public static void update(float delta_time) {
// If the user changes modes, reset
if (relative != Settings.CAMERA_MOVABLE_RELATIVE.get(Settings.currentProfile)) {
- add_lookat_x = 0;
- add_lookat_y = 0;
- relative = Settings.CAMERA_MOVABLE_RELATIVE.get(Settings.currentProfile);
+ resetCamera();
}
delta_lookat_x = new_lookat_x; // Util.lerp(delta_lookat_x, new_lookat_x, 8.0f * delta_time);
@@ -157,6 +162,14 @@ public static void resize() {
}
}
+ private static void resetCamera() {
+ add_lookat_x = 0;
+ add_lookat_y = 0;
+ relative = Settings.CAMERA_MOVABLE_RELATIVE.get(Settings.currentProfile);
+ resetPitch();
+ offset_height = 0;
+ }
+
public static void strafe(float speed) {
if (!Settings.CAMERA_MOVABLE.get(Settings.currentProfile)
|| Settings.SPEEDRUNNER_MODE_ACTIVE.get(Settings.currentProfile)) {
@@ -179,11 +192,32 @@ public static void move(float speed) {
add_movement(xDiff * speed, yDiff * speed);
}
+ // up or down
+ private static void elevate(float speed) {
+ if (!Settings.CAMERA_MOVABLE.get(Settings.currentProfile)
+ || Settings.SPEEDRUNNER_MODE_ACTIVE.get(Settings.currentProfile)) {
+ return;
+ }
+ offset_height -= speed;
+ }
+
+ // pitch forward or back
+ public static void pitch(float speed) {
+ if (!Settings.CAMERA_MOVABLE.get(Settings.currentProfile)
+ || Settings.SPEEDRUNNER_MODE_ACTIVE.get(Settings.currentProfile)) {
+ return;
+ }
+ pitch_rsctimes -= speed;
+ if (pitch_rsctimes < 0) pitch_rsctimes = 1023;
+ if (pitch_rsctimes > 1023) pitch_rsctimes = 0;
+ }
+
public static void add_movement(float x, float y) {
if (!Settings.CAMERA_MOVABLE_RELATIVE.get(Settings.currentProfile)
&& ((add_lookat_x == 0.0f && x != 0.0f) || (add_lookat_y == 0.0f && y != 0.0f))) {
add_lookat_x = lookat_x;
add_lookat_y = lookat_y;
+ if (isUsing3DMouseControls) offset_height = 200;
Client.displayMessage("The camera is no longer following the player", Client.CHAT_NONE);
}
@@ -233,6 +267,10 @@ public static void addRotation(float amount) {
public static void addZoom(float amount) {
if (amount == 0 || !Settings.CAMERA_ZOOMABLE.get(Settings.currentProfile)) return;
+ if (isUsing3DMouseControls) {
+ leave3DMouseControls();
+ }
+
delta_zoom += amount;
if (delta_zoom > 1238.0f) delta_zoom = 1238.0f;
else if (delta_zoom < 262.0f) delta_zoom = 262.0f;
@@ -263,4 +301,59 @@ public static void resetRotation() {
rotation = 126;
delta_rotation = (float) rotation;
}
+
+ public static void postSetCamera() {
+ Camera.pitch_internal = pitch_rsctimes;
+ }
+
+ public static void resetPitch() {
+ Camera.pitch_rsctimes = 112;
+ }
+
+ public static void handleJoystick(String inputName) {
+ float amount = JoystickHandler.joystickInputReports.get(inputName) / 50;
+ zoom = 0; // this is so that Z Rotation isn't displaced from the camera
+ isUsing3DMouseControls = true;
+ switch (inputName) {
+ case "X Axis":
+ if (KeyboardHandler.keyShift) {
+ move(amount / 2);
+ } else {
+ move(amount / 5);
+ }
+ break;
+ case "Y Axis":
+ if (KeyboardHandler.keyShift) {
+ strafe(amount / 2);
+ } else {
+ strafe(amount / 5);
+ }
+ break;
+ case "Z Axis":
+ elevate(JoystickHandler.joystickInputReports.get(inputName) / 10);
+ break;
+ case "X Rotation":
+ pitch(JoystickHandler.joystickInputReports.get(inputName) / 30);
+ break;
+ case "Y Rotation":
+ break;
+ case "Z Rotation":
+ addRotation(amount);
+ break;
+ case "Button 0":
+ if (JoystickHandler.joystickInputReports.get(inputName) == 1) break;
+ case "Button 1":
+ if (JoystickHandler.joystickInputReports.get(inputName) == 1) {
+ leave3DMouseControls();
+ }
+ break;
+ }
+ }
+
+ private static void leave3DMouseControls() {
+ isUsing3DMouseControls = false;
+ init(); // resets zoom as well
+ resetCamera();
+ Client.displayMessage("The camera is now following the player", Client.CHAT_NONE);
+ }
}
diff --git a/src/Game/Client.java b/src/Game/Client.java
index 6f6db74..b0cc290 100644
--- a/src/Game/Client.java
+++ b/src/Game/Client.java
@@ -265,6 +265,10 @@ public static void update() {
Camera.setLookatTile(getPlayerWaypointX(), getPlayerWaypointY());
Camera.update(delta_time);
+ if (Settings.JOYSTICK_ENABLED.get(Settings.currentProfile)) {
+ JoystickHandler.poll();
+ }
+
// Replay.update();
/*if (Settings.RECORD_AUTOMATICALLY_FIRST_TIME.get(Settings.currentProfile)
diff --git a/src/Game/Game.java b/src/Game/Game.java
index 098f737..8e3a978 100644
--- a/src/Game/Game.java
+++ b/src/Game/Game.java
@@ -101,6 +101,7 @@ public void start() {
Reflection.Load();
Renderer.init();
+ JoystickHandler.init();
}
public JConfig getJConfig() {
diff --git a/src/Game/JoystickHandler.java b/src/Game/JoystickHandler.java
new file mode 100644
index 0000000..e69670b
--- /dev/null
+++ b/src/Game/JoystickHandler.java
@@ -0,0 +1,79 @@
+package Game;
+
+import Client.Launcher;
+import Client.Settings;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import net.java.games.input.Component;
+import net.java.games.input.Controller;
+import net.java.games.input.ControllerEnvironment;
+import net.java.games.input.Event;
+import net.java.games.input.EventQueue;
+
+public class JoystickHandler {
+ public static List knownAxises = new ArrayList<>();
+ public static HashMap joystickInputReports = new HashMap();
+ public static HashMap joystickInputReportTimestamps = new HashMap();
+
+ public static void init() {
+ System.setProperty(
+ "net.java.games.input.librarypath",
+ new File(Settings.Dir.JAR + "/lib/jinput-natives").getAbsolutePath());
+ }
+
+ public static void poll() {
+ /* Get the available controllers */
+ Controller[] controllers = ControllerEnvironment.getDefaultEnvironment().getControllers();
+ if (controllers.length == 0) {
+ return;
+ }
+
+ for (int i = 0; i < controllers.length; i++) {
+ if (!isSupported3DMouse(controllers[i].getName())) continue;
+
+ // process the controller's eventqueue
+ controllers[i].poll();
+ EventQueue queue = controllers[i].getEventQueue();
+ Event event = new Event();
+ while (queue.getNextEvent(event)) {
+ Component comp = event.getComponent();
+ if (!knownAxises.contains(comp.getName())) {
+ knownAxises.add(comp.getName());
+ }
+
+ float value = event.getValue();
+ joystickInputReports.put(comp.getName(), value);
+ joystickInputReportTimestamps.put(comp.getName(), System.currentTimeMillis());
+
+ doJoystickAction(comp.getName());
+ }
+
+ // Update inputs that are stale
+ // returning to Zero position does not consistently generate an event, so we do this.
+ joystickInputReportTimestamps.forEach(
+ (key, value) -> {
+ if (value != 0) {
+ if (System.currentTimeMillis() - value > 100) {
+ joystickInputReports.put(key, 0f);
+ doJoystickAction(key);
+ }
+ }
+ });
+ }
+ }
+
+ private static boolean isSupported3DMouse(String name) {
+ return name.contains("SpaceNavigator") || name.contains("SpaceMouse");
+ }
+
+ public static void doJoystickAction(String inputName) {
+ if (joystickInputReports.get(inputName) != 0) {
+ Camera.handleJoystick(inputName);
+ }
+ if (Launcher.getConfigWindow().isShown()) {
+ Launcher.getConfigWindow().updateJoystickInput(inputName);
+ }
+ }
+}
diff --git a/src/Game/Menu.java b/src/Game/Menu.java
index dad33c1..3e4abe7 100644
--- a/src/Game/Menu.java
+++ b/src/Game/Menu.java
@@ -18,7 +18,6 @@
*/
package Game;
-
/** Handles adjusting the position and behavior of the in-game menu */
public class Menu {
diff --git a/src/Game/Renderer.java b/src/Game/Renderer.java
index a20d04d..79535a5 100644
--- a/src/Game/Renderer.java
+++ b/src/Game/Renderer.java
@@ -1030,6 +1030,8 @@ public static void present(Image image) {
y += 16;
drawShadowText(g2, "Camera Auto Speed: " + Camera.auto_speed, x, y, color_text, false);
y += 16;
+ drawShadowText(g2, "Camera Pitch: " + Camera.pitch_internal, x, y, color_text, false);
+ y += 16;
drawShadowText(g2, "Camera Rotation Y: " + Camera.rotation_y, x, y, color_text, false);
y += 16;
drawShadowText(g2, "Camera Lookat X: " + Camera.lookat_x, x, y, color_text, false);