+
+ # Process entity data
+ # ==================================================================
+ node.offset = entdata_length
+
+ if classtype != 'k_classtype_none':
+ disptype = classtype
+ else:
+ disptype = objt
+
+ s000 = F" [{uid: 3}/{header.node_count-1}]" + " |"*(depth-1)
+ s001 = F" L {obj.name}"
+ s002 = s000+s001
+ s003 = F"{disptype}"
+ s004 = F"{node.parent: 3}"
+ s005 = ""
+
+ if classtype == 'k_classtype_skin':
+ armature_def['obj'].data.pose_position = POSE_OR_REST_CACHE
+ s005 = F" [armature -> {armature_def['obj'].cv_data.uid}]"
+
+ scmp = F"{s002:<32} {s003:<22} {s004} {s005}"
+ print( scmp )
+
+ if classtype == 'k_classtype_INSTANCE' or \
+ classtype == 'k_classtype_BONE' or \
+ classtype == 'k_classtype_SKELETON' or \
+ classtype == 'k_classtype_SKIN':
+ print( "ERROR: user classtype cannot be _INSTANCE or _BONE" )
+ node.classtype = 0
+ node.offset = 0
+
+ elif classtype == 'k_classtype_skin':
+ node.classtype = 12
+
+ armature = armature_def['obj']
+ entdata_length += sizeof( classtype_skin )
+
+ skin = classtype_skin()
+ skin.skeleton = armature.cv_data.uid
+ entdata_buffer += [skin]
+
+ elif classtype == 'k_classtype_skeleton':
+ node.classtype = 11
+ entdata_length += sizeof( classtype_skeleton )
+ skeleton = classtype_skeleton()
+
+ armature_def = graph_lookup[obj]
+ armature = obj
+ bones = armature_def['bones']
+ skeleton.channels = len(bones)
+ skeleton.ik_count = armature_def["ik_count"]
+ skeleton.collider_count = armature_def["collider_count"]
+
+ if armature.animation_data:
+ previous_frame = bpy.context.scene.frame_current
+ previous_action = armature.animation_data.action
+
+ skeleton.anim_start = len(anim_buffer)
+ skeleton.anim_count = 0
+
+ for NLALayer in obj.animation_data.nla_tracks:
+ for NLAStrip in NLALayer.strips:
+ # Use action
+ for a in bpy.data.actions:
+ if a.name == NLAStrip.name:
+ armature.animation_data.action = a
+ break
+
+ anim_start = int(NLAStrip.action_frame_start)
+ anim_end = int(NLAStrip.action_frame_end)
+
+ # export strips
+ anim = mdl_animation()
+ anim.pstr_name = emplace_string( NLAStrip.action.name )
+ anim.rate = 30.0
+ anim.offset = animdata_length
+ anim.length = anim_end-anim_start
+
+ # Export the fucking keyframes
+ for frame in range(anim_start,anim_end):
+ bpy.context.scene.frame_set(frame)
+
+ for bone_name in bones:
+ for pb in armature.pose.bones:
+ if pb.name == bone_name:
+ rb = armature.data.bones[ bone_name ]
+
+ loc, rot, sca = pb.matrix_basis.decompose()
+
+ # local position
+ vp = rb.matrix @ loc
+ final_pos = Vector(( vp[0], vp[2], -vp[1] ))
+
+ # rotation
+ lc_m = pb.matrix_channel.to_3x3()
+ if pb.parent is not None:
+ smtx = pb.parent.matrix_channel.to_3x3()
+ lc_m = smtx.inverted() @ lc_m
+ rq = lc_m.to_quaternion()
+
+ kf = mdl_keyframe()
+ kf.co[0] = final_pos[0]
+ kf.co[1] = final_pos[1]
+ kf.co[2] = final_pos[2]
+
+ kf.q[0] = rq[1]
+ kf.q[1] = rq[3]
+ kf.q[2] = -rq[2]
+ kf.q[3] = rq[0]
+
+ # scale
+ kf.s[0] = sca[0]
+ kf.s[1] = sca[2]
+ kf.s[2] = sca[1]
+
+ animdata_buffer += [kf]
+ animdata_length += sizeof(mdl_keyframe)
+ break
+
+ anim_buffer += [anim]
+ skeleton.anim_count += 1
+
+ s000 = F" [{uid: 3}/{header.node_count-1}]" + " |"*(depth-1)
+ print( F"{s000} | *anim: {NLAStrip.action.name}" )
+
+ bpy.context.scene.frame_set( previous_frame )
+ armature.animation_data.action = previous_action
+
+ entdata_buffer += [skeleton]
+
+ elif classtype == 'k_classtype_bone':
+ node.classtype = 10
+ entdata_length += sizeof( classtype_bone )
+
+ bone = classtype_bone()
+ bone.deform = node_def['deform']
+
+ if 'target' in node_def:
+ bone.ik_target = armature_def['bones'].index( node_def['target'] )
+ bone.ik_pole = armature_def['bones'].index( node_def['pole'] )
+ else:
+ bone.ik_target = 0
+ bone.ik_pole = 0
+
+ bone.collider = 1 if obj.cv_data.collider else 0
+ if obj.cv_data.collider:
+ bone.hitbox[0][0] = obj.cv_data.v0[0]
+ bone.hitbox[0][1] = obj.cv_data.v0[2]
+ bone.hitbox[0][2] = -obj.cv_data.v1[1]
+ bone.hitbox[1][0] = obj.cv_data.v1[0]
+ bone.hitbox[1][1] = obj.cv_data.v1[2]
+ bone.hitbox[1][2] = -obj.cv_data.v0[1]
+ else:
+ bone.hitbox[0][0] = 0.0
+ bone.hitbox[0][1] = 0.0
+ bone.hitbox[0][2] = 0.0
+ bone.hitbox[1][0] = 0.0
+ bone.hitbox[1][1] = 0.0
+ bone.hitbox[1][2] = 0.0
+
+ if obj.cv_data.con0:
+ bone.use_limits = 1
+ bone.angle_limits[0][0] = obj.cv_data.mins[0]
+ bone.angle_limits[0][1] = obj.cv_data.mins[2]
+ bone.angle_limits[0][2] = -obj.cv_data.maxs[1]
+ bone.angle_limits[1][0] = obj.cv_data.maxs[0]
+ bone.angle_limits[1][1] = obj.cv_data.maxs[2]
+ bone.angle_limits[1][2] = -obj.cv_data.mins[1]
+ else:
+ bone.use_limits = 0
+ bone.angle_limits[0][0] = 0.0
+ bone.angle_limits[0][1] = 0.0
+ bone.angle_limits[0][2] = 0.0
+ bone.angle_limits[1][0] = 0.0
+ bone.angle_limits[1][1] = 0.0
+ bone.angle_limits[1][2] = 0.0
+
+ bone.deform = node_def['deform']
+ entdata_buffer += [bone]
+
+ elif classtype == 'k_classtype_gate':
+ node.classtype = 1
+ entdata_length += sizeof( classtype_gate )
+
+ gate = classtype_gate()
+ gate.target = 0
+ if obj.cv_data.target != None:
+ gate.target = obj.cv_data.target.cv_data.uid
+
+ if obj.type == 'MESH':
+ gate.dims[0] = obj.data.cv_data.v0[0]
+ gate.dims[1] = obj.data.cv_data.v0[1]
+ gate.dims[2] = obj.data.cv_data.v0[2]
+ else:
+ gate.dims[0] = obj.cv_data.v0[0]
+ gate.dims[1] = obj.cv_data.v0[1]
+ gate.dims[2] = obj.cv_data.v0[2]
+
+ entdata_buffer += [gate]
+
+ elif classtype == 'k_classtype_block':
+ node.classtype = 2
+ entdata_length += sizeof( classtype_block )
+
+ source = obj.data.cv_data
+
+ block = classtype_block()
+ block.bbx[0][0] = source.v0[0]
+ block.bbx[0][1] = source.v0[2]
+ block.bbx[0][2] = -source.v1[1]
+
+ block.bbx[1][0] = source.v1[0]
+ block.bbx[1][1] = source.v1[2]
+ block.bbx[1][2] = -source.v0[1]
+ entdata_buffer += [block]
+
+ elif classtype == 'k_classtype_spawn':
+ node.classtype = 3
+
+ elif classtype == 'k_classtype_water':
+ node.classtype = 4
+
+ elif classtype == 'k_classtype_car_path':
+ node.classtype = 5
+ entdata_length += sizeof( classtype_car_path )
+
+ pn = classtype_car_path()
+ pn.target = 0
+ pn.target1 = 0
+
+ if obj.cv_data.target != None:
+ pn.target = obj.cv_data.target.cv_data.uid
+ if obj.cv_data.target1 != None:
+ pn.target1 = obj.cv_data.target1.cv_data.uid
+
+ entdata_buffer += [pn]
+
+ elif obj.is_instancer:
+ target = obj.instance_collection
+
+ node.classtype = 6
+ entdata_length += sizeof( classtype_instance )
+
+ inst = classtype_instance()
+ inst.pstr_file = emplace_string( F"models/{target.name}.mdl" )
+ entdata_buffer += [inst]
+
+ elif classtype == 'k_classtype_capsule':
+ node.classtype = 7
+
+ elif classtype == 'k_classtype_route_node':
+ node.classtype = 8
+ entdata_length += sizeof( classtype_route_node )
+
+ rn = classtype_route_node()
+ if obj.cv_data.target != None:
+ rn.target = obj.cv_data.target.cv_data.uid
+ if obj.cv_data.target1 != None:
+ rn.target1 = obj.cv_data.target1.cv_data.uid
+
+ entdata_buffer += [rn]
+
+ elif classtype == 'k_classtype_route':
+ node.classtype = 9
+ entdata_length += sizeof( classtype_route )
+ r = classtype_route()
+ r.pstr_name = emplace_string("not-implemented")
+ r.colour[0] = obj.cv_data.colour[0]
+ r.colour[1] = obj.cv_data.colour[1]
+ r.colour[2] = obj.cv_data.colour[2]
+
+ if obj.cv_data.target != None:
+ r.id_start = obj.cv_data.target.cv_data.uid
+
+ entdata_buffer += [r]
+
+ # classtype == 'k_classtype_none':
+ else:
+ node.classtype = 0
+ node.offset = 0
+