Seems to work perfectly now from initial testing, thanks for the update
SLR browser/quest remote control plugin
For anybody interested, this is the updated script that uses the new toggles that will be released in 1.32.1. It’s improved in various ways and now uses System.Net.Http instead of TCP. This unfortunately will require you to start mfp as administrator though (can be solved by using a different library but this is fine for me for now). I’ll probably change it to a web socket in the future anyways. The plugin could potentially host a basic web page you can go to in your quest, getting similar functionality to deovr with all the MFP benefits. I didn’t add that here as for me it’s part of a larger app of mine but you can see my earlier post for details on how to do this yourself: MultiFunPlayer v1.33.1 - Multi-axis funscript player with SLR & FapTap support - #1261 by fenderwq
RemoteControlPlugin.cs.txt (17.7 KB)
How should my EDI/SetariaPlayer/FunscriptPlayer-compatible plugin be called?
- MultiGamePlayer
- MultiFunGamer
- Other (in comments)
MultiFunPlayer v1.32.1:
Download: timed patreon only exclusive
Patreon build: https://www.patreon.com/posts/118304718
1.32.1
Additional patreon only changelog:
- Fix SLR not using cached session when logging in with email
- Fix SLR not using cached session when username letter case differs from session username
- Fix DeoVR not staring if SLR fails to log in
- Convert DeoVR haptics input from buttons to toggles
- Improve behavior of DeoVR haptics input
Changelog:
- Use force seek when updating position after a seek request in Internal source
- Add support for toggles in shortcuts
- Fix crash when trying to create shortcuts with missing type
- Fix local script loading failing when one of the matched scripts is corrupted
- Improve performance of shortcut action runner
Plugins:
- Add or remove plugins after adding or removing folders
- Recompile plugins on file change event
- Recompile plugins when adding or removing xaml file
- Limit plugin path depth to one subfolder
- Automatically unregister all plugin registered actions on dispose
- Add helpers for starting plugin background tasks/threads that are cleaned up on dispose
- Fix plugin assembly not unloading
- Fix plugin compilation error when plugin file contains classes with no base class
- Fix plugin compilation error when non plugin class has constructors
1.32.0
Additional patreon only changelog:
- Support SLR login using login code
- Allow connecting DeoVR even when SLR login fails or credentials are empty
- Don’t use cached session if username is different
- Fix “wrong password” error when logging in to SLR
- Fix SLR api sending local scripts causing double sync
Changelog:
- Rework and simplify plugin system
- Allow placing plugins in subfolders
- Expose available actions and properties to plugins
- Allow plugins to create their own UI
- Improve performance of creating assembly references for plugins
- Register missing properties for plugins where possible to match registered actions
- Sample plugins: MultiFunPlayer Sample Plugins · GitHub
- Update to .net 9 (performance improvements)
- Allow assigned actions to be in disabled state instead of getting removed from shortcuts if plugin or output target action is unregistered (#88)
- Add support for auto-home and speed limit when using PolledUpdate (#180)
- Fix unable to place breakpoints in plugins due to plugin assembly embedded source not including BOM
- Fix nested dialogs getting stuck invisible in certain situations
- Fix custom curve motion provider tiling when using makima interpolation
- Fix manual axis transitions loosing steps with shortcuts in relative mode
- Fix axis value flipping repeatedly with invert option enabled by reverting it to invert script only
- Fix auto-home taking shorter time to complete than configured
- Fix SyncOnMediaResourceChanged not having any effect when set to false
- Fix MotionProvider::Custom Curve::Points::Set actions not updating display name
- Fix MotionProvider::Custom Curve::Points::Set actions adding additional point on each launch
If you like what I’m doing, please consider supporting me on Patreon
https://www.patreon.com/yoooi
Thanks
It does fail with “file is used by another program” once every while but works
Consider adding a little wait/retry
Is there a way to view multiple graphs at once? Or at least to view a graph of non-L0 axis?
Mkay I’ve got problems
MFP with my plugin is too slow to update multiaxis script at 60fps
2-axis is fine, but when I make it 3-axis it starts lagging behind
I wonder if it’s problem with my code or the MFP
Gonna test
No, could be made as a plugin I guess.
Use scroll wheel on the heatmap to switch the axes.
MFP updates internally at 400hz and each output at up to 333hz so I dont think its the problem.
My measurements say that setting up 6-axis takes 0 alot of time even for short scripts
Could you perf the ChangeScriptMessage please?
2025-01-12 18:53:29.6150|WARN|MultiFunPlayer.Plugins.TominFapHero2.HttpServerPlugin|Action: /Live2D/Tomin/v2/live (http://localhost:5000/Live2D/Tomin/v2/live?Day=11DAY_HAnime&Hand/35=0.5890,-10.0997&Penis/55=0.5646,-10.2049&Penis/60=0.5490,-10.0123&now=1736697209620)
2025-01-12 18:53:29.6150|WARN|MultiFunPlayer.Plugins.TominFapHero2.HttpServerPlugin|Projection Time: 0 ms
2025-01-12 18:53:29.6150|WARN|MultiFunPlayer.Plugins.TominFapHero2.HttpServerPlugin|SetScript 6 axes 28 keys 0.000-2.382 28 keys L0, L1, L2, R0, R1, R2
2025-01-12 18:53:29.6150|INFO|MultiFunPlayer.UI.Controls.ViewModels.ScriptViewModel|Received ChangeScriptMessage [Axes: L0, L1, L2, R0, R1, R2]
2025-01-12 18:53:29.6258|INFO|MultiFunPlayer.UI.Controls.ViewModels.ScriptViewModel|Set L0 script to [Name: "", Source: ""]
2025-01-12 18:53:29.6258|DEBUG|MultiFunPlayer.UI.Controls.ViewModels.ScriptViewModel|Searching for valid index [Axis: L0]
2025-01-12 18:53:29.6258|INFO|MultiFunPlayer.UI.Controls.ViewModels.ScriptViewModel|Set L1 script to [Name: "", Source: ""]
2025-01-12 18:53:29.6258|INFO|MultiFunPlayer.UI.Controls.ViewModels.ScriptViewModel|Set L2 script to [Name: "", Source: ""]
2025-01-12 18:53:29.6258|DEBUG|MultiFunPlayer.UI.Controls.ViewModels.ScriptViewModel|Searching for valid index [Axis: L1]
2025-01-12 18:53:29.6258|DEBUG|MultiFunPlayer.UI.Controls.ViewModels.ScriptViewModel|Searching for valid index [Axis: L2]
2025-01-12 18:53:29.6258|INFO|MultiFunPlayer.UI.Controls.ViewModels.ScriptViewModel|Set R0 script to [Name: "", Source: ""]
2025-01-12 18:53:29.6258|DEBUG|MultiFunPlayer.UI.Controls.ViewModels.ScriptViewModel|Searching for valid index [Axis: R0]
2025-01-12 18:53:29.6406|INFO|MultiFunPlayer.UI.Controls.ViewModels.ScriptViewModel|Set R1 script to [Name: "", Source: ""]
2025-01-12 18:53:29.6406|DEBUG|MultiFunPlayer.UI.Controls.ViewModels.ScriptViewModel|Searching for valid index [Axis: R1]
2025-01-12 18:53:29.6406|INFO|MultiFunPlayer.UI.Controls.ViewModels.ScriptViewModel|Set R2 script to [Name: "", Source: ""]
2025-01-12 18:53:29.6406|DEBUG|MultiFunPlayer.UI.Controls.ViewModels.ScriptViewModel|Searching for valid index [Axis: R2]
2025-01-12 18:53:29.6406|WARN|MultiFunPlayer.Plugins.TominFapHero2.HttpServerPlugin|SetScript 6 axes ok
2025-01-12 18:53:29.6406|WARN|MultiFunPlayer.Plugins.TominFapHero2.HttpServerPlugin|Elapsed Time: 210201 ticks 21 ms (serializing: 811 ticks)
2025-01-12 18:53:29.6406|WARN|MultiFunPlayer.Plugins.TominFapHero2.HttpServerPlugin|UpdateKfScript Time: 211083 ms
2025-01-12 18:53:29.6406|WARN|MultiFunPlayer.Plugins.TominFapHero2.HttpServerPlugin|Request time: 21 ms
Edit: I’ve perfed more, it seems every axis takes 1-3ms no matter what
Heatmap is internal class so thats hard
The script change message was not designed for what you are doing, you should set the axis value via Axis::Value::Set
(with invokeDirectly: true
) and it should work better.
Any change to the internal axis state requires a lock.
You could also try keeping a reference to the keyframe collection that you create the script resource with and add new keyframes without sending a new script. But I dont know how well will that work if at all.
As far as I see it requires a lock per axis
Would it be faster is there is only a single lock that is locked once for the whole change?
What are even the use cases where you want to lock each axis separately?
Technically yes, but the lock should be held at most for 0.3-0.5ms.
The multiple locks are from the old versions where the update thread did not lock all axes for an update like it does now.
Anyways, I still don’t understand what takes 3ms of constant per non-primary axis
I’d perf if I’d have the code I guess
The code on github is pretty much the same, current code uses the new lock which is supposed to be faster.
Btw I experience complete freezes (after which I have to kill MFP) when I click on GUI while it’s updating script in realtime
Should I lock something somewhere?
s.RegisterAction<double>("Media::ScriptOffset::Set",
s => s.WithLabel("Value").AsNumericUpDown(stringFormat: "{0:F2}s"), value => GlobalOffset = value);
There is an action for this, but can I read the property?
I would need more information, preferably steps to reproduce, what do you click specifically. It’s probably your plugin making a dead lock some how.
Media::ScriptOffset
All actions have a corresponding property to read.
Most likely
This is where it hangs it seems
Should I make a lock or something?
Hmm
Maybe I shouldn’t use
async
where I don’t need it so I can just make a global lock?
Okay makes sense. I search code of public version and it wasn’t there iirc
Feature requests:
- a static
L0
/L1
I could not make this code to dead lock, so its probably not that.
No, the axes are parsed on startup, you are not guaranteed that L0 or L1 will even exist if someone configures their device that way.
I do have a repro (but it’s heavy)
- Have something spam HTTP requests faster then they cane be processed so it’s busy 100% of the time
- HTTP requests update script with ChangeScriptMessage
- If you publish another message in
void HandleMessage(MediaSeekMessage message) => PublishMessage(new MediaPositionChangedMessage(message.Position, true));
from UI thread while it’s still processing ChangeScriptMessage in HTTP thread, it will hang
So, “you shouldn’t use lock
in async code” or something?
I’ve hacked in some SemaphoreSlim
(idk what’s that) and it seems to work now
A regular lock
didn’t work, a SemaphoreSlim
sis work
I have some videos where I have multiple versions of a funscript (not multi-axis, just on the main axis). I have them assigned in XBVR which is what I’m using for my script repository, and it looks like XBVR does send the multiple file data in the API. Is there a way to choose among the scripts in MFP (e.g. set up a controller shortcut to cycle through them)?
Is that linked to a specific behavior of MFP?