Skip to content

Commit

Permalink
Use fixture UUIDs instead of names in groups
Browse files Browse the repository at this point in the history
    - (this ensures group validy on fixture rename)
    - ensure unique UUIDs in fixtures
    - ensure unique UUIDs in groups
    - add migration
  • Loading branch information
vanous committed Dec 16, 2023
1 parent 0b51b31 commit eb4056d
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 22 deletions.
93 changes: 80 additions & 13 deletions __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from threading import Timer
import time
import json
import uuid as py_uuid

from dmx.pymvr import GeneralSceneDescription
from dmx.mvr import extract_mvr_textures, process_mvr_child_list
Expand Down Expand Up @@ -247,7 +248,7 @@ def prepare_empty_buffer(self, context):

data_version: IntProperty(
name = "BlenderDMX data version, bump when changing RNA structure and provide migration script",
default = 3,
default = 4,
)

# New DMX Scene
Expand Down Expand Up @@ -410,17 +411,73 @@ def migrations(self):
for fixture in dmx.fixtures:
if "uuid" not in fixture:
print("Adding UUID to", fixture.name)
fixture.uuid = str(uuid.uuid4())
fixture.uuid = str(py_uuid.uuid4())
print("Add UUID to groups, convert groups to json")
for group in dmx.groups:
if "uuid" not in group:
print("Adding UUID to", group.name)
group.uuid = str(uuid.uuid4())
group.uuid = str(py_uuid.uuid4())
print("Migrating group")
group.dump = json.dumps([x[1:-1] for x in group.dump.strip('[]').split(', ')])

if file_data_version < 4:
print("Running migration 3→4")
dmx = bpy.context.scene.dmx

def findFixtureUuidDuplicates(uuid):
found = []
for fixture in self.fixtures:
if fixture is None:
continue
if fixture.uuid == uuid:
found.append(fixture)
return found

def findGroupUuidDuplicates(uuid):
found = []
for group in self.groups:
if group is None:
continue
if group.uuid == uuid:
found.append(group)
return found

print("Ensure unique fixture UUID")
duplicates = []
for fixture in dmx.fixtures:
duplicates = findFixtureUuidDuplicates(fixture.uuid)
if len(duplicates) > 1:
for fixture in duplicates:
u = fixture.uuid
fixture.uuid = str(py_uuid.uuid4())
print("Updating fixture", fixture.name, u, fixture.uuid)

print("Ensure unique group UUID")
duplicates = []
for group in dmx.groups:
duplicates = findGroupUuidDuplicates(group.uuid)
if len(duplicates) > 1:
for group in duplicates:
u = group.uuid
group.uuid = str(py_uuid.uuid4())
print("Updating group", group.name, u, group.uuid)

print("Convert groups from fixture names to UUIDs")
for group in dmx.groups:
grouped_fixtures = json.loads(group.dump)
uuid_list = []
for g_fixture in grouped_fixtures:
if g_fixture in dmx.fixtures:
fixture = dmx.fixtures[g_fixture]
if fixture is not None:
uuid_list.append(fixture.uuid)
group.dump = json.dumps(uuid_list)
print("Groups updated")

print("Migration done")

# add here another if statement for next migration condition... like:
# if file_data_version < 4: #...
# if file_data_version < 5: #...

self.collection["DMX_DataVersion"] = self.data_version # set data version to current

