feat: append dump function to save the db
This commit is contained in:
@ -28,14 +28,15 @@ def module_can_be_imported(name):
|
|||||||
|
|
||||||
# UTILITY FUNCTIONS
|
# UTILITY FUNCTIONS
|
||||||
def client_list_callback(scene, context):
|
def client_list_callback(scene, context):
|
||||||
from . import operators
|
from . import client
|
||||||
|
|
||||||
items = [("Common", "Common", "")]
|
items = [("Common", "Common", "")]
|
||||||
|
|
||||||
username = bpy.context.window_manager.session.username
|
username = bpy.context.window_manager.session.username
|
||||||
|
|
||||||
if operators.client_keys:
|
if client.instance:
|
||||||
for k in operators.client_keys:
|
client_keys = client.instance.list()
|
||||||
|
for k in client_keys:
|
||||||
if 'Client' in k[0]:
|
if 'Client' in k[0]:
|
||||||
name = k[1]
|
name = k[1]
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ import time
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
from random import randint
|
from random import randint
|
||||||
import zmq
|
import zmq
|
||||||
|
import json
|
||||||
|
|
||||||
from . import helpers, message
|
from . import helpers, message
|
||||||
from .libs import dump_anything, umsgpack
|
from .libs import dump_anything, umsgpack
|
||||||
@ -204,6 +205,12 @@ class Client(object):
|
|||||||
# else:
|
# else:
|
||||||
# return None
|
# return None
|
||||||
|
|
||||||
|
# SAVING FUNCTIONS
|
||||||
|
def dump(self, filepath):
|
||||||
|
with open('result.json',"w") as fp:
|
||||||
|
for key, value in self.store.items():
|
||||||
|
line = json.dumps(value.body)
|
||||||
|
fp.write(line)
|
||||||
|
|
||||||
class Server(object):
|
class Server(object):
|
||||||
address = None # Server address
|
address = None # Server address
|
||||||
|
@ -220,7 +220,6 @@ def load_mesh(target=None, data=None, create=False):
|
|||||||
|
|
||||||
material_to_load = []
|
material_to_load = []
|
||||||
material_to_load = revers(data["materials"])
|
material_to_load = revers(data["materials"])
|
||||||
|
|
||||||
target.materials.clear()
|
target.materials.clear()
|
||||||
# SLots
|
# SLots
|
||||||
i = 0
|
i = 0
|
||||||
@ -265,7 +264,7 @@ def load_object(target=None, data=None, create=False):
|
|||||||
|
|
||||||
client = bpy.context.window_manager.session.username
|
client = bpy.context.window_manager.session.username
|
||||||
|
|
||||||
if target.id == client:
|
if target.id == client or target.id == "Common":
|
||||||
target.hide_select = False
|
target.hide_select = False
|
||||||
else:
|
else:
|
||||||
target.hide_select = True
|
target.hide_select = True
|
||||||
@ -342,7 +341,7 @@ def load_collection(target=None, data=None, create=False):
|
|||||||
|
|
||||||
client = bpy.context.window_manager.session.username
|
client = bpy.context.window_manager.session.username
|
||||||
|
|
||||||
if target.id == client:
|
if target.id == client or target.id == "Common":
|
||||||
target.hide_select = False
|
target.hide_select = False
|
||||||
else:
|
else:
|
||||||
target.hide_select = True
|
target.hide_select = True
|
||||||
|
58
operators.py
58
operators.py
@ -10,6 +10,7 @@ from operator import itemgetter
|
|||||||
|
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
|
from bpy_extras.io_utils import ExportHelper
|
||||||
import mathutils
|
import mathutils
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
@ -26,16 +27,19 @@ execution_queue = queue.Queue()
|
|||||||
|
|
||||||
# This function can savely be called in another thread.
|
# This function can savely be called in another thread.
|
||||||
# The function will be executed when the timer runs the next time.
|
# The function will be executed when the timer runs the next time.
|
||||||
|
|
||||||
|
|
||||||
def run_in_main_thread(function, args):
|
def run_in_main_thread(function, args):
|
||||||
execution_queue.put(function)
|
execution_queue.put(function)
|
||||||
|
|
||||||
|
|
||||||
def execute_queued_functions():
|
def execute_queued_functions():
|
||||||
while not execution_queue.empty():
|
while not execution_queue.empty():
|
||||||
function, args = execution_queue.get()
|
function, args = execution_queue.get()
|
||||||
logger.info(args[0])
|
|
||||||
function(args[0], args[1])
|
function(args[0], args[1])
|
||||||
return .1
|
return .1
|
||||||
|
|
||||||
|
|
||||||
def clean_scene(elements=helpers.BPY_TYPES.keys()):
|
def clean_scene(elements=helpers.BPY_TYPES.keys()):
|
||||||
for datablock in elements:
|
for datablock in elements:
|
||||||
datablock_ref = getattr(bpy.data, helpers.BPY_TYPES[datablock])
|
datablock_ref = getattr(bpy.data, helpers.BPY_TYPES[datablock])
|
||||||
@ -53,7 +57,6 @@ def upload_client_instance_position():
|
|||||||
|
|
||||||
key = "Client/{}".format(username)
|
key = "Client/{}".format(username)
|
||||||
|
|
||||||
|
|
||||||
current_coords = draw.get_client_view_rect()
|
current_coords = draw.get_client_view_rect()
|
||||||
client_list = client.instance.get(key)
|
client_list = client.instance.get(key)
|
||||||
|
|
||||||
@ -70,7 +73,7 @@ def update_client_selected_object(context):
|
|||||||
client_data = client.instance.get(client_key)
|
client_data = client.instance.get(client_key)
|
||||||
|
|
||||||
selected_objects = helpers.get_selected_objects(context.scene)
|
selected_objects = helpers.get_selected_objects(context.scene)
|
||||||
if len(selected_objects) > 0:
|
if len(selected_objects) > 0 and len(client_data) > 0:
|
||||||
|
|
||||||
for obj in selected_objects:
|
for obj in selected_objects:
|
||||||
# if obj not in client_data[0][1]['active_objects']:
|
# if obj not in client_data[0][1]['active_objects']:
|
||||||
@ -84,6 +87,8 @@ def update_client_selected_object(context):
|
|||||||
client.instance.set(client_key, client_data[0][1])
|
client.instance.set(client_key, client_data[0][1])
|
||||||
|
|
||||||
# TODO: cleanup
|
# TODO: cleanup
|
||||||
|
|
||||||
|
|
||||||
def init_datablocks():
|
def init_datablocks():
|
||||||
for datatype in helpers.BPY_TYPES.keys():
|
for datatype in helpers.BPY_TYPES.keys():
|
||||||
for item in getattr(bpy.data, helpers.BPY_TYPES[datatype]):
|
for item in getattr(bpy.data, helpers.BPY_TYPES[datatype]):
|
||||||
@ -95,7 +100,7 @@ def init_datablocks():
|
|||||||
def default_tick():
|
def default_tick():
|
||||||
upload_client_instance_position()
|
upload_client_instance_position()
|
||||||
|
|
||||||
return .2
|
return .1
|
||||||
|
|
||||||
|
|
||||||
def register_ticks():
|
def register_ticks():
|
||||||
@ -103,6 +108,7 @@ def register_ticks():
|
|||||||
bpy.app.timers.register(default_tick)
|
bpy.app.timers.register(default_tick)
|
||||||
bpy.app.timers.register(execute_queued_functions)
|
bpy.app.timers.register(execute_queued_functions)
|
||||||
|
|
||||||
|
|
||||||
def unregister_ticks():
|
def unregister_ticks():
|
||||||
# REGISTER Updaters
|
# REGISTER Updaters
|
||||||
try:
|
try:
|
||||||
@ -112,6 +118,8 @@ def unregister_ticks():
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
# OPERATORS
|
# OPERATORS
|
||||||
|
|
||||||
|
|
||||||
class SessionJoinOperator(bpy.types.Operator):
|
class SessionJoinOperator(bpy.types.Operator):
|
||||||
bl_idname = "session.join"
|
bl_idname = "session.join"
|
||||||
bl_label = "join"
|
bl_label = "join"
|
||||||
@ -229,7 +237,8 @@ class SessionHostOperator(bpy.types.Operator):
|
|||||||
|
|
||||||
net_settings = context.window_manager.session
|
net_settings = context.window_manager.session
|
||||||
|
|
||||||
script_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)),"server.py")
|
script_dir = os.path.join(os.path.dirname(
|
||||||
|
os.path.abspath(__file__)), "server.py")
|
||||||
|
|
||||||
python_path = Path(bpy.app.binary_path_python)
|
python_path = Path(bpy.app.binary_path_python)
|
||||||
cwd_for_subprocesses = python_path.parent
|
cwd_for_subprocesses = python_path.parent
|
||||||
@ -277,7 +286,6 @@ class SessionStopOperator(bpy.types.Operator):
|
|||||||
# client_instance = None
|
# client_instance = None
|
||||||
net_settings.is_admin = False
|
net_settings.is_admin = False
|
||||||
|
|
||||||
|
|
||||||
unregister_ticks()
|
unregister_ticks()
|
||||||
draw.renderer.stop()
|
draw.renderer.stop()
|
||||||
else:
|
else:
|
||||||
@ -319,8 +327,10 @@ class SessionPropertyRightOperator(bpy.types.Operator):
|
|||||||
val[0][1]['id'] = net_settings.clients
|
val[0][1]['id'] = net_settings.clients
|
||||||
|
|
||||||
client.instance.set(key=self.key, value=val[0][1], override=True)
|
client.instance.set(key=self.key, value=val[0][1], override=True)
|
||||||
|
item = helpers.resolve_bpy_path(self.key)
|
||||||
print("Updating {} rights to {}".format(
|
if item:
|
||||||
|
item.id = net_settings.clients
|
||||||
|
logger.info("Updating {} rights to {}".format(
|
||||||
self.key, net_settings.clients))
|
self.key, net_settings.clients))
|
||||||
else:
|
else:
|
||||||
print("Not admin")
|
print("Not admin")
|
||||||
@ -343,7 +353,8 @@ class SessionSnapUserOperator(bpy.types.Operator):
|
|||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
area, region, rv3d = draw.view3d_find()
|
area, region, rv3d = draw.view3d_find()
|
||||||
|
|
||||||
target_client = client.instance.get("Client/{}".format(self.target_client))
|
target_client = client.instance.get(
|
||||||
|
"Client/{}".format(self.target_client))
|
||||||
if target_client:
|
if target_client:
|
||||||
rv3d.view_location = target_client[0][1]['location'][0]
|
rv3d.view_location = target_client[0][1]['location'][0]
|
||||||
rv3d.view_distance = 30.0
|
rv3d.view_distance = 30.0
|
||||||
@ -355,6 +366,34 @@ class SessionSnapUserOperator(bpy.types.Operator):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class SessionDumpDatabase(bpy.types.Operator, ExportHelper):
|
||||||
|
bl_idname = "session.dump"
|
||||||
|
bl_label = "dump json data"
|
||||||
|
bl_description = "dump session stored data to a json file"
|
||||||
|
bl_options = {"REGISTER"}
|
||||||
|
|
||||||
|
# ExportHelper mixin class uses this
|
||||||
|
filename_ext = ".json"
|
||||||
|
|
||||||
|
filter_glob: bpy.props.StringProperty(
|
||||||
|
default="*.json",
|
||||||
|
options={'HIDDEN'},
|
||||||
|
maxlen=255, # Max internal buffer length, longer would be clamped.
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
print(self.filepath)
|
||||||
|
if client.instance and client.instance.state() == 3:
|
||||||
|
client.instance.dump(self.filepath)
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
return {"CANCELLED"}
|
||||||
|
|
||||||
|
pass
|
||||||
# TODO: Rename to match official blender convention
|
# TODO: Rename to match official blender convention
|
||||||
classes = (
|
classes = (
|
||||||
SessionJoinOperator,
|
SessionJoinOperator,
|
||||||
@ -365,6 +404,7 @@ classes = (
|
|||||||
SessionPropertyRemoveOperator,
|
SessionPropertyRemoveOperator,
|
||||||
SessionSnapUserOperator,
|
SessionSnapUserOperator,
|
||||||
SessionPropertyRightOperator,
|
SessionPropertyRightOperator,
|
||||||
|
SessionDumpDatabase,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
1
result.json
Normal file
1
result.json
Normal file
File diff suppressed because one or more lines are too long
35
ui.py
35
ui.py
@ -8,11 +8,11 @@ ICONS = {'Curve':'CURVE_DATA', 'Client':'SOLO_ON','Collection': 'FILE_FOLDER', '
|
|||||||
'Texture': 'TEXTURE_DATA', 'Scene': 'SCENE_DATA','AreaLight':'LIGHT_DATA', 'Light': 'LIGHT_DATA', 'SpotLight': 'LIGHT_DATA', 'SunLight': 'LIGHT_DATA', 'PointLight': 'LIGHT_DATA', 'Camera': 'CAMERA_DATA', 'Action': 'ACTION_DATA', 'Armature': 'ARMATURE_DATA', 'GreasePencil': 'GREASEPENCIL'}
|
'Texture': 'TEXTURE_DATA', 'Scene': 'SCENE_DATA','AreaLight':'LIGHT_DATA', 'Light': 'LIGHT_DATA', 'SpotLight': 'LIGHT_DATA', 'SunLight': 'LIGHT_DATA', 'PointLight': 'LIGHT_DATA', 'Camera': 'CAMERA_DATA', 'Action': 'ACTION_DATA', 'Armature': 'ARMATURE_DATA', 'GreasePencil': 'GREASEPENCIL'}
|
||||||
|
|
||||||
class SESSION_PT_settings(bpy.types.Panel):
|
class SESSION_PT_settings(bpy.types.Panel):
|
||||||
bl_label = "NET settings"
|
bl_idname = "MULTIUSER_SETTINGS_PT_panel"
|
||||||
bl_idname = "SCENE_PT_SessionSettings"
|
bl_label = "Network"
|
||||||
bl_space_type = 'PROPERTIES'
|
bl_space_type = 'VIEW_3D'
|
||||||
bl_region_type = 'WINDOW'
|
bl_region_type = 'UI'
|
||||||
bl_context = "scene"
|
bl_category = "Multiuser"
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
@ -79,6 +79,10 @@ class SESSION_PT_settings(bpy.types.Panel):
|
|||||||
|
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.operator("session.stop", icon='QUIT', text="Exit")
|
row.operator("session.stop", icon='QUIT', text="Exit")
|
||||||
|
row = layout.row(align=True)
|
||||||
|
|
||||||
|
row.operator("session.dump", icon='QUIT', text="Dump")
|
||||||
|
row.operator("session.dump", icon='QUIT', text="Load")
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
|
|
||||||
box = row.box()
|
box = row.box()
|
||||||
@ -99,12 +103,11 @@ class SESSION_PT_settings(bpy.types.Panel):
|
|||||||
|
|
||||||
|
|
||||||
class SESSION_PT_user(bpy.types.Panel):
|
class SESSION_PT_user(bpy.types.Panel):
|
||||||
bl_label = "NET users"
|
bl_idname = "MULTIUSER_USER_PT_panel"
|
||||||
bl_idname = "SCENE_PT_SessionUsers"
|
bl_label = "Users online"
|
||||||
bl_space_type = 'PROPERTIES'
|
bl_space_type = 'VIEW_3D'
|
||||||
bl_region_type = 'WINDOW'
|
bl_region_type = 'UI'
|
||||||
bl_context = "scene"
|
bl_category = "Multiuser"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
return client.instance and client.instance.state() == 3
|
return client.instance and client.instance.state() == 3
|
||||||
@ -145,11 +148,11 @@ def get_client_key(item):
|
|||||||
return item[0]
|
return item[0]
|
||||||
|
|
||||||
class SESSION_PT_properties(bpy.types.Panel):
|
class SESSION_PT_properties(bpy.types.Panel):
|
||||||
bl_label = "NET properties"
|
bl_idname = "MULTIUSER_PROPERTIES_PT_panel"
|
||||||
bl_idname = "SCENE_PT_SessionProps"
|
bl_label = "Replicated properties"
|
||||||
bl_space_type = 'PROPERTIES'
|
bl_space_type = 'VIEW_3D'
|
||||||
bl_region_type = 'WINDOW'
|
bl_region_type = 'UI'
|
||||||
bl_context = "scene"
|
bl_category = "Multiuser"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
|
Reference in New Issue
Block a user