What's new

Life-to-toys with XToys. Small Tutorial


Joined
Nov 15, 2020
Messages
3
Reputation score
0
Hi there,

long-time-lurker, here. I thought that I might give something back to the community.

Recently, I found a nice little app called "XToys" and I think that some of you might be interested in its potential.

At its most distilled, this is an app for controlling "toys" - toys that vibrate, airpulse, etc. Most often, if one of those toys is bluetooth-enabled, the manufacturer already supplied a small app - but XToys goes a bit beyond. It also allows you to connect those toys. Connect to where and what? Well - this is where things get interesting.

Instead of going into advertisement or promotion, I'd like to show some of the possibilities via a tutorial. If you have a supported toy and follow the tutorial, you should be able to let your toy rect to events in a computer game. I think that there are some games referenced in this forum that might be interesting for a "control your toys"-scenaria.

How's that for a small teaser: At some point in this tutorial, the vibration intensity of the toy will be linked to the arousal/libido of the protagonist of the game "Captivity"

Step 1: Connect the toy to the app

Some toys can only be directly connected to the WebApp in Chrome, others can only be directly connected to the App on a smartphone (something about Bluetooth Low Energy, I guess). There is a compatibility-list at .
Don't worry if you have one of those app-only-toys. I will use one of those, too - and the PC-connection only is a small hurdle.

Adding the toy often is rather easy:
  • Download and start the app (it is not on Play Store but needs to be downloaded from the web-app-page)
  • remember to enable bluetooth (the app does not demand enabled bluetooth on startup - simply fails to connect)
  • Press the Plus-Button and select your toy from the "toys" section (we will go into the "tools" and "scripts", later)
  • Press the Bluetooth-button on the added widget; enable pairing on your toy and hope that the connection succeeds.
Once the Bluetooth-symbol turns green, you should be connected. You can change the intensity by sliding over the left area and select different patterns via the button ("On" is simply on, "Off" is simply off and there is some "random" stuff in the puiblic patterns in case everything else feels too predictable).

Step 2: Connect the Mobile-App to the Desktop-App

If your toy is directly supported by the WebApp in Chrome, you can skip this step.

XToys allows users to open a session and le other users connect to it. That way, several people can have a party, connecting their own tools and controlling others. Here, this feature will be used to connect the mobile app to the desktop/browser app.
  • Click the globe-symbol on deskop, select "Host Session", check the settings and confirm. Note the Session Code.
  • Press the globe-symbol on the mobile app; select "Join Session" and enter the Session Code; press "Join"
  • After a short moment, the mnew connection should appear in the Desktop-browser's connections-list.
  • The dashboard should now be linked; the mobile app should display the same widgets and data as the desktop app. You should be able to control the toy via the desktop browser.
Unfortunately, this linking seems to not be very stable in the software. I've had quite a few app-crashes and it often takes several tries to get the connection working. Sometimes some workarounds help:
  • Add the toy to the desktop-app before hosting the session. You cannot start the connection there, buit the toy will be present for the mobile app to connect.
  • Do not connect the toy on the mobile app before joining the session. Wait for the dashboard to load and only then tap the bluetooth-button.
  • Deactivate Standby on the mobile phone; attach it to a charger during the session.
I wish this was more reliable. Maybe I'm the only one having these technical difficulties.
Once you can control the toy via your desktop browser, it's time to start scripting. Oh.. did I forget to mention "you can script stuff" in the teaser?

