feat(rcf): update ui, append data load

This commit is contained in:
Swann Martinez 2019-03-25 14:56:09 +01:00
parent 704ea35129
commit a7f712e824
No known key found for this signature in database
GPG Key ID: 414CCAFD8DA720E1
3 changed files with 128 additions and 155 deletions

View File

@ -1,30 +1,29 @@
# import zmq
import asyncio
import logging
from .libs.esper import esper
from .libs import zmq
from .libs import umsgpack
import time
import random
import struct
import collections
import logging
import time
from enum import Enum
from .libs import umsgpack, zmq
logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.DEBUG)
CONNECT_TIMEOUT = 2
WAITING_TIME = 0.001
class RCFStatus(Enum):
IDLE = 1
CONNECTING = 2
CONNECTED = 3
class RCFFactory(object):
"""
Abstract layer used to bridge external and inter
"""
def init(self, data):
"""
set the RCFMessage pointer to local data
@ -36,7 +35,6 @@ class RCFFactory(object):
# TODO: Setup local pointer
def load_getter(self, data):
"""
local program > rcf
@ -61,6 +59,7 @@ class RCFFactory(object):
"""
pass
class RCFStore(collections.MutableMapping, dict):
def __init__(self, custom_factory=RCFFactory()):
@ -75,13 +74,17 @@ class RCFStore(collections.MutableMapping,dict):
def __delitem__(self, key):
dict.__delitem__(self, key)
def __iter__(self):
return dict.__iter__(self)
def __len__(self):
return dict.__len__(self)
def __contains__(self, x):
return dict.__contains__(self, x)
class RCFMessage(object):
"""
Message is formatted on wire as 2 frames:
@ -110,7 +113,6 @@ class RCFMessage(object):
elif self.key in dikt:
del dikt[self.key]
def send(self, socket):
"""Send key-value message to socket; any empty frames are sent as such."""
key = ''.encode() if self.key is None else self.key.encode()
@ -148,7 +150,8 @@ class RCFMessage(object):
data=data,
))
class Client():
class RCFClient():
def __init__(
self,
context=zmq.Context(),
@ -236,8 +239,10 @@ class Client():
logger.info("{} client running".format(id))
self.push_update("net/clients/{}".format(self.id.decode()),"client",self.id)
self.push_update("net/objects/{}".format(self.id.decode()),"client_object","None")
self.push_update(
"net/clients/{}".format(self.id.decode()), "client", self.id)
self.push_update(
"net/objects/{}".format(self.id.decode()), "client_object", "None")
self.tick_task = asyncio.ensure_future(self.tick())
@ -270,9 +275,12 @@ class Client():
self.push_sock.close()
self.pull_sock.close()
self.load_task.cancel()
if self.tick_task:
self.tick_task.cancel()
class Server():
class RCFServer():
def __init__(self, context=zmq.Context(), id="admin"):
self.context = context
@ -285,7 +293,7 @@ class Server():
self.id = id
self.bind_ports()
# Main client loop registration
self.task = asyncio.ensure_future(self.main())
self.task = asyncio.ensure_future(self.tick())
logger.info("{} client initialized".format(id))
@ -312,7 +320,7 @@ class Server():
self.poller.register(self.request_sock, zmq.POLLIN)
self.poller.register(self.collector_sock, zmq.POLLIN)
async def main(self):
async def tick(self):
logger.info("{} server launched".format(id))
while True:
@ -350,7 +358,7 @@ class Server():
msg.store(self.property_map)
msg.send(self.pub_sock)
else:
await asyncio.sleep(0.0001)
await asyncio.sleep(WAITING_TIME)
def stop(self):
logger.debug("Stopping server")

View File

@ -1,19 +1,19 @@
from bpy_extras import view3d_utils
import bpy
from . import net_components
from . import net_ui
from . import rna_translation
from .libs import dump_anything
import time
import logging
import mathutils
import random
import string
import time
import bgl
import blf
import bpy
import gpu
import mathutils
from bpy_extras import view3d_utils
from gpu_extras.batch import batch_for_shader
from . import net_components, net_ui, rna_translation
from .libs import dump_anything
logger = logging.getLogger(__name__)
client = None
@ -22,7 +22,15 @@ context = None
COLOR_TABLE = [(1, 0, 0, 1), (0, 1, 0, 1), (0, 0, 1, 1),
(0, 0.5, 1, 1), (0.5, 0, 1, 1)]
SUPPORTED_DATABLOCKS = ['collections', 'meshes', 'objects', 'materials', 'textures', 'lights', 'cameras', 'actions', 'armatures']
# UTILITY FUNCTIONS
def clean_scene(elements=SUPPORTED_DATABLOCKS):
for datablock in elements:
datablock_ref = getattr(bpy.data, datablock)
for item in datablock_ref:
datablock_ref.remove(item)
def view3d_find():
@ -98,13 +106,6 @@ def get_client_2d(coords):
return view3d_utils.location_3d_to_region_2d(region, rv3d, coords)
def on_scene_evalutation(scene):
# TODO: viewer representation
# TODO: Live update only selected object
# TODO: Scene representation
pass
def randomStringDigits(stringLength=6):
"""Generate a random string of letters and digits """
lettersAndDigits = string.ascii_letters + string.digits
@ -126,30 +127,6 @@ def resolve_bpy_path(path):
return item
def observer(scene):
global client
pass
# if client:
# for key, values in client.property_map.items():
# try:
# obj, attr = resolve_bpy_path(key)
# if attr != to_bpy(client.property_map[key]):
# value_type, value = from_bpy(attr)
# client.push_update(key, value_type, value)
# except:
# pass
return bpy.context.scene.session_settings.update_frequency
def mark_objects_for_update(scene):
for item in dir(bpy.data):
# if item in SUPPORTED_DATABLOCKS:
for datablock in getattr(bpy.data,item):
if bpy.context.object.is_evaluated:
print("EVALUATED: {}:{}".format(item,datablock.name))
def refresh_window():
import bpy
@ -159,9 +136,15 @@ def refresh_window():
def init_scene():
global client
for mesh in bpy.data.meshes:
pass
def load_mesh(target, data):
import bmesh
# TODO: handle error
mesh_buffer = bmesh.new()
for i in data["vertices"]:
@ -180,13 +163,17 @@ def load_mesh(target,data):
for v in data["polygons"][p]["vertices"]:
verts.append(mesh_buffer.verts[v])
if len(verts) > 0:
mesh_buffer.faces.new(verts)
if not target:
target = bpy.data.meshes.new(data["name"])
mesh_buffer.to_mesh(target)
def load_object(target,data):
pass
def update_scene(msg):
global client
@ -197,39 +184,24 @@ def update_scene(msg):
if bpy.context.scene.session_settings.active_object.name in msg.key:
raise ValueError()
if msg.mtype == 'Mesh' or 'Object':
if msg.mtype in SUPPORTED_DATABLOCKS:
item = resolve_bpy_path(msg.key)
if item:
if item is None:
pass
loader = dump_anything.Loader()
loader.load(item, msg.body)
if msg.mtype == 'Mesh':
load_mesh(item, msg.body)
# print(msg.get)
# logger.debug("Updating scene:\n object: {} attribute: {} , value: {}".format(
# obj, attr_name, value))
# setattr(obj, attr_name, value)
# except:
# passñ
else:
pass
# logger.debug('no need to update scene on our own')
def update_ui(msg):
"""
Update collaborative UI elements
"""
pass
recv_callbacks = [update_scene, update_ui]
recv_callbacks = [update_scene]
post_init_callbacks = [refresh_window]
# OPERATORS
class session_join(bpy.types.Operator):
bl_idname = "session.join"
@ -245,25 +217,27 @@ class session_join(bpy.types.Operator):
global client
net_settings = context.scene.session_settings
# Scene setup
if net_settings.session_mode == "CONNECT":
clean_scene()
# Session setup
if net_settings.username == "DefaultUser":
net_settings.username = "{}_{}".format(
net_settings.username, randomStringDigits())
username = str(context.scene.session_settings.username)
client_factory = rna_translation.RNAFactory()
print("{}".format(client_factory.__class__.__name__))
client = net_components.Client(
client = net_components.RCFClient(
id=username,
on_recv=recv_callbacks,
on_post_init=post_init_callbacks,
factory=client_factory,
address=net_settings.ip)
# time.sleep(1)
address=net_settings.ip,
is_admin=net_settings.session_mode == "HOST")
bpy.ops.asyncio.loop()
# bpy.app.timers.register(observer)
net_settings.is_running = True
@ -278,6 +252,7 @@ class session_add_property(bpy.types.Operator):
bl_options = {"REGISTER"}
property_path: bpy.props.StringProperty(default="None")
depth: bpy.props.IntProperty(default=1)
@classmethod
def poll(cls, context):
@ -295,7 +270,7 @@ class session_add_property(bpy.types.Operator):
dumper = dump_anything.Dumper()
dumper.type_subset = dumper.match_subset_all
dumper.depth = 4
dumper.depth = self.depth
data = dumper.dump(item)
data_type = item.__class__.__name__
@ -342,14 +317,13 @@ class session_create(bpy.types.Operator):
global server
global client
server = net_components.Server()
server = net_components.RCFServer()
time.sleep(0.1)
bpy.ops.session.join()
# init_scene()
init_scene()
bpy.app.timers.register(observer)
return {"FINISHED"}
@ -369,8 +343,6 @@ class session_stop(bpy.types.Operator):
net_settings = context.scene.session_settings
# bpy.app.timers.unregister(observer)
if server:
server.stop()
del server
@ -390,14 +362,13 @@ class session_stop(bpy.types.Operator):
class session_settings(bpy.types.PropertyGroup):
username = bpy.props.StringProperty(
name="Username", default="user_{}".format(randomStringDigits()))
ip = bpy.props.StringProperty(name="localhost")
ip = bpy.props.StringProperty(name="ip")
port = bpy.props.IntProperty(name="5555")
add_property_depth = bpy.props.IntProperty(name="add_property_depth",default=1)
buffer = bpy.props.StringProperty(name="None")
is_running = bpy.props.BoolProperty(name="is_running", default=False)
hide_users = bpy.props.BoolProperty(name="is_running", default=False)
hide_settings = bpy.props.BoolProperty(name="hide_settings", default=False)
hide_properties = bpy.props.BoolProperty(
name="hide_properties", default=True)
load_data = bpy.props.BoolProperty(name="load_data", default=True)
update_frequency = bpy.props.FloatProperty(
name="update_frequency", default=0.008)
active_object = bpy.props.PointerProperty(
@ -622,6 +593,7 @@ class session_snapview(bpy.types.Operator):
pass
# TODO: Rename to match official blender convention
classes = (
session_join,
@ -634,6 +606,7 @@ classes = (
session_snapview,
)
def depsgraph_update(scene):
for c in bpy.context.depsgraph.updates.items():
# print(c[1].id)
@ -653,22 +626,11 @@ def register():
bpy.types.Scene.session_settings = bpy.props.PointerProperty(
type=session_settings)
# bpy.app.handlers.depsgraph_update_post.append(depsgraph_update)
# bpy.app.handlers.depsgraph_update_post.append(observer)
def unregister():
try:
bpy.app.handlers.depsgraph_update_post.remove(observer)
except:
pass
global server
global client
# bpy.app.handlers.depsgraph_update_post.remove(depsgraph_update)
# bpy.app.handlers.depsgraph_update_post.remove(observer)
# bpy.app.handlers.depsgraph_update_post.remove(mark_objects_for_update)
if server:
server.stop()
del server
@ -682,8 +644,6 @@ def unregister():
for cls in reversed(classes):
unregister_class(cls)
del bpy.types.Scene.session_settings

View File

@ -38,8 +38,11 @@ class SessionSettingsPanel(bpy.types.Panel):
if scene.session_settings.session_mode == 'HOST':
row.operator("session.create",text="HOST")
else:
row.prop(net_settings,"ip",text="server ip")
box = row.box()
box.prop(net_settings,"ip",text="server ip")
box = box.row()
box.label(text="load data:")
box.prop(net_settings,"load_data",text="")
row = layout.row()
row.operator("session.join",text="CONNECT")
@ -131,8 +134,10 @@ class SessionPropertiesPanel(bpy.types.Panel):
if net_operators.client:
row = layout.row(align=True)
row.prop(net_settings, "buffer", text="")
row.prop(net_settings,"add_property_depth",text="")
row.operator("session.add_prop", text="",
icon="ADD").property_path = net_settings.buffer
row = layout.row()
# Property area
area_msg = row.box()