Expand Down Expand Up @@ -886,12 +943,13 @@ def addFixture(self, name, profile, universe, address, mode, gel_color, display_
# TODO: fix order of attributes to match fixture.build()
bpy.app.handlers.depsgraph_update_post.clear()
dmx = bpy.context.scene.dmx
dmx.fixtures.add()
dmx.fixtures[-1].build(name, profile, mode, universe, address, gel_color, display_beams, add_target, position, focus_point, uuid, fixture_id, custom_id, fixture_id_numeric, unit_number)
new_fixture = dmx.fixtures.add()
new_fixture.uuid = str(py_uuid.uuid4()) # ensure clean uuid
new_fixture.build(name, profile, mode, universe, address, gel_color, display_beams, add_target, position, focus_point, uuid, fixture_id, custom_id, fixture_id_numeric, unit_number)
bpy.app.handlers.depsgraph_update_post.append(onDepsgraph)

def removeFixture(self, fixture):
self.remove_fixture_from_groups(fixture.name)
self.remove_fixture_from_groups(fixture.uuid)
for obj in fixture.collection.objects:
bpy.data.objects.remove(obj)
for obj in fixture.objects:
Expand All @@ -908,11 +966,19 @@ def getFixture(self, collection):
def findFixture(self, object):
for fixture in self.fixtures:
if fixture is None:
return None
continue
if (object.name in fixture.collection.objects):
return fixture
return None

def findFixtureByUUID(self, uuid):
for fixture in self.fixtures:
if fixture is None:
continue
if fixture.uuid == uuid:
return fixture
return None

def selectedFixtures(self):
selected = []
for fixture in self.fixtures:
Expand Down Expand Up @@ -982,10 +1048,11 @@ def ensureUniverseExists(self, universe):

def createGroup(self, name):
dmx = bpy.context.scene.dmx
dmx.groups.add()
group = dmx.groups[-1]
group = dmx.groups.add()
group.name = name
group.uuid = str(py_uuid.uuid4()) #ensure clean uuid
group.update()
print(group.dump)
if (not len(group.dump)):
print("DMX Group: no fixture selected!")
dmx.groups.remove(len(dmx.groups)-1)
Expand All @@ -1005,12 +1072,12 @@ def renameGroup(self, i, name):
def removeGroup(self, i):
bpy.context.scene.dmx.groups.remove(i)

def remove_fixture_from_groups(self, fixture_name):
def remove_fixture_from_groups(self, fixture_uuid):
dmx = bpy.context.scene.dmx
for group in dmx.groups:
dump = json.loads(group.dump)
if fixture_name in dump:
dump.remove(fixture_name)
if fixture_uuid in dump:
dump.remove(fixture_uuid)
group.dump = json.dumps(dump)

# # Preview Volume
Expand Down
10 changes: 5 additions & 5 deletions group.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,7 @@ def update(self):
# and repopulate it
if (len(sel_fixtures)):
#self.runtime[self.name] = sel_fixtures;
# TODO: it would be better to use fixture UUID
self.dump = json.dumps([fixture.name for fixture in sel_fixtures])
self.dump = json.dumps([fixture.uuid for fixture in sel_fixtures])
else:
self.dump = ''

Expand All @@ -68,13 +67,14 @@ def select(self):
# which seems to mess with the runtime volatile data declared as runtime
# However, a better way should be considered (a Blender String Array)
#for fixture in self.runtime[self.name]:
fixtures = bpy.context.scene.dmx.fixtures
dmx = bpy.context.scene.dmx

if not bpy.context.window_manager.dmx.aditive_selection:
bpy.ops.object.select_all(action='DESELECT')
bpy.context.scene.dmx.updatePreviewVolume()

for fixture in [fixtures[fxt] for fxt in json.loads(self.dump)]:
fixture.select()
for fixture in [dmx.findFixtureByUUID(f_uuid) for f_uuid in json.loads(self.dump)]:
if fixture is not None:
fixture.select()
bpy.context.scene.dmx.updatePreviewVolume()

4 changes: 1 addition & 3 deletions mvr.py
Original file line number Diff line number Diff line change
Expand Up @@ -401,8 +401,6 @@ def add_mvr_fixture(
)

if fixture_group is not None:
fixture_name = f"{fixture.name} {layer_index}-{fixture_index}"
group = None
if fixture_group.name in dmx.groups:
group = dmx.groups[fixture_group.name]
else:
Expand All @@ -413,5 +411,5 @@ def add_mvr_fixture(
dump = json.loads(group.dump)
else:
dump = []
dump.append(fixture_name)
dump.append(fixture.uuid_number)
group.dump = json.dumps(dump)
1 change: 0 additions & 1 deletion panels/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,6 @@ def execute(self, context):
dmx = scene.dmx
selected = scene.dmx.selectedFixtures()
context.window_manager.dmx.pause_render = True # pause renderer as partially imported fixture can cause issues during updates
# TODO: handle re-grouping if fixture name changed
# Single fixture
if (len(selected) == 1):
fixture = selected[0]
Expand Down

0 comments on commit eb4056d

Please sign in to comment.