MultiFunPlayer v1.32.1 - Multi axis funscript player - Now with SLR script streaming

did some testing, with auto-connect button on, it still disconnects, but helps it reconnect after putting back the headset on. But forgot to mention another bad thing about when it disconnects is it looses the loaded script, so have to reload script in player whenever it disconnects. Pretty sure its disconnecting beacuse headset goes to auto sleep, can increase that time but ofcourse that drains battery. Before it lost slr support, I used to use joyfunplayer connected to slr and it never disconnected even with the headset off for long period of time, so perhaps some way to get it to stay connected is possible dunno.

edit: Or at least if could make it so player doesnt loose the script when disconnects would also be an improvement
besides that all perfect loving the player and its awesome flexibility/functionality

Thanks

The actual issue might be that if you first start a SLR video+script in DeoVR and only after that connect MFP it wont load the script.
The disconnect/reconnect due to auto sleep should not matter as MFP receives new state on connect.
Or it also might be a bug in DeoVR where you need to set the script again for the api to reset inside DeoVR.

Lemme ask a stupid question

Could MFP be a buttplug.io server (i.e. to have buttplug input source) in the further future (e.g. 2028)?

My Intiface Central experience with OSR2 where you can only use a single unconfigurable axis is pretty meh compared to MFP axis configs/hotkeys/mapping/randomiser

(Note: I remember finding an archived C# buttplug server implementation somewhere on buttplug github)

1 Like

@Yoooi so I made a nice plugin that communicates with a web overlay for quest that contains stuff like range sliders, an edging mode, etc. which are mapped to the DeoVR buttons to make it pretty much on par with the native handy toy controls in the DeoVR app, thanks for the help!

Only thing that I find weird is that I need to press the DeoVR haptic buttons twice to trigger an action. Why is that? Can this be changed / improved or am I just overlooking something?

Sure, should be done by 31.12.2028 depending on how difficult it is to make a dummy server.
Tho this would be a good feature for a plugin.

Cool! I actually wanted to make something very similar, like a dashboard/tile style page you can use to invoke actions. Using AvailableActions, AvailableProperties you should be able to make this fully dynamic/configurable.

So the buttons are really toggles, so you toggle on/off edge mode, so for a full click (off → on → off) you have to press the button it twice.
At least thats the behavior I got pressing the buttons in the UI, maybe they behave differently if you make shortcuts for them in DeoVR. You can enable trace logging and see the button events.
If there is a way to get events for on/off and the UI button press/release separately (press → release → on → press → release → off) I could add it but from my testing DeoVR only sends the feature state not button state.

1 Like

Also make sure it doesn’t say “Click count: 2” (why is that even a default?)

1 Like

The default is now changed to 1. The default was 2 because at first this was a DoubleClick shortcut that then changed to configurable amount of clicks but the default value remained.

1 Like

Ahh, that explains it. Checked out the log and this is what I see for the edging button when using it bound to my controller.

First click
Received command “{“Time”:“2024-12-20T18:14:28.172029Z”,“IsHolding”:false,“IsDown”:true,“Type”:3}”

Second click
Received command “{“Time”:“2024-12-20T18:14:28.594306Z”,“IsHolding”:false,“IsDown”:false,“Type”:3}”

I think MFP only triggers the button action on IsDown true or false or something.

Personally I think it would make more sense if it triggered on each command that is received regardless of the parameters as this is more usuable. It’s pretty inconvenient to double click some button combinations and also different from how the rest of the DeoVR app works.

In the future it would be nice to get the IsHolding and IsDown parameters as input too as that would allow us to sync with the deovr switch state and to add logic for hold for edging like DeoVR has with MFP too. This will also align with single click behavior.

Anyways, cool this is possible regardless and curious to hear your thoughts about triggering the action each time a command for a specific haptic button is received.

Repeat count: 0.5 lol

You know, I know your joking but even that would be fine with me. I just want to be able to register each button event so I can implement the logic I want (a single press toggle). Now you don’t have that choice.

@Yoooi can I have a solution on how to make a plugin?
A Visual Studio solution (or whatever works eg vscode)
I havent seesharped for years now

Hmm
I’ve managed to make a solution, link dlls, and copy GlobalUsing.cs from decompiled MFP.dll

What was I trying to make again? :thinking:

You dont need to make solutions, you can just edit the .cs files in any text editor, tho you lose intellisense.
You also dont need GlobalUsings, if you have a solution visual studio will help you add the usings at the top. The global usings for plugins are just so that you dont have to add them for each plugin if you dont use visual studio.


Consider adding multiline error please
…
Also how do I use a dll
…
Okay I’ve just got the dll-excluded build of MFP and it works now

Yea, that part could be improved.

//#r "System.Net.Http"

using System.Net.Http;

At the top of the plugin.
Tho I wonder why plugins dont have a reference to “System.Net.Http” while MFP does.

What do you mean by “dll-excluded”?

HttpListener, I’m making a server

The one that uses system .net dlls

It already responds with the url I put into localhost:5000

Now i stumbled on how to make it play the specified chapter of the specified funscript with tge specified offset because that’s what EDI does and that’s what I’m trying to clone

My current plan is running AssemblyPubliciser over mfp.dll, dnspying Internal source into a singleton, and using it’s now not private methods to run scripts

Well, you dont need my help if you want to make a plugin this way then.
If I understand correctly you can literally make that by handling one event, and publishing another.

But which ones?

I’ve tried this

        var result = new Dictionary<DeviceAxis, IScriptResource>();
        var scriptName = context.Request.Url.LocalPath.Replace("/Edi/Play/", "");

        var fi = new FileInfo($"./ClassLibrary1/funscript/{scriptName}.funscript");

        var fr = FunscriptReader.Default;
        var readerResult = fr.FromFileInfo(fi);
        if (readerResult.IsSuccess && readerResult.IsMultiAxis)
        {
            result.Merge(readerResult.Resources);
            PublishMessage(new ChangeScriptMessage(result));
        }

but it doesn’t seem to do anything
…
It does override the graph
… but only after I’ve started-stopped internal source?
And I can’t seek on the graph
…
I will try MediaPathChangedMessage now

Enough trying for today, here’s what I’ve got (it doesn’t really work but some pieces seem to do something somewhat close to correct)
ServerPlugin.cs.txt (4.7 KB)

Okay it works now

        InvokeAction("Internal::Playlist::PlayByName", $"{file}.funscript", true);
        InvokeAction("Media::PlayPause::Set", true, true);
        InvokeAction("Media::Position::Time::Set", start, true);

        // sleep because Internal::Playlist::PlayByName resets AB
        await Task.Delay(10);
        InvokeAction("Media::Loop::Set", start, end, true);
        InvokeAction("Media::Position::Time::Set", start + 0.010, true);
        Logger.Info($"Playing {file} from {start} to {end}");