diff --git a/docs/getting_started/img/server_preset_exemple.gif b/docs/getting_started/img/server_preset_exemple.gif new file mode 100644 index 0000000..9157675 Binary files /dev/null and b/docs/getting_started/img/server_preset_exemple.gif differ diff --git a/docs/getting_started/img/server_preset_image_add.PNG b/docs/getting_started/img/server_preset_image_add.PNG new file mode 100644 index 0000000..c909038 Binary files /dev/null and b/docs/getting_started/img/server_preset_image_add.PNG differ diff --git a/docs/getting_started/img/server_preset_image_admin.PNG b/docs/getting_started/img/server_preset_image_admin.PNG new file mode 100644 index 0000000..2c2550d Binary files /dev/null and b/docs/getting_started/img/server_preset_image_admin.PNG differ diff --git a/docs/getting_started/img/server_preset_image_normal_server.PNG b/docs/getting_started/img/server_preset_image_normal_server.PNG new file mode 100644 index 0000000..d0ea35f Binary files /dev/null and b/docs/getting_started/img/server_preset_image_normal_server.PNG differ diff --git a/docs/getting_started/img/server_preset_image_report.PNG b/docs/getting_started/img/server_preset_image_report.PNG new file mode 100644 index 0000000..f808815 Binary files /dev/null and b/docs/getting_started/img/server_preset_image_report.PNG differ diff --git a/docs/getting_started/quickstart.rst b/docs/getting_started/quickstart.rst index c3092e7..f7ae7ff 100644 --- a/docs/getting_started/quickstart.rst +++ b/docs/getting_started/quickstart.rst @@ -108,36 +108,69 @@ Before starting make sure that you have access to the session IP address and por 1. Fill in your user information -------------------------------- -Follow the user-info_ section for this step. +Joining a server +======================= ----------------- -2. Network setup ----------------- +-------------- +Network setup +-------------- In the network panel, select **JOIN**. The **join sub-panel** (see image below) allows you to configure your client to join a collaborative session which is already hosted. -.. figure:: img/quickstart_join.png - :align: center - :alt: Connect menu +.. figure:: img/server_preset_image_normal_server.png + :align: center + :width: 200px - Connection panel + Connection pannel Fill in the fields with your information: - **IP**: the host's IP address. - **Port**: the host's port number. -- **Connect as admin**: connect yourself with **admin rights** (see :ref:`admin` ) to the session. - -.. Maybe something more explicit here - -.. note:: - Additional configuration settings can be found in the :ref:`advanced` section. Once you've configured every field, hit the button **CONNECT** to join the session ! When the :ref:`session-status` is **ONLINE** you are online and ready to start co-creating. +.. note:: + + If you want to have **administrator rights** (see :ref:`admin` ) on the server, just enter the password created by the host in the **Connect as admin** section + + .. figure:: img/server_preset_image_admin.png + :align: center + :width: 200px + + Admin password + +--------------- +Server presets +--------------- + +You can save your server presets in a preset list below the 'JOIN' and 'HOST' buttons. This allows you to quickly access and manage your servers. + +To add a server, first enter the ip address and the port (plus the password if needed), then click on the + icon to add a name to your preset. To remove a server from the list, select it and click on the - icon. + +.. figure:: img/server_preset_exemple.gif + :align: center + :width: 200px + +.. warning:: Be careful, if you don't rename your new preset, or if it has the same name as an existing preset, the old preset will be overwritten. + + .. figure:: img/server_preset_image_report.png + :align: center + :width: 200px + +.. note:: + + Two presets are already present when the addon is launched: + + - The 'localhost' preset, to host and join a local session quickly + - The 'public session' preset, to join the public sessions of the multi-user server (official discord to participate : https://discord.gg/aBPvGws) + +.. note:: + Additional configuration settings can be found in the :ref:`advanced` section. + .. note:: When starting a **dedicated server**, the session status screen will take you to the **LOBBY**, awaiting an admin to start the session. diff --git a/docs/tutorials/hosting_guide.rst b/docs/tutorials/hosting_guide.rst index ecedafc..7ec9c75 100644 --- a/docs/tutorials/hosting_guide.rst +++ b/docs/tutorials/hosting_guide.rst @@ -76,7 +76,7 @@ Hit 'Create a network'(see image below) and go to the network settings. :align: center :width: 450px - Network page + Admin password Now that the network is created, let's configure it. diff --git a/multi_user/libs/replication b/multi_user/libs/replication index 8c27d0c..b2bd39a 160000 --- a/multi_user/libs/replication +++ b/multi_user/libs/replication @@ -1 +1 @@ -Subproject commit 8c27d0cec6b7db1756a7d142c94023fe20f352ff +Subproject commit b2bd39a6e140f60fc2422d710bce83586cc93af1 diff --git a/multi_user/operators.py b/multi_user/operators.py index 8afce01..d8bff20 100644 --- a/multi_user/operators.py +++ b/multi_user/operators.py @@ -34,6 +34,8 @@ from queue import Queue from time import gmtime, strftime import traceback +from bpy.props import FloatProperty + try: import _pickle as pickle except ImportError: @@ -161,7 +163,7 @@ class SessionStartOperator(bpy.types.Operator): settings = utils.get_preferences() runtime_settings = context.window_manager.session users = bpy.data.window_managers['WinMan'].online_users - admin_pass = runtime_settings.password + admin_pass = settings.password users.clear() deleyables.clear() @@ -902,6 +904,76 @@ class SessionLoadSaveOperator(bpy.types.Operator, ImportHelper): def poll(cls, context): return True +class SessionPresetServerAdd(bpy.types.Operator): + """Add a server to the server list preset""" + bl_idname = "session.preset_server_add" + bl_label = "add server preset" + bl_description = "add the current server to the server preset list" + bl_options = {"REGISTER"} + + name : bpy.props.StringProperty(default="server_preset") + + @classmethod + def poll(cls, context): + return True + + def invoke(self, context, event): + assert(context) + return context.window_manager.invoke_props_dialog(self) + + def draw(self, context): + layout = self.layout + + col = layout.column() + settings = utils.get_preferences() + + col.prop(settings, "server_name", text="server name") + + def execute(self, context): + assert(context) + + settings = utils.get_preferences() + + existing_preset = settings.server_preset.get(settings.server_name) + + new_server = existing_preset if existing_preset else settings.server_preset.add() + new_server.name = settings.server_name + new_server.server_ip = settings.ip + new_server.server_port = settings.port + new_server.server_password = settings.password + + settings.server_preset_interface = settings.server_name + + if new_server == existing_preset : + self.report({'INFO'}, "Server '" + settings.server_name + "' override") + else : + self.report({'INFO'}, "New '" + settings.server_name + "' server preset") + + return {'FINISHED'} + + +class SessionPresetServerRemove(bpy.types.Operator): + """Remove a server to the server list preset""" + bl_idname = "session.preset_server_remove" + bl_label = "remove server preset" + bl_description = "remove the current server from the server preset list" + bl_options = {"REGISTER"} + + @classmethod + def poll(cls, context): + return True + + def execute(self, context): + assert(context) + + settings = utils.get_preferences() + + settings.server_preset.remove(settings.server_preset.find(settings.server_preset_interface)) + + return {'FINISHED'} + + + def menu_func_import(self, context): self.layout.operator(SessionLoadSaveOperator.bl_idname, text='Multi-user session snapshot (.db)') @@ -919,11 +991,13 @@ classes = ( SessionKickOperator, SessionInitOperator, SessionClearCache, - SessionNotifyOperator, + SessionNotifyOperator, SessionSaveBackupOperator, SessionLoadSaveOperator, SessionStopAutoSaveOperator, SessionPurgeOperator, + SessionPresetServerAdd, + SessionPresetServerRemove, ) def update_external_dependencies(): diff --git a/multi_user/preferences.py b/multi_user/preferences.py index 7ebc2a8..2c5afea 100644 --- a/multi_user/preferences.py +++ b/multi_user/preferences.py @@ -33,6 +33,19 @@ from replication.interface import session IP_REGEX = re.compile("^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$") HOSTNAME_REGEX = re.compile("^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$") +DEFAULT_PRESETS = { + "localhost" : { + "server_ip": "localhost", + "server_port": 5555, + "server_password": "admin" + }, + "public session" : { + "server_ip": "51.75.71.183", + "server_port": 5555, + "server_password": "" + }, +} + def randomColor(): """Generate a random color """ r = random.random() @@ -65,8 +78,11 @@ def update_ip(self, context): logging.error("Wrong IP format") self['ip'] = "127.0.0.1" - - +def update_server_preset_interface(self, context): + self.server_name = self.server_preset.get(self.server_preset_interface).name + self.ip = self.server_preset.get(self.server_preset_interface).server_ip + self.port = self.server_preset.get(self.server_preset_interface).server_port + self.password = self.server_preset.get(self.server_preset_interface).server_password def update_directory(self, context): new_dir = Path(self.cache_directory) @@ -93,6 +109,10 @@ class ReplicatedDatablock(bpy.types.PropertyGroup): auto_push: bpy.props.BoolProperty(default=True) icon: bpy.props.StringProperty() +class ServerPreset(bpy.types.PropertyGroup): + server_ip: bpy.props.StringProperty() + server_port: bpy.props.IntProperty(default=5555) + server_password: bpy.props.StringProperty(default="admin", subtype = "PASSWORD") def set_sync_render_settings(self, value): self['sync_render_settings'] = value @@ -145,7 +165,7 @@ class SessionPrefs(bpy.types.AddonPreferences): ip: bpy.props.StringProperty( name="ip", description='Distant host ip', - default="127.0.0.1", + default="localhost", update=update_ip) username: bpy.props.StringProperty( name="Username", @@ -160,6 +180,17 @@ class SessionPrefs(bpy.types.AddonPreferences): description='Distant host port', default=5555 ) + server_name: bpy.props.StringProperty( + name="server_name", + description="Custom name of the server", + default='localhost', + ) + password: bpy.props.StringProperty( + name="password", + default=random_string_digits(), + description='Session password', + subtype='PASSWORD' + ) sync_flags: bpy.props.PointerProperty( type=ReplicationFlags ) @@ -321,6 +352,25 @@ class SessionPrefs(bpy.types.AddonPreferences): max=59 ) + # Server preset + def server_list_callback(scene, context): + settings = get_preferences() + enum = [] + for i in settings.server_preset: + enum.append((i.name, i.name, "")) + return enum + + server_preset: bpy.props.CollectionProperty( + name="server preset", + type=ServerPreset, + ) + server_preset_interface: bpy.props.EnumProperty( + name="servers", + description="servers enum", + items=server_list_callback, + update=update_server_preset_interface, + ) + # Custom panel panel_category: bpy.props.StringProperty( description="Choose a name for the category of the panel", @@ -420,6 +470,18 @@ class SessionPrefs(bpy.types.AddonPreferences): new_db.icon = type_module_class.bl_icon new_db.bl_name = type_module_class.bl_id + # custom at launch server preset + def generate_default_presets(self): + for preset_name, preset_data in DEFAULT_PRESETS.items(): + existing_preset = self.server_preset.get(preset_name) + if existing_preset : + continue + new_server = self.server_preset.add() + new_server.name = preset_name + new_server.server_ip = preset_data.get('server_ip') + new_server.server_port = preset_data.get('server_port') + new_server.server_password = preset_data.get('server_password',None) + def client_list_callback(scene, context): from . import operators @@ -496,12 +558,6 @@ class SessionProps(bpy.types.PropertyGroup): description='Connect as admin', default=False ) - password: bpy.props.StringProperty( - name="password", - default=random_string_digits(), - description='Session password', - subtype='PASSWORD' - ) internet_ip: bpy.props.StringProperty( name="internet ip", default="no found", @@ -523,6 +579,7 @@ classes = ( SessionProps, ReplicationFlags, ReplicatedDatablock, + ServerPreset, SessionPrefs, ) @@ -537,6 +594,10 @@ def register(): if len(prefs.supported_datablocks) == 0: logging.debug('Generating bl_types preferences') prefs.generate_supported_types() + + # at launch server presets + prefs.generate_default_presets() + def unregister(): diff --git a/multi_user/ui.py b/multi_user/ui.py index df5ae13..451586c 100644 --- a/multi_user/ui.py +++ b/multi_user/ui.py @@ -156,7 +156,13 @@ class SESSION_PT_settings_network(bpy.types.Panel): row = layout.row() row.prop(runtime_settings, "session_mode", expand=True) row = layout.row() + + col = row.row(align=True) + col.prop(settings, "server_preset_interface", text="") + col.operator("session.preset_server_add", icon='ADD', text="") + col.operator("session.preset_server_remove", icon='REMOVE', text="") + row = layout.row() box = row.box() if runtime_settings.session_mode == 'HOST': @@ -168,7 +174,7 @@ class SESSION_PT_settings_network(bpy.types.Panel): row.prop(settings, "init_method", text="") row = box.row() row.label(text="Admin password:") - row.prop(runtime_settings, "password", text="") + row.prop(settings, "password", text="") row = box.row() row.operator("session.start", text="HOST").host = True else: @@ -184,11 +190,10 @@ class SESSION_PT_settings_network(bpy.types.Panel): if runtime_settings.admin: row = box.row() row.label(text="Password:") - row.prop(runtime_settings, "password", text="") + row.prop(settings, "password", text="") row = box.row() row.operator("session.start", text="CONNECT").host = False - class SESSION_PT_settings_user(bpy.types.Panel): bl_idname = "MULTIUSER_SETTINGS_USER_PT_panel" bl_label = "User info"