diff --git a/i_scene_cp77_gltf/exporters/sectors_export.py b/i_scene_cp77_gltf/exporters/sectors_export.py index 6c05147..bdc3a38 100644 --- a/i_scene_cp77_gltf/exporters/sectors_export.py +++ b/i_scene_cp77_gltf/exporters/sectors_export.py @@ -21,30 +21,10 @@ # Ask in world-editing on the discord (https://discord.gg/redmodding) if you have any trouble # TODO - -# - Fix the entities -# - Add collisions +# - Fix the entities - done +# - Add collisions - can delete # - sort out instanced bits -import mathutils -def are_matrices_equal(mat1, mat2, tolerance=0.01): - if len(mat1) != len(mat2): - return False - - for i in range(len(mat1)): - for j in range(len(mat1[i])): - if abs(mat1[i][j] - mat2[i][j]) > tolerance: - return False - - return True - - - - - - - - import json @@ -66,6 +46,20 @@ def are_matrices_equal(mat1, mat2, tolerance=0.01): except: print('pyyaml not available') from mathutils import Vector, Matrix, Quaternion + +def are_matrices_equal(mat1, mat2, tolerance=0.01): + if len(mat1) != len(mat2): + return False + + for i in range(len(mat1)): + for j in range(len(mat1[i])): + if abs(mat1[i][j] - mat2[i][j]) > tolerance: + return False + + return True + + + C = bpy.context # function to recursively count nested collections @@ -87,7 +81,10 @@ def to_archive_xl(xlfilename, deletions, expectedNodes): continue new_sector={} new_sector['path']=sectorPath - new_sector['expectedNodes']=expectedNodes[sectorPath] + if sectorPath in expectedNodes.keys(): + new_sector['expectedNodes']=expectedNodes[sectorPath] + else: + continue new_sector['nodeDeletions']=[] sectorData = deletions[sectorPath] currentNodeIndex = -1 @@ -313,13 +310,56 @@ def createNodeData(t, col, nodeIndex, obj, ID): new = t[len(t)-1] new['NodeIndex']=nodeIndex new['Position']={'$type': 'Vector4','W':0,'X':float("{:.9g}".format(obj.location[0])),'Y':float("{:.9g}".format(obj.location[1])),'Z':float("{:.9g}".format(obj.location[2]))} + new['Orientation']={'$type': 'Quaternion','r':float("{:.9g}".format(obj.rotation_quaternion[0])),'i':float("{:.9g}".format(obj.rotation_quaternion[1])),'j':float("{:.9g}".format(obj.rotation_quaternion[2])),'k':float("{:.9g}".format(obj.rotation_quaternion[3]))} + new['Scale']= {'$type': 'Vector3', 'X': float("{:.9g}".format(obj.scale[0])), 'Y': float("{:.9g}".format(obj.scale[1])), 'Z': float("{:.9g}".format(obj.scale[2]))} new['Pivot']= {'$type': 'Vector3', 'X': 0, 'Y': 0, 'Z': 0} new['Bounds']= {'$type': 'Box'} new['Bounds']['Max']={'$type': 'Vector4','X':float("{:.9g}".format(obj.location[0])),'Y':float("{:.9g}".format(obj.location[1])),'Z':float("{:.9g}".format(obj.location[2]))} new['Bounds']['Min']={'$type': 'Vector4','X':float("{:.9g}".format(obj.location[0])),'Y':float("{:.9g}".format(obj.location[1])),'Z':float("{:.9g}".format(obj.location[2]))} - new['Orientation']={'$type': 'Quaternion','r':float("{:.9g}".format(obj.rotation_quaternion[0])),'i':float("{:.9g}".format(obj.rotation_quaternion[1])),'j':float("{:.9g}".format(obj.rotation_quaternion[2])),'k':float("{:.9g}".format(obj.rotation_quaternion[3]))} - new['Scale']= {'$type': 'Vector3', 'X': float("{:.9g}".format(obj.scale[0])), 'Y': float("{:.9g}".format(obj.scale[1])), 'Z': float("{:.9g}".format(obj.scale[2]))} +def create_static_from_WIMN(node, template_nodes, newHID): + new_ni=len(template_nodes) + WSMN={ + "Data": { + "$type": "worldStaticMeshNode", + "castLocalShadows": "Always", + "castRayTracedGlobalShadows": "Always", + "castRayTracedLocalShadows": "Always", + "castShadows": "Always", + "debugName": { + "$type": "CName", + "$storage": "string", + "$value": node['Data']['debugName']['$value'] + }, + "isHostOnly": node['Data']['isHostOnly'], + "isVisibleInGame": node['Data']['isVisibleInGame'], + "mesh": { + "DepotPath": { + "$type": "ResourcePath", + "$storage": "string", + "$value": node['Data']['mesh']['DepotPath']['$value'] + }, + "Flags": "Soft" + }, + "meshAppearance": { + "$type": "CName", + "$storage": "string", + "$value": node['Data']['meshAppearance']['$value'] + }, + "occluderAutohideDistanceScale": node['Data']['occluderAutohideDistanceScale'], + "occluderType": node['Data']['occluderType'], + "proxyScale": node['Data']['proxyScale'], + + "sourcePrefabHash": node['Data']['sourcePrefabHash'], + "tag": node['Data']['tag'], + "tagExt":node['Data']['tagExt'], + "version": node['Data']['version'], + + } + } + template_nodes.append(WSMN) + newHID+=1 + @@ -359,7 +399,10 @@ def exportSectors( filename): if 'exported' in obj.keys(): obj['exported']=False coll_scene = bpy.context.scene.collection + impacts=None + impact_mats=[] Inst_bufferIDs={} + new_HID=10000 # . . __ . .. . . __ __ ___ . . ___ ___ # |\/| / \ \ / | |\ | / _` /__` | | | |__ |__ # | | \__/ \/ | | \| \__/ .__/ | \__/ | | @@ -412,39 +455,33 @@ def exportSectors( filename): print(meshname, ' not found in masters') continue - num=data['worldTransformsBuffer']['numElements'] - start=data['worldTransformsBuffer']['startIndex'] - if(meshname != 0): - for idx in range(start, start+num): - bufferID=0 - if 'Data' in data['worldTransformsBuffer']['sharedDataBuffer'].keys(): - inst_trans=data['worldTransformsBuffer']['sharedDataBuffer']['Data']['buffer']['Data']['Transforms'][idx] - - elif 'HandleRefId' in data['worldTransformsBuffer']['sharedDataBuffer'].keys(): - bufferID = int(data['worldTransformsBuffer']['sharedDataBuffer']['HandleRefId']) - ref=e - for n in nodes: - if n['HandleId']==str(bufferID-1): - ref=n - inst_trans = ref['Data']['worldTransformsBuffer']['sharedDataBuffer']['Data']['buffer']['Data']['Transforms'][idx] - # store the bufferID for when we add new stuff. - if Sector_additions_coll: - Sector_additions_coll['Inst_bufferID']=bufferID - obj_col=find_col(i,idx,Sector_coll) - if obj_col and inst_trans: - if len(obj_col.objects)>0: - obj=obj_col.objects[0] - # Check for Position and if changed delete the original and add to the new sector - if obj.matrix_world!=Matrix(obj_col['matrix']): - deletions[sectorName].append(obj_col) - new_ni=len(template_nodes) - template_nodes.append(copy.deepcopy(nodes[obj_col['nodeIndex']])) - # might need to convert instanced to static here, not sure what the best approach is. - createNodeData(template_nodeData, obj_col, new_ni, obj,ID) - ID+=1 - else: - if obj_col: - deletions[sectorName].append(obj_col) + instances = [(NodeData,nodeDataIndex) for nodeDataIndex,NodeData in enumerate(t) if NodeData['NodeIndex'] == i] + for Nidx,(inst,instNDidx) in enumerate(instances): + num=data['worldTransformsBuffer']['numElements'] + start=data['worldTransformsBuffer']['startIndex'] + if(meshname != 0): + for idx in range(start, start+num): + # find the top level instance collector + obj_col=find_col(i,idx,Sector_coll) + if obj_col : + # elements are in collectors inside the top one, not just objects + if len(obj_col.children)>0: + obj=obj_col.children[0].objects[0] + # Check for Position and if changed delete the original and add to the new sector + if obj.matrix_world!=Matrix(obj_col['matrix']): + deletions[sectorName].append(obj_col) + # working with instancedmesh nodes is a pain in the ass, so convert to static + + create_static_from_WIMN(e, template_nodes, new_HID) + new_ni=len(template_nodes)-1 + for child in obj_col.children: + # might need to convert instanced to static here, not sure what the best approach is. + createNodeData(template_nodeData, child, new_ni, child.objects[0], ID) + ID+=1 + else: + # empty collector, so just delete + if obj_col: + deletions[sectorName].append(obj_col) case 'worldStaticDecalNode': #print('worldStaticDecalNode') @@ -522,67 +559,43 @@ def exportSectors( filename): num=data['cookedInstanceTransforms']['numElements'] start=data['cookedInstanceTransforms']['startIndex'] instances = [x for x in t if x['NodeIndex'] == i] + # need to go through the instances (tlidx - top level index) and then the elements (just idx) + new_WIDM_static=None for tlidx,inst in enumerate(instances): for idx in range(start, start+num): - bufferID=0 - basic_trans=None - # Transforms are inside the cookedInstanceTransforms in a buffer - if 'Data' in data['cookedInstanceTransforms']['sharedDataBuffer'].keys(): - basic_trans=data['cookedInstanceTransforms']['sharedDataBuffer']['Data']['buffer']['Data']['Transforms'][idx] - - # Transforms are in a shared buffer in another node, so get the reference and find the transform data - elif 'HandleRefId' in data['cookedInstanceTransforms']['sharedDataBuffer'].keys(): - bufferID = int(data['cookedInstanceTransforms']['sharedDataBuffer']['HandleRefId']) - ref=e - for n in nodes: - if n['HandleId']==str(bufferID-1): - ref=n - basic_trans = ref['Data']['cookedInstanceTransforms']['sharedDataBuffer']['Data']['buffer']['Data']['Transforms'][idx] - #print(basic_trans) - else : - print(e) - # store the bufferID for when we add new stuff. - if Sector_additions_coll: - Sector_additions_coll['Dest_bufferID']=bufferID - #print('Setting Dest_bufferID to ',bufferID) - - # the Transforms are stored as 2 parts, a basic transform applied to all the instances and individual ones per instance - # lets get the basic one so we can calculate the instance one. - basic_pos =Vector(get_pos(basic_trans)) - basic_rot =Quaternion(get_rot(basic_trans)) - basic_scale =Vector((1,1,1)) - basic_matr=Matrix.LocRotScale(basic_pos,basic_rot,basic_scale) - basic_matr_inv=basic_matr.inverted() - - # Never modify the basic on as other nodes may be referencing it. (its normally 0,0,0 anyway) - inst_pos =Vector(get_pos(inst)) - inst_rot =Quaternion(get_rot(inst)) - inst_scale =Vector((1,1,1)) - inst_m=Matrix.LocRotScale(inst_pos,inst_rot,inst_scale) - - obj_col=find_wIDMN_col(i,tlidx,idx,Sector_coll) - if obj_col: - if len(obj_col.objects)>0: - obj=obj_col.objects[0] + + if obj_col : + # elements are in collectors inside the top one, not just objects + if len(obj_col.children)>0: + obj=obj_col.children[0].objects[0] # Check for Position and if changed delete the original and add to the new sector if obj.matrix_world!=Matrix(obj_col['matrix']): deletions[sectorName].append(obj_col) - new_ni=len(template_nodes) - template_nodes.append(copy.deepcopy(nodes[obj_col['nodeIndex']])) - - createNodeData(template_nodeData, obj_col, new_ni, obj,ID) - ID+=1 - + # working with instancedmesh nodes is a pain in the ass, so convert to static + if new_WIDM_static==None: + create_static_from_WIMN(e, template_nodes, new_HID) + new_ni=len(template_nodes)-1 + new_WIDM_static=new_ni + + + for child in obj_col.children: + # might need to convert instanced to static here, not sure what the best approach is. + createNodeData(template_nodeData, child, new_WIDM_static, child.objects[0],ID) + ID+=1 else: + # empty collector, so just delete if obj_col: deletions[sectorName].append(obj_col) + + case 'worldCollisionNode': # need to process the sector_coll sectors and look for deleted collision bodies - this is almost identical to import, refactor them to have it in one place if sector_Collisions in coll_scene.children.keys(): - print('collisions') + sector_Collisions_coll=bpy.data.collections.get(sector_Collisions) inst = [x for x in t if x['NodeIndex'] == i][0] + print('collisions Node ',inst['nodeDataIndex']) Actors=e['Data']['compiledData']['Data']['Actors'] expectedNodes[sectorName+'_NI_'+str(inst['nodeDataIndex'])] = len(Actors) for idx,act in enumerate(Actors): @@ -593,10 +606,49 @@ def exportSectors( filename): for s,shape in enumerate(act['Shapes']): collname='NodeDataIndex_'+str(inst['nodeDataIndex'])+'_Actor_'+str(idx)+'_Shape_'+str(s) if collname in sector_Collisions_coll.objects: - print('found') + #print('found') crash= sector_Collisions_coll.objects[collname] - if are_matrices_equal(crash.matrix_world,Matrix(crash['matrix'])): + if Matrix(crash['matrix']).to_translation()!=crash.matrix_world.to_translation(): print('collision moved - cant process this yet') + # how the f do we deal with this??? + # delete the actor with archivexl, then recreate it with the new position + # so we need a collisions node, then we need to add the actor + # if we already added one to the export sector it should be ref'd by impacts, if not copy this one and ref it from impacts + # Code below is working, but the collisions arent, I'm clearly missing something. + if impacts==None: + # add the actor to the archivexl deletion list + if inst['nodeDataIndex'] in deletions['Collisions'][sectorName].keys(): + deletions['Collisions'][sectorName][inst['nodeDataIndex']].append(str(idx)) + else: + deletions['Collisions'][sectorName][inst['nodeDataIndex']]=[str(idx)] + + # nodeindex is the len of template nodes + new_ni=len(template_nodes) + #copy the collision node + template_nodes.append(copy.deepcopy(nodes[i])) + createNodeData(template_nodeData, nodes[i], new_ni, obj,ID) + ID+=1 + impacts = template_nodes[len(template_nodes)-1] + impacts['Data']['compiledData']['Data']['Actors']=[] + #need to update the position data + + # Add the current actor to the actors + impacts['Data']['compiledData']['Data']['Actors'].append(copy.deepcopy(Actors[idx])) + #update its position + ddyer=impacts['Data']['compiledData']['Data']['Actors'][len(impacts['Data']['compiledData']['Data']['Actors'])-1] + ddyer['Position']={'$type': 'WorldPosition',"x": { "$type": "FixedPoint", "Bits": int(crash.location[0]*131072) },"y": {"$type": "FixedPoint","Bits": int(crash.location[1]*131072) }, + "z": { "$type": "FixedPoint", "Bits": int(crash.location[2]*131072) }} + ddyer['Orientation']={'$type': 'Quaternion','r':float("{:.9g}".format(crash.rotation_quaternion[0])),'i':float("{:.9g}".format(obj.rotation_quaternion[1])),'j':float("{:.9g}".format(crash.rotation_quaternion[2])),'k':float("{:.9g}".format(crash.rotation_quaternion[3]))} + ddyer['Scale']= {'$type': 'Vector3', 'X': float("{:.9g}".format(crash.scale[0])), 'Y': float("{:.9g}".format(crash.scale[1])), 'Z': float("{:.9g}".format(crash.scale[2]))} + #update the numActors property + impacts['Data']['numActors']=len(impacts['Data']['compiledData']['Data']['Actors']) + + for mat in shape['Materials']: + if mat['$value'] not in impact_mats: + impact_mats.append(mat['$value']) + impacts['Data']['numMaterials']=len(impact_mats) + + else: if shape['ShapeType']=='Box' or shape['ShapeType']=='Capsule': if inst['nodeDataIndex'] in deletions['Collisions'][sectorName].keys(): @@ -975,5 +1027,5 @@ def exportSectors( filename): xlpathout=os.path.join(xloutpath,os.path.splitext(os.path.basename(filename))[0]+'.archive.xl') to_archive_xl(xlpathout, deletions, expectedNodes) - print('Finished exporting sectors from ',os.path.splitext(os.path.basename(filename))[0]) + print('Finished exporting sectors from ',os.path.splitext(os.path.basename(filename))[0], ' to ',sectpathout ) diff --git a/i_scene_cp77_gltf/importers/sector_import.py b/i_scene_cp77_gltf/importers/sector_import.py index fbba6f1..9c31441 100644 --- a/i_scene_cp77_gltf/importers/sector_import.py +++ b/i_scene_cp77_gltf/importers/sector_import.py @@ -239,6 +239,7 @@ def importSectors( filepath='', want_collisions=False, am_modding=False, with_ma #print(len(nodes)) #nodes=[] for i,e in enumerate(nodes): + print(i) data = e['Data'] type = data['$type'] match type: @@ -335,6 +336,9 @@ def importSectors( filepath='', want_collisions=False, am_modding=False, with_ma projectjson=os.path.join(path,'base',os.path.basename(project)+'.streamingsector.json') if filepath==projectjson: continue + + if 'sim_' in filepath: + continue if VERBOSE: print(projectjson) print(filepath) @@ -433,12 +437,14 @@ def importSectors( filepath='', want_collisions=False, am_modding=False, with_ma new.children.link(newchild) for old_obj in child.objects: obj=old_obj.copy() + obj.color = (0.567942, 0.0247339, 0.600028, 1) newchild.objects.link(obj) obj.matrix_local= inst_trans_mat @ obj.matrix_local if 'Armature' in obj.name: obj.hide_set(True) for old_obj in group.objects: obj=old_obj.copy() + obj.color = (0.567942, 0.0247339, 0.600028, 1) new.objects.link(obj) obj.matrix_local= inst_trans_mat @ obj.matrix_local if 'Armature' in obj.name: @@ -527,6 +533,7 @@ def importSectors( filepath='', want_collisions=False, am_modding=False, with_ma meshYScale=curvelength/meshyLength for old_obj in group.all_objects: obj=old_obj.copy() + obj.color = (0.0380098, 0.595213, 0.600022, 1) new.objects.link(obj) if obj.type=='MESH': curveMod=obj.modifiers.new('Curve','CURVE') @@ -543,51 +550,69 @@ def importSectors( filepath='', want_collisions=False, am_modding=False, with_ma case 'worldInstancedMeshNode' : #print('worldInstancedMeshNode') - meshname = data['mesh']['DepotPath']['$value'].replace('\\', os.sep) - num=data['worldTransformsBuffer']['numElements'] - start=data['worldTransformsBuffer']['startIndex'] - if(meshname != 0): - #print('Mesh - ',meshname, ' - ',i, e['HandleId']) - groupname = os.path.splitext(os.path.split(meshname)[-1])[0] - while len(groupname) > 63: - groupname = groupname[:-1] - group=Masters.children.get(groupname) - if (group): - #print('Group found for ',groupname) - for idx in range(start, start+num): - #create the linked copy of the group of mesh - - new=bpy.data.collections.new(groupname) - Sector_coll.children.link(new) - new['nodeType']=type - new['nodeIndex']=i - new['nodeDataIndex']=inst['nodeDataIndex'] - new['instance_idx']=idx - new['mesh']=meshname - new['debugName']=e['Data']['debugName'] - new['sectorName']=sectorName - for old_obj in group.all_objects: - obj=old_obj.copy() - new.objects.link(obj) - if 'Data' in data['worldTransformsBuffer']['sharedDataBuffer'].keys(): - inst_trans=data['worldTransformsBuffer']['sharedDataBuffer']['Data']['buffer']['Data']['Transforms'][idx] - - elif 'HandleRefId' in data['worldTransformsBuffer']['sharedDataBuffer'].keys(): - bufferID = int(data['worldTransformsBuffer']['sharedDataBuffer']['HandleRefId']) - new['bufferID']=bufferID - ref=e - for n in nodes: - if n['HandleId']==str(bufferID-1): - ref=n - inst_trans = ref['Data']['worldTransformsBuffer']['sharedDataBuffer']['Data']['buffer']['Data']['Transforms'][idx] - else : - print(e) - obj.location = get_pos(inst_trans) - obj.rotation_quaternion=get_rot(inst_trans) - obj.scale = get_scale(inst_trans) - obj['matrix']=obj.matrix_world - #if obj.location.x == 0: - # print('Location @ 0 for Mesh - ',meshname, ' - ',i,'HandleId - ', e['HandleId']) + instances = [x for x in t if x['NodeIndex'] == i] + for idx,inst in enumerate(instances): + meshname = data['mesh']['DepotPath']['$value'].replace('\\', os.sep) + num=data['worldTransformsBuffer']['numElements'] + start=data['worldTransformsBuffer']['startIndex'] + if(meshname != 0): + #print('Mesh - ',meshname, ' - ',i, e['HandleId']) + groupname = os.path.splitext(os.path.split(meshname)[-1])[0] + while len(groupname) > 63: + groupname = groupname[:-1] + group=Masters.children.get(groupname) + if (group): + #print('Group found for ',groupname) + NDI_Coll_name = 'NDI'+str(inst['nodeDataIndex'])+'_'+groupname + while len(NDI_Coll_name) > 63: + NDI_Coll_name = NDI_Coll_name[:-1] + NDI_Coll = bpy.data.collections.new(NDI_Coll_name) + Sector_coll.children.link(NDI_Coll) + NDI_Coll['nodeType']=type + NDI_Coll['nodeIndex']=i + NDI_Coll['nodeDataIndex']=inst['nodeDataIndex'] + NDI_Coll['mesh']=meshname + NDI_Coll['debugName']=e['Data']['debugName'] + NDI_Coll['sectorName']=sectorName + NDI_Coll['numElements']=num + for El_idx in range(start, start+num): + #create the linked copy of the group of mesh + new_groupname = 'NDI'+str(inst['nodeDataIndex'])+'_'+str(El_idx)+'_'+groupname + while len(new_groupname) > 63: + new_groupname = new_groupname[:-1] + new = bpy.data.collections.new(new_groupname) + NDI_Coll.children.link(new) + new['nodeType']=type + new['nodeIndex']=i + new['nodeDataIndex']=inst['nodeDataIndex'] + new['Element_idx']=El_idx + new['mesh']=meshname + new['debugName']=e['Data']['debugName'] + new['sectorName']=sectorName + for old_obj in group.all_objects: + obj=old_obj.copy() + new.objects.link(obj) + if 'Data' in data['worldTransformsBuffer']['sharedDataBuffer'].keys(): + inst_trans=data['worldTransformsBuffer']['sharedDataBuffer']['Data']['buffer']['Data']['Transforms'][El_idx] + + elif 'HandleRefId' in data['worldTransformsBuffer']['sharedDataBuffer'].keys(): + bufferID = int(data['worldTransformsBuffer']['sharedDataBuffer']['HandleRefId']) + new['bufferID']=bufferID + ref=e + for n in nodes: + if n['HandleId']==str(bufferID-1): + ref=n + inst_trans = ref['Data']['worldTransformsBuffer']['sharedDataBuffer']['Data']['buffer']['Data']['Transforms'][El_idx] + else : + print(e) + obj.location = get_pos(inst_trans) + obj.rotation_quaternion=get_rot(inst_trans) + obj.scale = get_scale(inst_trans) + obj['matrix']=obj.matrix_world + obj.color = (0.785188, 0.409408, 0.0430124, 1) + + #if obj.location.x == 0: + # print('Location @ 0 for Mesh - ',meshname, ' - ',i,'HandleId - ', e['HandleId']) else: print('Mesh not found - ',meshname, ' - ',i, e['HandleId']) @@ -779,7 +804,8 @@ def importSectors( filepath='', want_collisions=False, am_modding=False, with_ma obj.location = get_pos(inst) obj.rotation_quaternion = get_rot(inst) obj.scale = get_scale(inst) - + obj.color = (0.3, 0.3, 0.3, 1) + if 'Armature' in obj.name: obj.hide_set(True) if type=='worldRotatingMeshNode': @@ -813,6 +839,18 @@ def importSectors( filepath='', want_collisions=False, am_modding=False, with_ma groupname = groupname[:-1] group=Masters.children.get(groupname) if (group): + NDI_Coll_name = 'NDI'+str(inst['nodeDataIndex'])+'_'+groupname + while len(NDI_Coll_name) > 63: + NDI_Coll_name = NDI_Coll_name[:-1] + NDI_Coll = bpy.data.collections.new(NDI_Coll_name) + Sector_coll.children.link(NDI_Coll) + NDI_Coll['nodeType']=type + NDI_Coll['nodeIndex']=i + NDI_Coll['nodeDataIndex']=inst['nodeDataIndex'] + NDI_Coll['mesh']=meshname + NDI_Coll['debugName']=e['Data']['debugName'] + NDI_Coll['sectorName']=sectorName + NDI_Coll['numElements']=num #print('Glb found - ',glbfoundname) #print('Glb found, looking for instances of ',i) instances = [x for x in t if x['NodeIndex'] == i] @@ -820,7 +858,7 @@ def importSectors( filepath='', want_collisions=False, am_modding=False, with_ma #print('Node - ',i, ' - ',meshname) for idx in range(start, start+num): new=bpy.data.collections.new(groupname) - Sector_coll.children.link(new) + NDI_Coll.children.link(new) new['nodeType']=type new['nodeIndex']=i new['nodeDataIndex']=inst['nodeDataIndex']