mirror of
https://github.com/EyeTrackVR/EyeTrackVR.git
synced 2025-09-26 23:09:28 +08:00

* initial changes * Mostly clean up, refactor registering listeners to make sense, backport tests * Add initial implementation of VRCFTModuleSender * Add basic GUI for the modules settings * Fix tooltip descriptions # TODO: # - there's ghosts in the machine - vrc osc is not working properly # - min/maxing will require field combinators in the modules lmao * Fix type validation bugs, fix typos # TODO: # - there's ghosts in the machine - vrc osc is not working properly # - min/maxing will require field combinators in the modules lmao * Add checkbox to switch to ETVR Module # TODO: # - there's ghosts in the machine - vrc osc is not working properly # - min/maxing will require field combinators in the modules lmao * Black stuff # TODO: # - there's ghosts in the machine - vrc osc is not working properly # - min/maxing will require field combinators in the modules lmao * Remove coverage by default # TODO: # - there's ghosts in the machine - vrc osc is not working properly # - min/maxing will require field combinators in the modules lmao * Fix timeout in tests # TODO: # - there's ghosts in the machine - vrc osc is not working properly # - min/maxing will require field combinators in the modules lmao * HEAVY WIP: Refactor native output, NOTE: I brought back the entire old OSC implementation as a live reference, this will be removed once I'm done. This also lays ground for other modes as they're pretty similar # TODO: # - there's ghosts in the machine - vrc osc is not working properly # - min/maxing will require field combinators in the modules lmao * HEAVY WIP: Refactor v1 params output, # TODO: # - min/maxing will require field combinators in the modules lmao * HEAVY WIP: Refactor v2 params output # TODO: # - min/maxing will require field combinators in the modules lmao * Finish refactoring v2 and v1, fixup tests, refactor native # TODO: # - min/maxing will require field combinators in the modules lmao * Add tests for v1 params # TODO: # - min/maxing will require field combinators in the modules lmao * Add tests for native params # TODO: # - min/maxing will require field combinators in the modules lmao * Fix OSC not getting up after config reset. Remove reset command, config sends everything changed anyway, sunset the idea of using single client and thus simplify the code a bit # TODO: # - min/maxing will require field combinators in the modules lmao * Rename gui_PortNumber to gui_VRCFTModulePort for readability # TODO: # - min/maxing will require field combinators in the modules lmao * Cleanup EyeID usage # TODO: # - min/maxing will require field combinators in the modules lmao * Cleanup osc after rebase # TODO: # - min/maxing will require field combinators in the modules lmao * Make VRChatOSCSender a bit more readable # TODO: # - min/maxing will require field combinators in the modules lmao * Remove unsued VRChatOSCReceiver, this is taken care of by generic OSCReceiver # TODO: # - min/maxing will require field combinators in the modules lmao * Commit crimes with try_convert_to_float to make osc, pysimplegui and pydantic happy * Cleanup after merge * Disable emulation by default * Fix OSCReceiver crashing on unknown addresses * Adjust VRCFT Module settings to look better in game * Fix recalibrate and recenter for OSC only working for the right eye * Fix save and restart button not restarting the tracking * Fix broken tracking on v1 params for eye_x, clean up implementation * Fix regular value being passed to OSC listeners instead of OSCMessage * Add a TODO, probably to be ignored * Add support for custom ETVR VRCFT Module listening address
275 lines
9.5 KiB
Python
275 lines
9.5 KiB
Python
from queue import Queue
|
|
from time import sleep
|
|
from unittest import mock
|
|
|
|
import pytest
|
|
|
|
from osc.osc import OSCManager, OSCMessage
|
|
from osc.OSCMessage import OSCMessageType
|
|
from tests import EyeInfoMock, SimpleUDPClientMock
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"messages,expected_outcome",
|
|
[
|
|
(
|
|
[
|
|
OSCMessage(
|
|
type=OSCMessageType.EYE_INFO,
|
|
data=(
|
|
0,
|
|
EyeInfoMock(
|
|
x=0,
|
|
y=0,
|
|
blink=1,
|
|
pupil_dilation=0,
|
|
avg_velocity=0,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
[
|
|
("/avatar/parameters/LeftEyeX", 0),
|
|
("/avatar/parameters/RightEyeX", 0),
|
|
("/avatar/parameters/EyesY", 0),
|
|
("/avatar/parameters/LeftEyeLidExpandedSqueeze", 1.0),
|
|
("/avatar/parameters/RightEyeLidExpandedSqueeze", 1.0),
|
|
],
|
|
),
|
|
(
|
|
[
|
|
OSCMessage(
|
|
type=OSCMessageType.EYE_INFO,
|
|
data=(
|
|
1,
|
|
EyeInfoMock(
|
|
x=0,
|
|
y=0,
|
|
blink=1,
|
|
pupil_dilation=0,
|
|
avg_velocity=0,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
[
|
|
("/avatar/parameters/LeftEyeX", 0),
|
|
("/avatar/parameters/RightEyeX", 0),
|
|
("/avatar/parameters/EyesY", 0),
|
|
("/avatar/parameters/LeftEyeLidExpandedSqueeze", 1.0),
|
|
("/avatar/parameters/RightEyeLidExpandedSqueeze", 1.0),
|
|
],
|
|
),
|
|
],
|
|
)
|
|
def test_send_command_v1_params_single_eye(main_config_v1_params, messages, expected_outcome):
|
|
with mock.patch("EyeTrackApp.osc.osc.udp_client.SimpleUDPClient", SimpleUDPClientMock):
|
|
msg_queue = Queue()
|
|
client = OSCManager(
|
|
config=main_config_v1_params,
|
|
osc_message_in_queue=msg_queue,
|
|
)
|
|
|
|
client.start()
|
|
|
|
for message in messages:
|
|
sleep(0.01)
|
|
msg_queue.put(message)
|
|
client.shutdown()
|
|
|
|
assert msg_queue.empty()
|
|
assert client.osc_sender.client.messages == expected_outcome
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"eye_data,expected_outcome",
|
|
[
|
|
(
|
|
[
|
|
OSCMessage(
|
|
type=OSCMessageType.EYE_INFO,
|
|
data=(
|
|
0,
|
|
EyeInfoMock(
|
|
x=0,
|
|
y=0,
|
|
blink=1,
|
|
pupil_dilation=1,
|
|
avg_velocity=0,
|
|
),
|
|
),
|
|
),
|
|
OSCMessage(
|
|
type=OSCMessageType.EYE_INFO,
|
|
data=(
|
|
1,
|
|
EyeInfoMock(
|
|
x=10,
|
|
y=5,
|
|
blink=0.5,
|
|
pupil_dilation=1,
|
|
avg_velocity=0,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
[
|
|
("/avatar/parameters/RightEyeLidExpandedSqueeze", 1.0),
|
|
("/avatar/parameters/RightEyeX", 0),
|
|
("/avatar/parameters/RightEyeLidExpandedSqueeze", 1.0),
|
|
("/avatar/parameters/LeftEyeLidExpandedSqueeze", 0.5),
|
|
("/avatar/parameters/LeftEyeX", 0),
|
|
("/avatar/parameters/LeftEyeLidExpandedSqueeze", 0.5),
|
|
("/avatar/parameters/EyesY", 2.5),
|
|
],
|
|
),
|
|
# binary blink
|
|
(
|
|
[
|
|
OSCMessage(
|
|
type=OSCMessageType.EYE_INFO,
|
|
data=(
|
|
0,
|
|
EyeInfoMock(
|
|
x=0,
|
|
y=0,
|
|
blink=0,
|
|
pupil_dilation=1,
|
|
avg_velocity=0,
|
|
),
|
|
),
|
|
),
|
|
OSCMessage(
|
|
type=OSCMessageType.EYE_INFO,
|
|
data=(
|
|
1,
|
|
EyeInfoMock(
|
|
x=10,
|
|
y=5,
|
|
blink=0,
|
|
pupil_dilation=1,
|
|
avg_velocity=0,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
[
|
|
("/avatar/parameters/RightEyeLidExpandedSqueeze", 0.0),
|
|
("/avatar/parameters/RightEyeLidExpandedSqueeze", 0.0),
|
|
("/avatar/parameters/RightEyeLidExpandedSqueeze", 0.0),
|
|
("/avatar/parameters/RightEyeLidExpandedSqueeze", 0.0),
|
|
("/avatar/parameters/RightEyeLidExpandedSqueeze", 0.0),
|
|
("/avatar/parameters/RightEyeLidExpandedSqueeze", 0.0),
|
|
("/avatar/parameters/RightEyeX", 0),
|
|
("/avatar/parameters/RightEyeLidExpandedSqueeze", 0.0),
|
|
("/avatar/parameters/LeftEyeLidExpandedSqueeze", 0.0),
|
|
("/avatar/parameters/LeftEyeLidExpandedSqueeze", 0.0),
|
|
("/avatar/parameters/LeftEyeLidExpandedSqueeze", 0.0),
|
|
("/avatar/parameters/LeftEyeLidExpandedSqueeze", 0.0),
|
|
("/avatar/parameters/LeftEyeLidExpandedSqueeze", 0.0),
|
|
("/avatar/parameters/LeftEyeLidExpandedSqueeze", 0.0),
|
|
("/avatar/parameters/LeftEyeX", 0),
|
|
("/avatar/parameters/LeftEyeLidExpandedSqueeze", 0.0),
|
|
("/avatar/parameters/EyesY", 2.5),
|
|
],
|
|
),
|
|
],
|
|
)
|
|
def test_send_command_v1_params_dual_eye(main_config_v1_params, eye_data, expected_outcome):
|
|
main_config_v1_params.eye_display_id = 2
|
|
|
|
with mock.patch("EyeTrackApp.osc.osc.udp_client.SimpleUDPClient", SimpleUDPClientMock):
|
|
msg_queue = Queue()
|
|
client = OSCManager(
|
|
config=main_config_v1_params,
|
|
osc_message_in_queue=msg_queue,
|
|
)
|
|
|
|
client.start()
|
|
|
|
for message in eye_data:
|
|
sleep(0.01)
|
|
msg_queue.put(message)
|
|
client.shutdown()
|
|
|
|
assert msg_queue.empty()
|
|
assert client.osc_sender.client.messages == expected_outcome
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"eye_data,expected_outcome",
|
|
[
|
|
(
|
|
[
|
|
OSCMessage(
|
|
type=OSCMessageType.EYE_INFO,
|
|
data=(
|
|
0,
|
|
EyeInfoMock(
|
|
x=0,
|
|
y=0,
|
|
blink=0,
|
|
pupil_dilation=1,
|
|
avg_velocity=0,
|
|
),
|
|
),
|
|
),
|
|
OSCMessage(
|
|
type=OSCMessageType.EYE_INFO,
|
|
data=(
|
|
1,
|
|
EyeInfoMock(
|
|
x=10,
|
|
y=5,
|
|
blink=0,
|
|
pupil_dilation=1,
|
|
avg_velocity=0,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
[
|
|
("/avatar/parameters/RightEyeLidExpandedSqueeze", 0.0),
|
|
("/avatar/parameters/RightEyeLidExpandedSqueeze", 0.0),
|
|
("/avatar/parameters/RightEyeLidExpandedSqueeze", 0.0),
|
|
("/avatar/parameters/RightEyeLidExpandedSqueeze", 0.0),
|
|
("/avatar/parameters/RightEyeLidExpandedSqueeze", 0.0),
|
|
("/avatar/parameters/RightEyeLidExpandedSqueeze", 0.0),
|
|
("/avatar/parameters/RightEyeX", 0),
|
|
("/avatar/parameters/RightEyeLidExpandedSqueeze", 0.0),
|
|
("/avatar/parameters/LeftEyeLidExpandedSqueeze", 0.0),
|
|
("/avatar/parameters/LeftEyeLidExpandedSqueeze", 0.0),
|
|
("/avatar/parameters/LeftEyeLidExpandedSqueeze", 0.0),
|
|
("/avatar/parameters/LeftEyeLidExpandedSqueeze", 0.0),
|
|
("/avatar/parameters/LeftEyeLidExpandedSqueeze", 0.0),
|
|
("/avatar/parameters/LeftEyeLidExpandedSqueeze", 0.0),
|
|
("/avatar/parameters/RightEyeLidExpandedSqueeze", 0.0),
|
|
("/avatar/parameters/LeftEyeLidExpandedSqueeze", 0.0),
|
|
("/avatar/parameters/LeftEyeX", 0),
|
|
("/avatar/parameters/LeftEyeLidExpandedSqueeze", 0.0),
|
|
("/avatar/parameters/EyesY", 2.5),
|
|
],
|
|
),
|
|
],
|
|
)
|
|
def test_send_command_v1_params_eye_outer_side_falloff(main_config_v1_params, eye_data, expected_outcome):
|
|
main_config_v1_params.eye_display_id = 2
|
|
main_config_v1_params.settings.gui_outer_side_falloff = True
|
|
|
|
with mock.patch("EyeTrackApp.osc.osc.udp_client.SimpleUDPClient", SimpleUDPClientMock):
|
|
msg_queue = Queue()
|
|
client = OSCManager(
|
|
config=main_config_v1_params,
|
|
osc_message_in_queue=msg_queue,
|
|
)
|
|
|
|
client.start()
|
|
|
|
for message in eye_data:
|
|
msg_queue.put(message)
|
|
sleep(1)
|
|
client.shutdown()
|
|
|
|
assert msg_queue.empty()
|
|
assert client.osc_sender.client.messages == expected_outcome
|