2025-12-01
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
|
||||
import bpy
|
||||
import time
|
||||
import socket
|
||||
import traceback
|
||||
from . import animations, utils
|
||||
|
||||
error_temp = ''
|
||||
show_error = []
|
||||
|
||||
|
||||
# Starts UPD server and handles data received from Rokoko Studio
|
||||
class Receiver:
|
||||
|
||||
sock = None
|
||||
|
||||
# Redraw counters
|
||||
i = -1 # Number of continuous received packets
|
||||
i_np = 0 # Number of continuous no packets
|
||||
|
||||
# Error counters
|
||||
error_temp = []
|
||||
error_count = 0
|
||||
|
||||
def run(self):
|
||||
data_raw = None
|
||||
received = True
|
||||
error = []
|
||||
force_error = False
|
||||
|
||||
# Try to receive a packet
|
||||
try:
|
||||
data_raw, address = self.sock.recvfrom(81920) # Prev 65536
|
||||
except BlockingIOError as e:
|
||||
print('Blocking error:', e)
|
||||
error = ['Receiving no data!']
|
||||
except OSError as e:
|
||||
print('Packet error:', e.strerror)
|
||||
error = ['Packets too big!']
|
||||
force_error = True
|
||||
except AttributeError as e:
|
||||
print('Socket error:', e)
|
||||
error = ['Socket not running!']
|
||||
force_error = True
|
||||
|
||||
# start_time = time.time()
|
||||
|
||||
# Process the packet
|
||||
if data_raw:
|
||||
# print('SIZE:', len(data_raw))
|
||||
# print('DATA:', data_raw)
|
||||
|
||||
# Process animation data
|
||||
error, force_error = self.process_data(data_raw)
|
||||
|
||||
# print(round((time.time() - start_time) * 1000, 4), 'ms')
|
||||
|
||||
self.handle_ui_updates(received)
|
||||
self.handle_error(error, force_error)
|
||||
|
||||
def process_data(self, data_raw) -> ([str], bool):
|
||||
"""
|
||||
Processes the received data. If there was an error it returns a list of strings creating the error message
|
||||
and if the error should be forced to show immediately instead of after a couple of packages
|
||||
:param data_raw:
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
animations.live_data.init(data_raw)
|
||||
except ValueError as e:
|
||||
print('Packet contained no data')
|
||||
print(e)
|
||||
return ['Packets contain no data!'], False
|
||||
except (UnicodeDecodeError, TypeError) as e:
|
||||
print('Wrong live data format! Use JSON v2 or higher!')
|
||||
print(e)
|
||||
print(traceback.format_exc())
|
||||
return ['Wrong data format!', 'Use JSON v2 or higher!'], True
|
||||
except KeyError as e:
|
||||
print('KeyError:', e)
|
||||
return ['Incompatible JSON version!', 'Use the latest Studio', 'and plugin versions.'], True
|
||||
except ImportError as e:
|
||||
# This error occurs specifically when LZ4 isn't supported by the operating system
|
||||
if "os" in e.msg:
|
||||
print('LZ4 unsupported by OS!', 'Use "Json" in the', 'Custom panel in Studio.')
|
||||
return ['LZ4 unsupported by OS!', 'Use "Json" in the', 'Custom panel in Studio.'], True
|
||||
|
||||
# This error occurs, when the LZ4 package could not be loaded while it was needed
|
||||
print('LZ4 unsupported by OS or', 'Blender! Use "Json" in the', 'Custom panel in Studio.')
|
||||
return ['LZ4 unsupported by OS or', 'Blender! Use "Json" in the', 'Custom panel in Studio.'], True
|
||||
|
||||
animations.animate()
|
||||
|
||||
return None, False
|
||||
|
||||
def handle_ui_updates(self, received):
|
||||
# Update UI every 5 seconds when packets are received continuously
|
||||
if received:
|
||||
self.i += 1
|
||||
self.i_np = 0
|
||||
if self.i % (bpy.context.scene.rsl_receiver_fps * 5) == 0:
|
||||
utils.ui_refresh_properties()
|
||||
utils.ui_refresh_view_3d()
|
||||
return
|
||||
|
||||
# If receiving a packet after one second of no packets, update UI with next packet
|
||||
self.i_np += 1
|
||||
if self.i_np == bpy.context.scene.rsl_receiver_fps:
|
||||
self.i = -1
|
||||
|
||||
def handle_error(self, error, force_error):
|
||||
global show_error
|
||||
if not error:
|
||||
self.error_count = 0
|
||||
if not show_error:
|
||||
return
|
||||
self.error_temp = []
|
||||
show_error = []
|
||||
utils.ui_refresh_view_3d()
|
||||
print('REFRESH')
|
||||
return
|
||||
|
||||
if not self.error_temp:
|
||||
self.error_temp = error
|
||||
if force_error:
|
||||
self.error_count = bpy.context.scene.rsl_receiver_fps - 1
|
||||
return
|
||||
|
||||
if error == self.error_temp:
|
||||
self.error_count += 1
|
||||
else:
|
||||
self.error_temp = error
|
||||
if force_error:
|
||||
self.error_count = bpy.context.scene.rsl_receiver_fps
|
||||
else:
|
||||
self.error_count = 0
|
||||
|
||||
if self.error_count == bpy.context.scene.rsl_receiver_fps:
|
||||
show_error = self.error_temp
|
||||
utils.ui_refresh_view_3d()
|
||||
print('REFRESH')
|
||||
|
||||
def start(self, port):
|
||||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
self.sock.setblocking(False)
|
||||
self.sock.bind(('', port))
|
||||
|
||||
self.i = -1
|
||||
self.i_np = 0
|
||||
|
||||
self.error_temp = []
|
||||
self.error_count = 0
|
||||
|
||||
global show_error
|
||||
show_error = False
|
||||
|
||||
print("Rokoko Studio Live started listening on port " + str(port))
|
||||
|
||||
def stop(self):
|
||||
self.sock.close()
|
||||
print("Rokoko Studio Live stopped listening")
|
||||
Reference in New Issue
Block a user