Skip to content

Commit

Permalink
Merge pull request RSCPlus#37 from conker-rsc/joystick
Browse files Browse the repository at this point in the history
Add 3D mouse support
  • Loading branch information
Hubcapp authored Dec 8, 2024
2 parents 373aadb + f0ed4f9 commit a35fe48
Show file tree
Hide file tree
Showing 19 changed files with 381 additions and 6 deletions.
1 change: 1 addition & 0 deletions .classpath
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<classpathentry kind="lib" path="lib/commons-compress-1.18.jar"/>
<classpathentry kind="lib" path="lib/hamcrest-core-1.3.jar"/>
<classpathentry kind="lib" path="lib/jansi-1.18.jar"/>
<classpathentry kind="lib" path="lib/jinput-2.0.9.jar"/>
<classpathentry kind="lib" path="lib/json-20201115.jar"/>
<classpathentry kind="lib" path="lib/junit-4.12.jar"/>
<classpathentry kind="lib" path="lib/flatlaf-3.1.1.jar"/>
Expand Down
2 changes: 2 additions & 0 deletions build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<property name="dist.dir" value="dist" />
<property name="bin.dir" value="bin" />
<property name="assets.dir" value="assets" />
<property name="jinput-natives.dir" value="lib/jinput-natives" />
<property name="tools.dir" value="tools" />
<property name="doc.dir" value="doc" />

Expand Down Expand Up @@ -104,6 +105,7 @@
<fileset dir=".">
<include name="${assets.dir}/**" />
<include name="${main.src.dir}/Client/FlatLaf/*.properties" />
<include name="${jinput-natives.dir}/**" />
<include name="LICENSE" />
</fileset>
<zipgroupfileset dir="lib" includes="*.jar" excludes="junit-*.jar,hamcrest-core-*.jar" />
Expand Down
Binary file added lib/coreapi-2.0.9.jar
Binary file not shown.
Binary file added lib/jinput-2.0.9.jar
Binary file not shown.
Binary file added lib/jinput-natives/jinput-dx8_64.dll
Binary file not shown.
Binary file added lib/jinput-natives/jinput-raw_64.dll
Binary file not shown.
Binary file added lib/jinput-natives/jinput-wintab.dll
Binary file not shown.
Binary file added lib/jinput-natives/libjinput-linux64.so
Binary file not shown.
Binary file added lib/jinput-natives/libjinput-osx.jnilib
Binary file not shown.
91 changes: 91 additions & 0 deletions src/Client/ConfigWindow.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import Game.Camera;
import Game.Client;
import Game.Game;
import Game.JoystickHandler;
import Game.KeyboardHandler;
import Game.Renderer;
import com.formdev.flatlaf.ui.FlatRoundBorder;
Expand Down Expand Up @@ -67,6 +68,7 @@
import java.util.Arrays;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.LinkedHashMap;
import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.Box;
Expand Down Expand Up @@ -284,6 +286,12 @@ public class ConfigWindow {
private HashMap<Integer, JLabel> worldListSpacingLabels = new HashMap<Integer, JLabel>();
private JPanel worldListPanel = new JPanel();

//// Joystick tab
private JCheckBox joystickPanelJoystickEnabledCheckbox;
private HashMap<String, JLabel> joystickInputJlabels = new LinkedHashMap<String, JLabel>();
private HashMap<String, JLabel> joystickInputValueJlabels = new HashMap<String, JLabel>();
private JPanel joystickPanel = new JPanel();

public ConfigWindow() {
Util.setUITheme();
eventQueueListener = createConfigWindowEventQueueListener();
Expand Down Expand Up @@ -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()) {
Expand Down Expand Up @@ -424,6 +433,7 @@ public void mouseClicked(MouseEvent e) {
streamingScrollPane.setBorder(scrollPaneBorder);
keybindScrollPane.setBorder(scrollPaneBorder);
worldListScrollPane.setBorder(scrollPaneBorder);
joystickScrollPane.setBorder(scrollPaneBorder);
authorsScrollPane.setBorder(scrollPaneBorder);
}

Expand All @@ -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");

Expand All @@ -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);
Expand All @@ -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
Expand Down Expand Up @@ -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);
Expand All @@ -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);

/*
Expand Down Expand Up @@ -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(
"<html><head><style>p{font-size:%dpx;}</style></head><p>"
+ "Currently, RSCx is compatible with only the 3DConnexion Space Navigator 3D Mouse.<br/>"
+ "It is used to enable a 5 degree of freedom camera (roll left/right is omitted).<br/><br/>"
+ "This setting does not allow you to move the player with a joystick or perform in-game actions.<br/><br/>"
+ "If you do not have a 3DConnexion Space Navigator 3D Mouse, you should not enable this setting."
+ "</p><br/></html>",
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("<html><br/></html>");
joystickPanel.add(joystickInputspacerLabel);
});

addPanelBottomGlue(joystickPanel);

//// End component creation ////
}

Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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();
}
Expand Down Expand Up @@ -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. */
Expand Down
40 changes: 40 additions & 0 deletions src/Client/JClassPatcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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));
}
}
}

Expand Down
41 changes: 41 additions & 0 deletions src/Client/Launcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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;
Expand Down
24 changes: 23 additions & 1 deletion src/Client/Settings.java
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,10 @@ public class Settings {
public static int WORLDS_TO_DISPLAY = 5;
public static boolean noWorldsConfigured = true;

//// nogui
//// joystick
public static HashMap<String, Boolean> JOYSTICK_ENABLED = new HashMap<String, Boolean>();

//// no gui
public static HashMap<String, Integer> COMBAT_STYLE = new HashMap<String, Integer>();
public static HashMap<String, Integer> WORLD = new HashMap<String, Integer>();
public static HashMap<String, Boolean> FIRST_TIME = new HashMap<String, Boolean>();
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}

/**
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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() {
Expand Down
Loading

0 comments on commit a35fe48

Please sign in to comment.