BoxedWine
02-12-2021, 11:53 AM
Hi,
I decided to revisit an MMO in slow decline, and see how far its automation could be pushed.
Chose HotKeyNet because it was free and because its website provided a huge amount of detail in a well-organised way.
My PC setup is fairly complex, being a Linux (Pop!_OS) host (on its own dedicated GPU) running a Windows VM guest (on a second, much better passthrough GPU) - generally controlled using 'barrier-kvm' (guest as server) or 'looking-glass'/SPICE with pros and cons depending on the situation.
I decided to run the main client and HKN server on the Windows guest, with the other clients on the host under WINE - odd as it might sound, this actually simplified multi-monitor setup tremendously.
I'd not used WINE before, and it took me a while to get to grips with what it was actually doing vs. what it pretended to be doing. I will say that 'helpers' like PlayOnLinux and Lutris did not help at all, just made it harder to work out what to fix and where. I'm sure they're great for more recent games, particularly those you'd only be running one instance of, but that's not today's topic.
I took the game's base environment (wineprefix/'bottle') from Steam Play, used winecfg to enable Virtual Desktop mode (important for window management later), and made a copy for each client I intended to run. These are directories that can be moved/copied like any other.
HKN has a quirk. Multiple clients can communicate with the server from the same IP (correctly recognising their different ports), but a SendPC action doesn't accept 'IP : portnumber '- only IP. As such, the keys would go only to the most recent client to connect rather than the whole set.
This is a very understandable quirk. The overwhelming majority of scenarios involving interactive applications involve one or multiple windows on the same graphical session on the same PC. While I was running in different wineprefixes which behave as different graphical sessions, these count as all being part of the same PC in terms of network configuration.
The solution - 'ForceBindIP'. I found one old reference to this software in this forum, and none in HKN's (where I would have posted this if new registration had been permitted)
Multiple applications running in the same wineprefix can interact as if they shared a real Windows desktop session; this is easier to see and understand in Virtual Desktop mode but I imagine it'd still work with that disabled.
WINE already 'saw' the host's network adapters, so it was just a matter of 1) making more and 2) getting the instance of HKN in each prefix to use a different one.
THE PROCESS:
1)
(where adapter name is 'virbr1' with static IP '192.168.100.1/24')
ip addr add 192.168.100.2/24 dev virbr1 label virbr1:2
ip addr add 192.168.100.3/24 dev virbr1 label virbr1:3
ip addr add 192.168.100.4/24 dev virbr1 label virbr1:4
...more as needed
This needs root, so I have it as a script to be run under sudo whenever I want to play this particular game. I know there are better ways.
2)
I added these elements into the game's launch script, which I call from a .desktop file. They assume that the game has already been launched x times in its respective prefixes
WINEPREFIX=/home/<me>/wineprefixes/1 wine ForcebindIP.exe 192.168.100.1 /home/<me>/opt/Hotkeynet/hotkeynet.exe
WINEPREFIX=/home/<me>/wineprefixes/2 wine ForcebindIP.exe 192.168.100.2 /home/<me>/opt/Hotkeynet/hotkeynet.exe
WINEPREFIX=/home/<me>/wineprefixes/3 wine ForcebindIP.exe 192.168.100.3 /home/<me>/opt/Hotkeynet/hotkeynet.exe
...
I found it interesting that ForceBindIP required the absolute location of my HKN exe in Linux' path format, not that of Windows.
Note: Don't confuse /opt with ~/opt. ForcebindIP can go in /opt if you like, but HKN needs to write its config file and this is far easier to handle if it's kept out of restricted directories.
In my scenario it was actually helpful that all HKN instances shared a config file - if this had not been the case, I'd probably have copied its directory into each prefix rather than calling it from 'outside'
I already had some 'sleep' entries in my script, largely to cover race conditions with the game launches and my window manager's focus commands. After a lot of tinkering, I got i3 to open the different copies on particular screens in particular places - but that's very specific to my setup, and not germane to the core tip which is 'Launching HKN with a suitably configured ForceBindIP can make it usable when it otherwise wouldn't be'.
Again, I don't consider this a 'flaw' of HKN - which has held up remarkably well over time, and which otherwise provides enough information/options to make amazing things possible. Even if HKN2 were still being developed, I think socket conflicts/port specification would be so niche as to be at the very bottom of any sane dev's to-do list - particularly when an acceptable workaround is present.
I hope this is of use to anyone else going down the same rabbit-hole. The snippets I provide will likely not work perfectly for you as-is, one important thing is to know what your script's 'working directory' is at any point in time and to change it when needed.
Cheers,
BoxedWine
I decided to revisit an MMO in slow decline, and see how far its automation could be pushed.
Chose HotKeyNet because it was free and because its website provided a huge amount of detail in a well-organised way.
My PC setup is fairly complex, being a Linux (Pop!_OS) host (on its own dedicated GPU) running a Windows VM guest (on a second, much better passthrough GPU) - generally controlled using 'barrier-kvm' (guest as server) or 'looking-glass'/SPICE with pros and cons depending on the situation.
I decided to run the main client and HKN server on the Windows guest, with the other clients on the host under WINE - odd as it might sound, this actually simplified multi-monitor setup tremendously.
I'd not used WINE before, and it took me a while to get to grips with what it was actually doing vs. what it pretended to be doing. I will say that 'helpers' like PlayOnLinux and Lutris did not help at all, just made it harder to work out what to fix and where. I'm sure they're great for more recent games, particularly those you'd only be running one instance of, but that's not today's topic.
I took the game's base environment (wineprefix/'bottle') from Steam Play, used winecfg to enable Virtual Desktop mode (important for window management later), and made a copy for each client I intended to run. These are directories that can be moved/copied like any other.
HKN has a quirk. Multiple clients can communicate with the server from the same IP (correctly recognising their different ports), but a SendPC action doesn't accept 'IP : portnumber '- only IP. As such, the keys would go only to the most recent client to connect rather than the whole set.
This is a very understandable quirk. The overwhelming majority of scenarios involving interactive applications involve one or multiple windows on the same graphical session on the same PC. While I was running in different wineprefixes which behave as different graphical sessions, these count as all being part of the same PC in terms of network configuration.
The solution - 'ForceBindIP'. I found one old reference to this software in this forum, and none in HKN's (where I would have posted this if new registration had been permitted)
Multiple applications running in the same wineprefix can interact as if they shared a real Windows desktop session; this is easier to see and understand in Virtual Desktop mode but I imagine it'd still work with that disabled.
WINE already 'saw' the host's network adapters, so it was just a matter of 1) making more and 2) getting the instance of HKN in each prefix to use a different one.
THE PROCESS:
1)
(where adapter name is 'virbr1' with static IP '192.168.100.1/24')
ip addr add 192.168.100.2/24 dev virbr1 label virbr1:2
ip addr add 192.168.100.3/24 dev virbr1 label virbr1:3
ip addr add 192.168.100.4/24 dev virbr1 label virbr1:4
...more as needed
This needs root, so I have it as a script to be run under sudo whenever I want to play this particular game. I know there are better ways.
2)
I added these elements into the game's launch script, which I call from a .desktop file. They assume that the game has already been launched x times in its respective prefixes
WINEPREFIX=/home/<me>/wineprefixes/1 wine ForcebindIP.exe 192.168.100.1 /home/<me>/opt/Hotkeynet/hotkeynet.exe
WINEPREFIX=/home/<me>/wineprefixes/2 wine ForcebindIP.exe 192.168.100.2 /home/<me>/opt/Hotkeynet/hotkeynet.exe
WINEPREFIX=/home/<me>/wineprefixes/3 wine ForcebindIP.exe 192.168.100.3 /home/<me>/opt/Hotkeynet/hotkeynet.exe
...
I found it interesting that ForceBindIP required the absolute location of my HKN exe in Linux' path format, not that of Windows.
Note: Don't confuse /opt with ~/opt. ForcebindIP can go in /opt if you like, but HKN needs to write its config file and this is far easier to handle if it's kept out of restricted directories.
In my scenario it was actually helpful that all HKN instances shared a config file - if this had not been the case, I'd probably have copied its directory into each prefix rather than calling it from 'outside'
I already had some 'sleep' entries in my script, largely to cover race conditions with the game launches and my window manager's focus commands. After a lot of tinkering, I got i3 to open the different copies on particular screens in particular places - but that's very specific to my setup, and not germane to the core tip which is 'Launching HKN with a suitably configured ForceBindIP can make it usable when it otherwise wouldn't be'.
Again, I don't consider this a 'flaw' of HKN - which has held up remarkably well over time, and which otherwise provides enough information/options to make amazing things possible. Even if HKN2 were still being developed, I think socket conflicts/port specification would be so niche as to be at the very bottom of any sane dev's to-do list - particularly when an acceptable workaround is present.
I hope this is of use to anyone else going down the same rabbit-hole. The snippets I provide will likely not work perfectly for you as-is, one important thing is to know what your script's 'working directory' is at any point in time and to change it when needed.
Cheers,
BoxedWine