Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Periodic execution decorator appears broken #239

Open
WhiteMagic opened this issue Sep 11, 2019 · 3 comments
Open

Periodic execution decorator appears broken #239

WhiteMagic opened this issue Sep 11, 2019 · 3 comments
Assignees
Labels
bug Issue is related to a bug. medium-work Amount of work required for this task.
Milestone

Comments

@WhiteMagic
Copy link
Owner

A simple periodic callback function seems to be broken due to some issues with comparison operator for partial functions not existing. A simple example that breaks is the following:

@gremlin.input_devices.periodic(0.1)
def periodic():
    print("Here")
@WhiteMagic WhiteMagic self-assigned this Sep 11, 2019
@WhiteMagic WhiteMagic added bug Issue is related to a bug. medium-work Amount of work required for this task. labels Sep 11, 2019
@Shfty
Copy link

Shfty commented Dec 19, 2019

Are periodic functions broken at large in the current release?

I'm seeing invocations, and the input viewer updates, but execution seems to stop unexpectedly during in-game use.

Minimal code:

import gremlin
from gremlin.user_plugin import *

import random

vjoy_axis = VirtualInputVariable(
        "Output Axis",
        "vJoy axis to use as the output",
        [gremlin.common.InputType.JoystickAxis]
)

@gremlin.input_devices.periodic(0.001)
def periodic_function(vjoy):
        device_id = vjoy_axis.value["device_id"]
        input_id = vjoy_axis.value["input_id"]

        value = float(random.randint(-1, 1)) * 0.001

        vjoy[device_id].axis(input_id).value = value

In addition, the vjoy device doesn't seem to be available consistently. It might be unavailable (and thus throw an error) on any given frame. I've tried to work around this with try/except blocks, as well as checking for the presence of a given device using if device_id in vjoy but that throws an error regardless.

Currently I'm using timers from python's threading model to sidestep the periodic decorator completely, but it's a messy hack that doesn't respect joystick gremlin's script lifecycle:

import gremlin
from gremlin.user_plugin import *

import random
from threading import Timer

mode = ModeVariable(
        "Mode",
        "The mode to use for this mapping"
)
vjoy_axis = VirtualInputVariable(
        "Output Axis",
        "vJoy axis to use as the output",
        [gremlin.common.InputType.JoystickAxis]
)
left_axis = PhysicalInputVariable(
        "Turn Left",
        "Left turn axis.",
        [gremlin.common.InputType.JoystickAxis]
)
right_axis = PhysicalInputVariable(
        "Turn Right",
        "Right turn axis.",
        [gremlin.common.InputType.JoystickAxis]
)


left_decorator = left_axis.create_decorator(mode.value)
right_decorator = right_axis.create_decorator(mode.value)


vj = None
state = [0.0, 0.0]


@left_decorator.axis(left_axis.input_id)
def left_axis_event(event, vjoy):
    global vj
    global state
    vj = vjoy
    state[0] = event.value


@right_decorator.axis(right_axis.input_id)
def right_axis_event(event, vjoy):
    global vj
    global state
    vj = vjoy
    state[1] = event.value

def update_axes():
    global vj
    if vj:
        global state
        value = (state[0] - state[1]) * 0.5
        value = min(max(value, -1.0), 1.0)

        if value == 0.0:
            value = float(random.randint(-1, 1)) * 0.001
        
        device_id = vjoy_axis.value["device_id"]
        input_id = vjoy_axis.value["input_id"]

        vj[device_id].axis(input_id).value = value

    r = Timer(0.01, update_axes)
    r.start()

r = Timer(0.01, update_axes)
r.start()

The use-case here is getting around MechWarrior 5's buggy turn handling. The turn axis doesn't zero out properly, instead holding at the last non-zero value received until another change is detected.
Thus, it's necessary to introduce a very small amount of noise in order to force the axis to constantly update to a small enough value that it appears to rest at zero, rather than constantly turning and interfering with the player's aim.

I also want to use periodic invocation to implement finer axis-to-mouse mapping, as the current implementation doesn't appear to respect response curves or have a configurable tick rate, though there doesn't seem to be an exposed way to control the mouse from user scripts? Unless it's exposed via keyboard and I've missed it.

@WhiteMagic
Copy link
Owner Author

Yeah, the entire decorator is broken. I did look into it for a decent amount of time but couldn't figure out what went wrong with it. I haven't looked at it again since I added this issue, mainly because I didn't get a lot of time to work on Gremlin lately. Though with the sweeping changes that I have to do behind the scenes I will end up looking at this again.

The mouse interfacing used by Gremlin is accessible by user scripts. Everything Gremlin uses is defined in https://github.com/WhiteMagic/JoystickGremlin/blob/develop/gremlin/sendinput.py There is a decent amount of sorcery going on in some of the more complex mouse motion behaviours though.

Somewhere I should have an issue that calls for other types of events that can be hooked, such as enabling a profile, swapping modes, etc. If those did already exist, which they sadly don't, then those would have been a good way to work around the broken periodic decorator.

@WhiteMagic
Copy link
Owner Author

Apparently the decorator does not work when a profile is initially activated, but on subsequent activations of profiles, it seems to do its job, see #272. This means that there is likely some setup code missing which the code activating and deactivating a profile resets to the correct state.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Issue is related to a bug. medium-work Amount of work required for this task.
Projects
Status: Todo
Development

No branches or pull requests

2 participants