Step 3: See an example script in motion
I don't want to jump directly to the "connection with a game"-stuff. I think it's important to know (or at least "have seen" the scripting concept.
  • In this example, we will not touch the toy-interface and thus need another input.
  • Add a simple push button - press the Plus Button (like with the toy), switch to "Tools" and select "Push Button" from the list. You might also want to glance at what other tools are available and phantasize on how to use them.
  • You can click on that button in the interface - but it is not "wired" to anything, yet.
  • Next, add a script (Plus Button, "Scripts". Let's use "Dilemma" as a simple example
  • Click on the plug in the "Dilemma"-Widget; Select your PushButton as the button and your toy as generic output. Then click "Save"
  • The plug should have vanished and be replaced with the abbreviation of your blocks.
  • Click the "Play"-Button on the "Dilemma"-Widget. The script should now be running - but nothing happens, yet.
  • As the description states, the toy's power level will rise by 5% if anyone pushes the button. Try clicking the button a few times (either on your phone or on desktop) and the toy should activate. It should also slow down bit by bit.
  • Stop the script by pressing the "Stop"-Button
  • Note how the current toy level will not decrease and the PushButton has no effect anymore. They are still connected but the script is stopped.
Step 4: Messle with the script
The best way to see how something works is by meddling with it (in my experience). Depending on your programming background and experience, the job/trigger/actions-concept may seem a bit complicated at first - so instead of starting with your own script, you may want to experiment with an existing one.

Of course, you might also just want to jump to the action. In that case, just skip these steps
  • Click the "Dilemma"-widget and select "Edit". There will be some tabs: "General", "Controls", "Actions", "Triggers" and "Jobs"
  • The "General"-Tab contains the name and a short description of the script. You also set the blocks the script "wants to have/needs to be connected to" in order to work.
  • You might want to rename the script to "Reverse Dilemma" and delete the destripcion. This is just for display in the interface and helps not to get lost once there are more scripts on the dashboard.
  • The "Controls"-Tab allows to add controls to the script. You might want to enter values or control some detail with a slider. This is not required at the moment.
  • The "Start/Stop Actions" tab defines actions which are run when the script is started and when it is ended
  • For example: It might be a good idea to complete stop the toy if the script is stopped. Let's to that!
  • Use "Add action" under "Final Actions". You want to update a "Block" - you "Generic Output" and set it to intensity 0. Click Add.
01_powerdown_action.PNG
  • This Action should then show up unter "Final Actions". You can also see that there is an initial action starting the Job "down". We will talk about that, later
02_finalaction.PNG
  • Start the script again (Press Play), set some intensity (via button or the slider on the toy) and then stop the script. The toy should instantly power down, completely.

  • Next, lets take a look at the global trigger (click on the script and choose edit, then the "Triggers"-tab)
03_trigger_up.PNG
  • If you click on the red "Generic Output +5%"-part, that Update-action should look famliar. This is almost the same as the reset-action we defined a moment before.
04_trigger_up_detail.PNG
  • It seems like this part is responsible for increasing the intensity by 5% when "something happens". It is interesting and useful that you use relative values instead of absolute ones, here.
  • If you click on the "Button"-part, you can see the "something" that triggers the action:
05_trigger_up_trigger.PNG
  • It is triggered, when the "Push Button" is set to "down" (a.k.a. pressed). This was to be expected. Note that you could also select "Generic Output" here and use it as a trigger. You could trigger other actions once intensity reaches a certain treshold.
  • You could also add more buttons (and their triggers) to the mix for additional changes. And - of course - you could connect more than one toy. XToys is very flexible on that front.
  • For now, I'd like the button to reset intensity to zero - so change the update Action from "+5" to "0". At first, this seems rather useless: The Button resets to Zero; ScriptStopping resets to zero and the timer never increases intensity. Let's change that last one.
  • The timer is under "jobs".
06_jobs.PNG
  • At the moment, there is a single job "Down" here. You can add remove and rename jobs by clicking on the "Jobs"-Button. For now, rename the job to "Up".
  • You can see a familiar Output-change under "Actions" - only this time is is a relative decrease. Switch it to "+5%" for this experiment.
  • Note how the action is in a "Step" called "Start" This means that the intensity change is done whenever the job reaches the step "Start".
  • On the right side, you can see a trigger in this step: When five seconds have passed, the trigger will go to step "Start" (thus changing the intensity) and it will also set itself up to run again. As we changed the name of the job, the new job has to be selected here.
  • So.. what runs the job (and stats the trigger) in the beginning? This was the "Start action" from before. You might have to re-add this action or just change the jobname as we changed it.
07_startJob.PNG

If you save andf start the script now, you should see that the behaviour has somewhat changed: It will now atomatically increase intensity every few second and the button will act as a reset-button. You could use this for some "dare"-games: Connect several toys and whoever reaches for the emergency-off-button first, loses.

(Post split because of image limit)
 
Step 5: Connect a video game
Now that we have seen how a toy can be controlled via scripting, you can imagine that it should be easy to connect such a script to a game running on the computer. We still need a bit of preparation:

Before this, we used a simple "Push Button" as input. In order to observe the memoty values in which the game stores data, we need the tool "XToys Process Monitor". In order to use this, we also need a Chrome Browser plugin (this can also be used to observe web pages and react to changes - but that's another topic) and an installed bridging software. Once you added the process monitor to the dashboard, it will provide links to those when trying to start.
This also was a point of much frustration: The process-monitor-widget only recognized the installed XToys-utilities after several tries.

In order to provide the monitor with the correct memory addresses, you need a way to search for the values. This is where all the CheatEngine-experience comes in handy.

  • Start up the game; start up CheatEngince and find the address that should be used as an input the toy. If you are unfamiliar wth CheatEngine, find a good tutorial as including one here would break sope.
  • 08_finding_address.PNG
  • Now, create a completely new script ("Add a Block", "Scripts", "Plus-Sign")
  • Edit it; you should be on the "General"-tab. Give the script a name. Now create the "Blocks interacted with": We need a "Generic Output" for the toy and the "XToys Process Monitor" for the memory-observer. This also needs the game's filename.
  • 09_linking_to_game.PNG
  • Supplying the observer with the memory address is done as a Start/Initial Action. You also give it an identifies and the variable type. There are some ways to deal with offsets and such - but let's keeep it simple at the moment (you may need to search/supply new addresses in different sessions or even levels).
  • 10_linking_to_memory.PNG
  • Check that the script can "see" the variable in the game. Don't forget to plug the process monitor and the toy into the script (using the plug symbol); start the process monitor (you will have to give it access like when you start CheatEngine); start the script; the Process Monitor should now report that it is monitoring the game and capturing the value
  • 11_successful_capture.PNG
  • Next, we want to do something with that value. Stop the script; edit it; add a trigger, using the identifier as input:
  • 12_react_to_value_change.PNG
  • The output of that trigger can be directly put onto the toy intensity (both are between 0 and 100). Note that the name "libido" is an "identifier" in the ProcessMonitor and does not exist as a "variable" outside of it. You need to access it as "{trigger}" in the following steps
  • 13_putTriggerValue.PNG
  • Start the script. The toy should immediately adjust intensity to the current libido value from the game and change with it:
  • 14_everythingLinked.PNG
Obviously, matching one percentage to another one is not exactly "high math". Maybe it would be better to use a combination of values (defense, health, libido) to show how dire the current situation is.
Still, this is a nice proof of concept. You really feel the "woozy" of some attacks and the calming effect of the anaphodisiac.

(Post split because of image limit)
 
Step 6: Small calculations / direness
As you can imagine, you can add more mathematics to the script for more complex operations. I remember that some RPGs store their variables as "real value times two plus one" and you might want to calculate the real values from there. I'll demonstrate a bit of math with the "direness"-concept: Your starting pistol has 12 shots before you need to recharge. The less shots you have left, the more "dire" the situation is.
  • Lets use this example to introduce an input box to our script-widget. Add it on the "Controls" tab and name the variable "{maxammo}"
  • Find the memory address for ammunition and add a "memory access init step" for it (just like you did with libido, before"
  • Put the calculations into some jobs action:
  • 15_calculationJob.PNG
  • The first two are simple Update-Variable-Value-calculations: Empty is how many shots have been fires since "maxammo" (the input box). Direness then scales the value into a percentage
  • The third action is a script (with Action "Set Status Text") to show calculated values. This can be used as debug-output (though only one text can be displayed at the same time - per script widget)
  • The final step is a typical and well-known "set intensity to a variable"; this time, it is not zero or a relative increase or decrease or the trigger - it is a calculated value stored in a variable.
  • Finally: This Job has to run (think of it like a method or function) for changing ammo-values. This means "Global Trigger". Again: Remember that the identifier "ammo" only exists in the Process Monitor and we have to assign its "{trigger}" into an "{ammo}"-variable to use it in the job.
  • 16_runjobOnValues.PNG
Start the script again; the intensity should now change with every shot fired and every reload:
17_direness_linked.PNG

Step 7: Event-driven
Previously, we directly linked one value in the game to the intensity of a toy - maybe with some calculations inbetween, but still via direct link. This is nice to convery some "situation" via haptic feedback (Just as a sidenote: Those direct links might be useful with the movement speed of your phone, distance to bluetooth beacons or something with GPS-coordinated. Of course, XToys supports all of those).
I went through my game library and it seems like not many games offer memory addresses that are very suitable for linking. Also, you might simply enjoy a more event-driven-approach, more. The main idea is: You detect an event in the game by watching an ddress; you also define a "reaction" for that event. This way, the toy intensity is no longer directly linked. We can even use Captivity as an example, again: The pink bar increases if the protagonist is grabbed - so we might react to getting grabbed with a "punishment".

Lets also use this to have two scripts running at the same time. One will be responsible for rising the intensity on the given events; the other will be responsible for "calming" the toy in between. This might sound familiar: It is just the basic "Dilemma" but split into two scripts and using process-watched events instead of a single PushButton. One reason for splitting the scripts is that the "calming"-script can be used for different games (or even without any game) and the game-specific script will only contain code relevant to that one.
  • To build the calming-script, add a new script (Plus-Sign, "Scripts", none of the already-listed); define a job that decreases the output (as action) and calls itself after a timed trigger. You might even want to use the calming value and the frequency as inputs (screenshots did not)
  • 18_calming_job.PNG
  • Don't forget to start that job once as an Initial Action in the Start/Stop-Actions-tab
  • Start that script and increase the intensity via the toy control field. It should gradually fall back to zero intensity.
  • Find the memory-address of the game's pink bar with CheatEngine (or any other tool that helps finding memory addresses).
  • Add the script for Increasing intensity. I called it "captivity-pink".
  • Add required blocks to the script ("Generic output" for the toy, "XToys Process Monitor" for the game - same as with the libido-example)
  • Again, add an observer for this memory address (Initial Actions, Block, Process Monitor, Float, Static Address).
  • At that point, you can already check whether observing the memory value works: Save the Script; Start the Process Monitor; Start the Script; Allow access to memory - and the observed value should be displayed in the process monitor. Stop the script again.
  • For some safety, add the usual "Final Action" - "Set intensity to zero"
  • You also need to initialize another variable in the "Start Action"-part. Let's call it "old-pink" and set it to zero on start:
  • 19_pink-init.PNG
  • We should pass the observerd value to a job. Like before, we add a global trigger ("When" "Block", "Process Minitor", "pink", "Any") which feeds the "trigger"-value back into a variable "pink" and then calls a job (you might to rename this job - or keep the "Main" name)
  • 20_pink_trigger.PNG
  • Than head to the Jobs-tab
  • We sometimes need to update "old-pink" to the current-value. So add a second step to the main job (maybe call it "Update") that simply sets "old-pink" to "pink".
  • If the value decreased from the previous value, we may want to not react - but still need to update the "old-pink"-value. So add a trigger (expression) "{pink} < {old-pink}" and make it "go to step" "Update"
  • 21_jump_to_update_on_down.PNG
  • The other case is more interesting: We still want to "go to step" "update" in the end - but before, we want to update the intensity of our toy:
  • 22_update_on_up.PNG
  • I decided to only increase intensity by the amount the pink bar increases (the "+1" was purged, later). That way we prevent lots of small changes to suddenly increase the intensity more than a single large change would have done. This also means that keeping the libido down (in-game) still us useful as it influences the speed in which the pink bar increases.
  • Save; Start the script. Now intensity should increase when the pink ba fills - but not be directly linked. You can still manipulate the toy widget directly - and the "calm"-script should always reduce intensity after some time.
Please note that the XToys-tutorial for the process monitor does a similar thing and increases intensity if the health in an emulated SNES-game decreases. I think that this tutorial overcomplicates things by including an offset - but the screenshots may be more informative.
You might wonder why we even need to store "old-pink" to recognize a change. That is because I lied (or didn't know any better), before. It seems like the ProcessMonitor-trigger does not trigger on a changed value but instead triggers all the time - so we need to store an old value to compare it to the current one.

Conclusion
This is the end of my tutorial. I hope it was useful and "brings you joy" and you have fun in trying things out.

Obviously, things aren't perfect. This is not a Go-To-Solution for everything:
  • It seems as if some games cannot be monitored easily due to non-ascii-exe-names. This is sad as quite some games featured in this forum are japanese and their main executables consist of japanese characters.
  • Some games often swap their addresses around. Some room-base-games change locations on every room; some switch between stages. In Captivity, you have to search for the new memory locations after every gameover. Maybe "getting better aat Chear Engine" and learning more about offsets would help.
  • XToys itself is one of those apps which seem "the best in their domain" - and miles ahead of the toy-manufacturer-supplied apps - but without "best" meaning "really good". I ofen have problems with the connections; the mobile app crashes a lot; sometimes reactions are delayed (changing patterns?); sometimes scriptes cannot be edited/saced any more (which is frustrating if you invested some work - but another reason to split functionality into different scripts) although they worked perfectly fine just a moment before (does XToys consider them "tainted" at some point?). Overall, it feels like it is still in beta-phase.
  • On the other hand: It is free to use; an account only is needed if you want to save your setup and script; a paid account is only needed if you want premium features - there is a saying about "gift horses".
  • Everything is hosted on their servers. I wish I could use this on a local webserver or even something self-/cloud-hosted in case the official server disappears.
  • I'm also not sure about those block-oriented-programming-languages but I understand that they help getting started. Not everyone wants to get a computer-sciency-degree just to code for some toys.
  • I wouldn't know how to tackle the really natural connection (REZ on PS2-emulator) and there is no public script for it, yet.
So.. have fun!

(end of segmented post)
 
Back
Top