Skip to content

Commit 8f7f45a

Browse files
committed
Deal with rigs in the app file, and slots that arent called vehicle slots.
1 parent 34265b9 commit 8f7f45a

File tree

3 files changed

+169
-99
lines changed

3 files changed

+169
-99
lines changed

i_scene_cp77_gltf/importers/entity_import.py

Lines changed: 82 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from math import sin,cos
1111
from mathutils import Vector, Matrix , Quaternion
1212
import bmesh
13-
from ..main.common import loc, show_message
13+
from ..main.common import *
1414
from ..jsontool import JSONTool
1515
from .phys_import import cp77_phys_import
1616
from ..collisiontools.collisions import draw_box_collider, draw_capsule_collider, draw_convex_collider, draw_sphere_collider
@@ -105,8 +105,9 @@ def importEnt(with_materials, filepath='', appearances=[], exclude_meshes=[], in
105105
appearances.append('BASE_COMPONENTS_ONLY')
106106

107107
VS=[]
108+
vehicle_slots=None
108109
for x in ent_components:
109-
if 'name' in x.keys() and x['name']['$value']=='vehicle_slots':
110+
if 'name' in x.keys() and x['name']['$value']=='vehicle_slots' or x['name']['$value']=='slots':
110111
VS.append(x)
111112
if len(VS)>0:
112113
vehicle_slots= VS[0]['slots']
@@ -199,7 +200,7 @@ def importEnt(with_materials, filepath='', appearances=[], exclude_meshes=[], in
199200
#link it to the scene
200201
coll_scene.children.link(ent_coll)
201202
# tag it with some custom properties.
202-
ent_coll['depotPath']=ent_name
203+
ent_coll['depotPath']=after
203204

204205

205206
enum_items = []
@@ -251,11 +252,7 @@ def importEnt(with_materials, filepath='', appearances=[], exclude_meshes=[], in
251252
ent_app_idx=i
252253
app_name=a['appearanceName']['$value']
253254
continue
254-
if a['name']['$value']==ent_default:
255-
print('appearance matched, id = ',i)
256-
ent_app_idx=i
257-
app_name=a['appearanceName']['$value']
258-
continue
255+
259256

260257
app_file = ent_apps[ent_app_idx]['appearanceResource']['DepotPath']['$value']
261258
appfilepath=os.path.join(path,app_file).replace('\\',os.sep)+'.json'
@@ -285,8 +282,41 @@ def importEnt(with_materials, filepath='', appearances=[], exclude_meshes=[], in
285282
if len(comps)==0:
286283
print('falling back to rootchunk components...')
287284
comps= ent_components
285+
286+
for c in comps:
287+
if 'name' in c.keys() and c['name']['$value']=='vehicle_slots' or c['name']['$value']=='slot':
288+
VS.append(c)
289+
if 'rig' in c.keys():
290+
rig_path = os.path.join(path, c['rig']['DepotPath']['$value'])
291+
ent_rigs.append(rig_path)
292+
if rig_path in ent_rigs:
293+
print(f"Rig found in app components: {c['rig']['DepotPath']['$value']}")
294+
if rig is None:
295+
rig_j=JSONTool.jsonload(rig_path+'.json', error_messages)
296+
if rig_j is not None:
297+
rig_j=rig_j['Data']['RootChunk']
298+
print('rig json loaded')
299+
# get the armatures already in the model
300+
oldarms= [x for x in bpy.data.objects if 'Armature' in x.name]
301+
animpath=os.path.join(path,c['animations']['gameplay'][0]['animSet']['DepotPath']['$value']+'.glb')
302+
bpy.ops.io_scene_gltf.cp77(with_materials, filepath=animpath, scripting=True)
303+
# find the armature we just loaded
304+
arms=[x for x in bpy.data.objects if 'Armature' in x.name and x not in oldarms]
305+
rig=arms[0]
306+
bones=rig.pose.bones
307+
rig["animset"] = animpath
308+
rig["rig"] = rig_path
309+
rig["ent"] = ent_name + ".ent.json"
310+
print('anim rig loaded')
311+
else:
312+
print('another rig already loaded')
313+
if not vehicle_slots:
314+
if len(VS)>0:
315+
vehicle_slots= VS[0]['slots']
316+
288317

289318
for c in comps:
319+
vs_rot=None
290320
if 'license_plate' in c['name']['$value']:
291321
includes_license_plates = True
292322
print('License plate component found:', c['name']['$value'])
@@ -397,7 +427,7 @@ def importEnt(with_materials, filepath='', appearances=[], exclude_meshes=[], in
397427
bindname=chunk_pt['Data']['bindName']['$value']
398428
# if it has a bindname of vehicle_slots, you may need to find the bone name in the vehicle slots in the root ent components
399429
# this should have been loaded earlier, check for it in the vehicle slots if not just set to the slot value
400-
if bindname=='vehicle_slots':
430+
if bindname=='vehicle_slots' or 'slots':
401431
if vehicle_slots:
402432
slotname=chunk_pt['Data']['slotName']['$value']
403433
for slot in vehicle_slots:
@@ -460,12 +490,18 @@ def importEnt(with_materials, filepath='', appearances=[], exclude_meshes=[], in
460490
bpy.context.view_layer.objects.active = obj
461491
bpy.ops.constraint.childof_set_inverse(constraint="Child Of", owner='OBJECT')
462492

493+
463494
# things like the tvs have a bindname but no slotname, bindname appears to point at the name of the main component, and its the only one with a transform applied
464495
elif bindname:
465496
#see if we can find a component that matches it
466497
if bindname=='interior_02':
467498
print('interior_02')
468499
bindpt=[cmp for cmp in comps if cmp['name']['$value']==bindname]
500+
slotname= chunk_pt.get('Data').get('slotName').get('$value')
501+
if bindpt and slotname:
502+
# Have a bindpoint and a slotname, so we can use the local transform from the bindpoint
503+
print('bindpt and slotname found')
504+
469505
if bindpt and len(bindpt)==1:
470506
if c['localTransform']['Position']['x']['Bits']==0 and c['localTransform']['Position']['y']['Bits']==0 and c['localTransform']['Position']['z']['Bits']==0 and 'localTransform' in bindpt[0]:
471507
c['localTransform']['Position']=bindpt[0]['localTransform']['Position']
@@ -525,16 +561,42 @@ def importEnt(with_materials, filepath='', appearances=[], exclude_meshes=[], in
525561
obj['bindname']=bindname
526562
pt_trans=bones[bindname].head
527563
pt_rot=bones[bindname].rotation_quaternion
528-
529-
obj.location.x = obj.location.x+pt_trans[0]
530-
obj.location.y = obj.location.y+pt_trans[1]
531-
obj.location.z = obj.location.z+pt_trans[2]
564+
vs=[slot for slot in vehicle_slots if slot['slotName']['$value']==slotname]
565+
vs_rot=Quaternion([0,0,0,1])
566+
vs_pos= Vector([0,0,0])
567+
vs_scale=Vector([1,1,1])
568+
if len(vs)>0:
569+
vs=vs[0]
570+
if 'relativeRotation' in vs.keys():
571+
vs_rot[0]=vs['relativeRotation']['i']
572+
vs_rot[1]=vs['relativeRotation']['j']
573+
vs_rot[2]=vs['relativeRotation']['k']
574+
vs_rot[3]=vs['relativeRotation']['r']
575+
if 'relativePosition' in vs.keys():
576+
vs_pos[0]=vs['relativePosition']['X']
577+
vs_pos[1]=vs['relativePosition']['Y']
578+
vs_pos[2]=vs['relativePosition']['Z']
579+
#print('vs_rot = ',vs_rot)
580+
vs_mat=Matrix.LocRotScale(Vector([0,0,0]),vs_rot,vs_scale)
581+
pt_mat=Matrix.LocRotScale(Vector([0,0,0]),pt_rot,Vector(vs_scale))
582+
vs_z_ang=vs_mat.to_euler().z
583+
pt_z_ang=pt_mat.to_euler().z
584+
585+
obj.location.x = obj.location.x+pt_trans[0]+vs_pos[0]
586+
obj.location.y = obj.location.y+pt_trans[1]+vs_pos[1]
587+
obj.location.z = obj.location.z+pt_trans[2]+vs_pos[2]
532588

533589
obj.rotation_quaternion.x = btrans['Rotation']['i']
534590
obj.rotation_quaternion.y = btrans['Rotation']['j']
535591
obj.rotation_quaternion.z = btrans['Rotation']['k']
536592
obj.rotation_quaternion.w = btrans['Rotation']['r']
537-
# Apply child of constraints to them and set the inverse
593+
594+
595+
obj.rotation_quaternion=obj.rotation_quaternion*Quaternion(vs_rot)
596+
#obj.matrix_local= obj.matrix_local @ vs_mat
597+
#obj.matrix_world= pt_mat @ obj.matrix_world
598+
599+
#Apply child of constraints to them and set the inverse
538600
if 'fuel_cap' not in bindname:
539601
co=obj.constraints.new(type='CHILD_OF')
540602
co.target=rig
@@ -593,11 +655,16 @@ def importEnt(with_materials, filepath='', appearances=[], exclude_meshes=[], in
593655
obj.location.x = obj.location.x+x
594656
obj.location.y = obj.location.y+y
595657
obj.location.z = obj.location.z+z
596-
if 'Orientation' in c['localTransform'].keys():
658+
# shouldnt need the 0 check, pretty sure I've fuked up a default somewhere, but at this point I just want it to work.
659+
if 'Orientation' in c['localTransform'].keys() and (sum(obj.rotation_quaternion[:])<1.1 and sum(obj.rotation_quaternion[:])>0.9) or (sum(obj.rotation_quaternion[:])<0.1 and sum(obj.rotation_quaternion[:])>-0.1):
660+
lrot=get_rot(c['localTransform'])
661+
obj.rotation_quaternion = obj.rotation_quaternion * Quaternion(lrot)
597662
obj.rotation_quaternion.x = c['localTransform']['Orientation']['i']
598663
obj.rotation_quaternion.y = c['localTransform']['Orientation']['j']
599664
obj.rotation_quaternion.z = c['localTransform']['Orientation']['k']
600665
obj.rotation_quaternion.w = c['localTransform']['Orientation']['r']
666+
#if vs_rot:
667+
# obj.matrix_local = Matrix.LocRotScale(Vector(0,0,0),Quaternion(vs_rot),Vector(1,1,1)) @
601668
if 'scale' in c['localTransform'].keys():
602669
obj.scale.x = c['localTransform']['scale']['X']
603670
obj.scale.y = c['localTransform']['scale']['Y']

i_scene_cp77_gltf/importers/sector_import.py

Lines changed: 2 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
# 2) If you want collision objects, change want_collisions to True
1515
# 3) If you want it to generate the _new collections for you to add new stuff in set am_modding to True
1616
# 4) Run it
17-
17+
from ..main.common import *
1818
from ..jsontool import JSONTool
1919
import glob
2020
import os
@@ -211,89 +211,7 @@ def add_to_list(basename, meshes, dict):
211211
dict[basename]={'apps':[mesh['appearances']],'sectors':[mesh['sector']]}
212212

213213

214-
def get_pos(inst):
215-
pos=[0,0,0]
216-
if 'Position' in inst.keys():
217-
if '$type' in inst['Position'].keys() and inst['Position']['$type']=='WorldPosition':
218-
pos[0]=inst['Position']['x']['Bits']/131072*scale_factor
219-
pos[1]=inst['Position']['y']['Bits']/131072*scale_factor
220-
pos[2]=inst['Position']['z']['Bits']/131072*scale_factor
221-
else:
222-
if 'Properties' in inst['Position'].keys():
223-
pos[0] = inst['Position']['Properties']['X'] /scale_factor
224-
pos[1] = inst['Position']['Properties']['Y'] /scale_factor
225-
pos[2] = inst['Position']['Properties']['Z'] /scale_factor
226-
else:
227-
if 'X' in inst['Position'].keys():
228-
pos[0] = inst['Position']['X'] /scale_factor
229-
pos[1] = inst['Position']['Y'] /scale_factor
230-
pos[2] = inst['Position']['Z'] /scale_factor
231-
else:
232-
pos[0] = inst['Position']['x'] /scale_factor
233-
pos[1] = inst['Position']['y'] /scale_factor
234-
pos[2] = inst['Position']['z'] /scale_factor
235-
elif 'position' in inst.keys():
236-
if 'X' in inst['position'].keys():
237-
pos[0] = inst['position']['X'] /scale_factor
238-
pos[1] = inst['position']['Y'] /scale_factor
239-
pos[2] = inst['position']['Z'] /scale_factor
240-
elif 'translation' in inst.keys():
241-
pos[0] = inst['translation']['X'] /scale_factor
242-
pos[1] = inst['translation']['Y'] /scale_factor
243-
pos[2] = inst['translation']['Z'] /scale_factor
244-
return pos
245214

246-
def get_rot(inst):
247-
rot=[0,0,0,0]
248-
if 'Orientation' in inst.keys():
249-
if 'Properties' in inst['Orientation'].keys():
250-
rot[0] = inst['Orientation']['Properties']['r']
251-
rot[1] = inst['Orientation']['Properties']['i']
252-
rot[2] = inst['Orientation']['Properties']['j']
253-
rot[3] = inst['Orientation']['Properties']['k']
254-
else:
255-
rot[0] = inst['Orientation']['r']
256-
rot[1] = inst['Orientation']['i']
257-
rot[2] = inst['Orientation']['j']
258-
rot[3] = inst['Orientation']['k']
259-
elif 'orientation' in inst.keys():
260-
rot[0] = inst['orientation']['r']
261-
rot[1] = inst['orientation']['i']
262-
rot[2] = inst['orientation']['j']
263-
rot[3] = inst['orientation']['k']
264-
elif 'Rotation' in inst.keys() and 'r' in inst['Rotation'].keys():
265-
rot[0] = inst['Rotation']['r']
266-
rot[1] = inst['Rotation']['i']
267-
rot[2] = inst['Rotation']['j']
268-
rot[3] = inst['Rotation']['k']
269-
elif 'Rotation' in inst.keys() and 'X' in inst['Rotation'].keys():
270-
rot[0] = inst['Rotation']['W']
271-
rot[1] = inst['Rotation']['X']
272-
rot[2] = inst['Rotation']['Y']
273-
rot[3] = inst['Rotation']['Z']
274-
elif 'rotation' in inst.keys():
275-
rot[0] = inst['rotation']['r']
276-
rot[1] = inst['rotation']['i']
277-
rot[2] = inst['rotation']['j']
278-
rot[3] = inst['rotation']['k']
279-
return rot
280-
281-
def get_scale(inst):
282-
scale=[0,0,0]
283-
if 'Scale' in inst.keys():
284-
if 'Properties' in inst['Scale'].keys():
285-
scale[0] = inst['Scale']['Properties']['X'] /scale_factor
286-
scale[1] = inst['Scale']['Properties']['Y'] /scale_factor
287-
scale[2] = inst['Scale']['Properties']['Z'] /scale_factor
288-
else:
289-
scale[0] = inst['Scale']['X'] /scale_factor
290-
scale[1] = inst['Scale']['Y'] /scale_factor
291-
scale[2] = inst['Scale']['Z'] /scale_factor
292-
elif 'scale' in inst.keys():
293-
scale[0] = inst['scale']['X'] /scale_factor
294-
scale[1] = inst['scale']['Y'] /scale_factor
295-
scale[2] = inst['scale']['Z'] /scale_factor
296-
return scale
297215

298216
def get_col(color):
299217
col=[0,0,0]
@@ -339,7 +257,7 @@ def importSectors( filepath, with_mats, remap_depot, want_collisions, am_modding
339257
print('')
340258
start_time = time.time()
341259
# Set this to true to limit import to the types listed in the import_types list.
342-
limittypes=False
260+
limittypes=True
343261
import_types=None
344262
import_types=['worldEntityNode'
345263
]

0 commit comments

Comments
 (0)