Maselkov / GW2RPC

Discord Rich Presence addon for Guild Wars 2
https://gw2rpc.info
GNU General Public License v3.0
46 stars 12 forks source link

Custom MumbleLink name support #17

Closed writzx closed 2 years ago

writzx commented 2 years ago

More of a question and observation. I am not familiar with how mumble link works internally but for my use case, I have to use a custom mumble link name (which I am specifying via gw2launcher, and it's dependent on what gw2launcher sets).

image

This breaks rpc since it uses a hardcoded name as well (https://github.com/Maselkov/GW2RPC/blob/master/gw2rpc/mumble.py#L39) from what I understand and it always shows "In Character Selection".

My use case is multiboxing + gw2radial. This requires custom mumble link names otherwise there are problems with the overlay. https://github.com/Friendly0Fire/GW2Radial/issues/208

I realize this might be hard for GW2RPC to emulate since it's not an addon and probably cannot access the command line. However what about setting something similar via the config and determining which process is active?

n1tr0-5urf3r commented 2 years ago

Hi writzx,

I prepared a prototype to implement multibox support via custom mumbleLink names in the settings. It seems to work with custom MumbleLink names, but as I understood it, there is no way to change the Gw2 process name in the GW2Launcher, so it will display "in Character selection", if the custom MumbleLink instance is not running but other instances are.

So it seems like the only use case for this would be to have the option to be able to change the MumbleLink API name for your case, but not something like "dynamic multiboxing" which automatically detects the correct instance running.

Feel free to reach out to me on the support discord server to test it:)

writzx commented 2 years ago

I would love to help test stuff out for it. I have spent some time understanding how mumblelink works meanwhile and I will share my findings as well.

I might be misunderstanding the situation a bit, but I had the idea there would be a way to link the process/mumble link data using a few pointers. I'll try to list them out.

  1. iteration of processes to find out the command line used to launch them:
  2. the processId parameter may be of help in case overlapping mumble links:

So, from the command lines, we should have a list of mumble link names that are attached to Gw2-64.exe. example: Gw2-64.exe -mumble "MumbleLink_1" If we don't find the mumble link name in the command line, the process id can be linked to the default mumble link name (already used by gw2rpc), where it might be overlapping with other processes (possible for non-default mumble link names as well). The processId field in the mumble link context can then be used for tracking which process is active (not necessarily required in our case).

n1tr0-5urf3r commented 2 years ago

Okay so for example with the following snippet we can get a list of all active mumblelinks or fall back to the default name if there is no parameter:

import psutil            

try:
    for process in psutil.process_iter():
        pinfo = process.as_dict(attrs=['pid', 'name', 'cmdline'])
        if pinfo['name'] in ("Gw2-64.exe", "Gw2.exe"):
            cmdline = pinfo['cmdline']
            try:
                mumble_link = cmdline[cmdline.index('-mumble') + 1] + " " + str(pinfo['pid'])
            except ValueError:
                mumble_link = "MumbleLink " + str(pinfo['pid'])
            print(mumble_link)
except psutil.NoSuchProcess:
    pass

which will output the mumble link and corresponding process id, i.e.

MumbleLink_main 6488
MumbleLink_alt1 9776

To get the data from Gw2 then, we would have to create a memfile to read from that MumbleLink name. I think the processId in the context struct will be the same as the pid returned by psutil. At least they are the same without multiboxing.

What was your idea then to determine which mumblelink context should be used to send to discord? Maybe I misunderstood your first message, because I thought you wanted to configure that via gw2rpc's config file.

writzx commented 2 years ago

It's pretty much what you described with the snippet that I had in mind. Do you think that is enough to get the dynamic tracking of multiple instances?

What was your idea then to determine which mumblelink context should be used to send to discord? Maybe I misunderstood your first message, because I thought you wanted to configure that via gw2rpc's config file.

You can probably ignore my initial suggestion at this point because I didn't realize we had ways to get the command line without being an add-on, in which case we wouldn't really have a way to find the mumble link names. But with the command-line we have the list dynamically.

Probably the only thing that's not (yet?) possible to dynamically determine is the currently active gw2 process to show the correct character details.

n1tr0-5urf3r commented 2 years ago

It's pretty much what you described with the snippet that I had in mind. Do you think that is enough to get the dynamic tracking of multiple instances?

In theory that should be doable with that, at least I think so.

Probably the only thing that's not (yet?) possible to dynamically determine is the currently active gw2 process to show the correct character details.

That's the main issue, I don't think that there is a way to dynamically determine the currently active process, but maybe we could work around that? Like cycling periodically through all active mumble links, or specyfing some order of precedence?

n1tr0-5urf3r commented 2 years ago

I don't think that there is a way to dynamically determine the currently active process

Scrap that, there is the uint32_t uiState; field in the mumble context struct, where Bit 4 determines if the game has focus. Maybe that could be used, at least that bit was 1 for the instance I had actually up and 0 for the other ones. Would need some fallback then too though if there is no instance in focus (meaning you are tabbed out of the game)

writzx commented 2 years ago

That's a pretty big find.

Would need some fallback then too though if there is no instance in focus (meaning you are tabbed out of the game)

I that case, I think you could just save the processes in an ordered list (based on their order of previous focus). And just use the most recently focused instance.

n1tr0-5urf3r commented 2 years ago

That's a pretty big find.

True and I think that I already implemented it. As far as I tested it, it worked. But I'm not experienced enough with multiboxing to decide that.

I have 2 Accounts and downloaded Gw2Launcher for that, where I set a custom MumbleLink Name each. If I run gw2rpc now, it will always display the state of the last active instance. I think I will clean it up a bit more and push it to the 2.3 branch then, could you test it then in your daily playing?

n1tr0-5urf3r commented 2 years ago

You can find the beta in releases :) Looking forward to your feedback!

writzx commented 2 years ago

I think I will clean it up a bit more and push it to the 2.3 branch then, could you test it then in your daily playing?

Sure. Would love to try it out.

I did some mild testing before leaving for work, and it seemed to pick up my main just fine. However, the alts weren't picked up at all. I will do some thorough testing when I get back and let you know if I notice something. For the record, I am running fullscreen windowed if that matters for the uiState var.

n1tr0-5urf3r commented 2 years ago

I tested it with fullscreen windowed too, that shouldnt be a problem. Did you happen to start gw2rpc.exe before starting your GW2 instances? Because I only checked once at the beginning for existing mumble links. I changed that to dynamically search for active mumble instances and add new ones to the pool on the fly (and kill old ones!), fix is coming soon :)

Also note that rich presence can only be updated every 15s, so it might take a short time to show up and change.

EDIT: New beta release is there :)

writzx commented 2 years ago

Yeah. looks like that was the issue.

gw2rpc is a startup program for me so usually, it's already running whenever I launch a new instance.

And I did some testing with 4-5 accounts on the new build. Seems to be working correctly. I really like that the duration tracking is actually consistent across the accounts 😄

I'll keep on testing some more.

n1tr0-5urf3r commented 2 years ago

I created a new version, which now display "In character select" if you return to the character screen and doesnt remain on the previous character.

I'm not quite sure if this introduced some new bugs, especially with the new multiboxing. One thing I noticed is, that it display the previous character for the first period of 15s when going from Char1 -> Character select -> Char2 sometimes, but it seems as the mumble data just does not update fast enough there.

Could you test it once more and give me some feedback? :)

n1tr0-5urf3r commented 2 years ago

Implemented in #18