Starting a local headless client - glitchfur/NeosVR-Headless-API GitHub Wiki

Make sure your shell is in the correct directory and that your virtual environment is active (source venv/bin/activate if you haven't done it already), then import LocalHeadlessClient.

from neosvr_headless_api import LocalHeadlessClient

You can create a new headless client by calling LocalHeadlessClient with the path to your headless client, meaning the folder that Neos.exe is in:

hc = LocalHeadlessClient(
    "/home/glitch/.local/share/Steam/steamapps/common/NeosVR/"
)
hc.wait_for_ready()

Creating this object will immediately launch the headless client in the background. Adjust the path above to point to where your headless client is located. Neos will use the default configuration file relative to itself at Config/Config.json if one is not specified. You can provide the path to a different configuration file using the config keyword argument:

hc = LocalHeadlessClient("...", config="/path/to/config.json")

The .wait_for_ready() method will block until the headless client has finished starting up. This ensures that we don't try to run any commands until the headless client is ready, otherwise they will throw an exception. In code, you should always call this function and wait for it to return immediately after starting the headless client to ensure you don't run any commands too early.

Interacting with the headless client

At this point the headless client is fully started and we can call some methods. Lets try .status().

In [1]: hc.status()
Out[1]: 
{'name': "Glitch's World",
 'session_id': 'S-1462cabf-9ac4-46b7-80b4-3921455093e1',
 'current_users': 1,
 'present_users': 0,
 'max_users': 8,
 'uptime': '00:00:18.9775300',
 'access_level': 'Anyone',
 'hidden_from_listing': False,
 'mobile_friendly': False,
 'description': 'This is where a cat knocks a bunch of stuff over.',
 'tags': ["computer", "cat", "code", "coffee", "chaos"],
 'users': ['GlitchHost']}

This will execute the status command in the headless client. Almost all of the commands that you can execute in the headless client are available as methods, such as .worlds() or .users(). For commands that contain multiple words, the words are separated with underscores instead of being camel case. For example: The method for the command hideFromListing is actually .hide_from_listing().

You'll also notice that this isn't traditional headless client output. This is actually a dict, with each line of information being its own key. Numbers like max_users are automatically converted to int. NeosVR-Headless-API does the heavy lifting for you of parsing command output and turning it into the appropriate Python data types. It will also make a best effort at handling sessions with complex data such as multi-line world names and descriptions. This means developers can get straight to coding without having to deal with substrings, splits, and regex to work with the data.

Each command has a different return type, so check the documentation to see what methods are available.

If you'd like to know how to control headless clients remotely, head over to Starting a remote headless client.

Examples

These examples don't have any logical rhyme or reason, they just show how to use the library.

Silence all unsilenced users in a session, and vice versa

hc = LocalHeadlessClient(...)
hc.wait_for_ready()

for user in hc.users()[1:]:  # The [1:] skips the headless user
    if user["silenced"]:
        hc.unsilence(user["name"])
    else:
        hc.silence(user["name"])

These examples assume the host user is friends with all users in the session.

Invite everyone in one session to a new session

old_world_users = hc.users()[1:]
hc.focus(1)

for user in old_world_users:
    hc.invite(user["name"])

Send a message to all users in all sessions, wait, then shut down

from time import sleep

# Keep track of the world we're currently in
start_world = hc.status()["session_id"]

for index, world in enumerate(hc.worlds()):
    hc.focus(index)
    for user in hc.users()[1:]:
        hc.message(
            user["name"], 
            "Heads up! The headless is going down in 60 seconds."
        )

# Switch back to where we were before
hc.focus(start_world)

sleep(60)
hc.shutdown()
⚠️ **GitHub.com Fallback** ⚠️