Привет, вот код аддона для Блендер 3.3.0, потом скажу что делать:

bl_info = {
    "name": "F1 Track Reducemechanics",
    "blender": (3, 3, 0),
    "category": "3D View",
}

import struct
import bpy
from bpy.types import Operator
from mathutils import Matrix, Vector
from bpy.types import Panel



class F1ImportTrackOperator(bpy.types.Operator):
    """Import F1 Track"""
    bl_idname = "f1.import_track"
    bl_label = "Import Track"
    bl_options = {'REGISTER', 'UNDO'}

    filepath: bpy.props.StringProperty(subtype="FILE_PATH")

    def execute(self, context):
        import_track(self.filepath)
        return {'FINISHED'}

    def invoke(self, context, event):
        context.window_manager.fileselect_add(self)
        return {'RUNNING_MODAL'}

class F1ExportTrackOperator(bpy.types.Operator):
    """Export F1 Track"""
    bl_idname = "f1.export_track"
    bl_label = "Export Track"
    bl_options = {'REGISTER', 'UNDO'}

    filepath: bpy.props.StringProperty(subtype="FILE_PATH")

    def execute(self, context):
        export_track(self.filepath)
        return {'FINISHED'}

    def invoke(self, context, event):
        context.window_manager.fileselect_add(self)
        return {'RUNNING_MODAL'}

def import_track(filename):
    left_points = []
    right_points = []

    with open(filename, 'rb') as f:
        version = struct.unpack('i', f.read(4))[0]

        while True:
            gate_data = f.read(17)
            if not gate_data:
                break
            
            x = struct.unpack('BBB', gate_data[0:3])
            y = struct.unpack('BBB', gate_data[3:6])
            z = struct.unpack('BBB', gate_data[6:9])
            xo = struct.unpack('b', gate_data[9:10])[0]
            yo = struct.unpack('b', gate_data[10:11])[0]
            zo = struct.unpack('b', gate_data[11:12])[0]
            racingAcrossProportion = struct.unpack('B', gate_data[12:13])[0]
            leftNormalX = struct.unpack('b', gate_data[13:14])[0]
            leftNormalZ = struct.unpack('b', gate_data[14:15])[0]
            rightNormalX = struct.unpack('b', gate_data[15:16])[0]
            rightNormalZ = struct.unpack('b', gate_data[16:17])[0]

            # Decompress data
            bX = ((x[0] << 16) + (x[1] << 8) + x[2] - 0x800000) / 200.0
            bY = ((y[0] << 16) + (y[1] << 8) + y[2] - 0x800000) / 200.0
            bZ = ((z[0] << 16) + (z[1] << 8) + z[2] - 0x800000) / 200.0
            
            oX = xo / 50.0
            oY = yo / 100.0
            oZ = zo / 50.0
            
            lx = bX - oX
            ly = bY - oY
            lz = bZ - oZ
            
            rx = bX + oX
            ry = bY + oY
            rz = bZ + oZ
            
            # Печатаем оригинальные точки
            print(f"Original Left Point: ({lx}, {ly}, {lz})")
            print(f"Original Right Point: ({rx}, {ry}, {rz})")
            
            left_points.append(Vector((lx, ly, lz)))
            right_points.append(Vector((rx, ry, rz)))

    mesh_object = create_mesh_from_splines(left_points, right_points)
    apply_global_y_mirror(mesh_object)

def create_mesh_from_splines(left_points, right_points):
    if len(left_points) != len(right_points):
        raise ValueError("Left and right point lists must be the same length.")

    vertices = []
    edges = []
    faces = []

    for i in range(len(left_points)):
        left_coord = left_points[i]
        right_coord = right_points[i]

        vertices.append((left_coord.x, left_coord.z, left_coord.y))  # X, Z, Y
        vertices.append((right_coord.x, right_coord.z, right_coord.y))  # X, Z, Y

        if i < len(left_points) - 1:
            idx1 = i * 2
            idx2 = idx1 + 1
            idx3 = idx1 + 2
            idx4 = idx3 + 1

            edges.append((idx1, idx2))
            faces.append((idx1, idx2, idx4, idx3))

    mesh_data = bpy.data.meshes.new("RaceTrackMesh")
    mesh_data.from_pydata(vertices, edges, faces)
    mesh_data.update()

    mesh_object = bpy.data.objects.new("RaceTrack", mesh_data)
    bpy.context.collection.objects.link(mesh_object)

    return mesh_object

def apply_global_y_mirror(obj):
    bpy.context.view_layer.objects.active = obj
    obj.select_set(True)

    bpy.ops.object.mode_set(mode='OBJECT')
    bpy.ops.transform.mirror(orient_type='GLOBAL', constraint_axis=(False, True, False))
    obj.select_set(False)

def export_track(filepath):
    if "RaceTrack" in bpy.data.objects:
        obj = bpy.data.objects["RaceTrack"]
        mesh = obj.data

        left_points = []
        right_points = []

        for vert in mesh.vertices:
            coord = obj.matrix_world @ vert.co
            if vert.index % 2 == 0:  # Четные индексы - левые точки
                left_points.append(coord)
            else:  # Нечетные индексы - правые точки
                right_points.append(coord)

        if len(left_points) != len(right_points):
            raise ValueError("Left and right points lists must be the same length.")

        with open(filepath, 'r+b') as f:
            f.seek(0)
            version = struct.unpack('i', f.read(4))[0]

            for i in range(len(left_points)):
                f.seek(4 + i * 17)

                left_coord = left_points[i]
                right_coord = right_points[i]

                # Поворачиваем точки на -90 градусов (или другую ось).....
                rotation_matrix = Matrix.Rotation(-1.5708, 4, 'X')
                
                left_rotated = rotation_matrix @ Vector((left_coord.x, left_coord.y, left_coord.z))
                right_rotated = rotation_matrix @ Vector((right_coord.x, right_coord.y, right_coord.z))

                # Восстанавливаем координаты с учетом смещения:
                oX = (right_rotated.x - left_rotated.x) * 0.5
                oY = (right_rotated.y - left_rotated.y) * 0.5
                oZ = (right_rotated.z - left_rotated.z) * 0.5

                # Корректируем координаты, как в импорте
                bX = left_rotated.x + oX
                bY = left_rotated.y + oY
                bZ = left_rotated.z + oZ

                # Кодирование координат
                bX = int(bX * 200 + 0x800000)
                bY = int(bY * 200 + 0x800000)
                bZ = int(bZ * 200 + 0x800000)

                # Запись в файл
                f.write(struct.pack('BBB', (bX >> 16) & 0xFF, (bX >> 8) & 0xFF, bX & 0xFF))
                f.write(struct.pack('BBB', (bY >> 16) & 0xFF, (bY >> 8) & 0xFF, bY & 0xFF))
                f.write(struct.pack('BBB', (bZ >> 16) & 0xFF, (bZ >> 8) & 0xFF, bZ & 0xFF))
                
                # Вывод для проверки
                print(f"Writing: Left ({bX}, {bY}, {bZ}), Right ({bX}, {bY}, {bZ})")

        print("Export completed successfully.")
    else:
        print("RaceTrack object not found.")

class TRANSFER_OT_spline_to_mesh(Operator):
    """Transfer Track_Line Spline to RaceTrack Mesh by reshaping existing RaceTrack"""
    bl_idname = "transfer.spline_to_mesh"
    bl_label = "Transfer Spline to Mesh"
    bl_options = {'REGISTER', 'UNDO'}

    def execute(self, context):
        # Получаем объект Track_Line
        track_line_object = context.scene.track_line_object

        if track_line_object and track_line_object.type == 'CURVE':
            # Получаем ширину из контекста
            width = context.scene.track_width

            # Преобразуем кривую Track_Line в меш
            bpy.context.view_layer.objects.active = track_line_object
            bpy.ops.object.convert(target='MESH')
            new_mesh_object = bpy.context.active_object

            if new_mesh_object and new_mesh_object.type == 'MESH':
                new_vertices = [v.co.copy() for v in new_mesh_object.data.vertices]

                # Получаем RaceTrack
                race_track_name = "RaceTrack"  # Имя вашего объекта RaceTrack
                race_track_object = bpy.data.objects.get(race_track_name)

                if not race_track_object or race_track_object.type != 'MESH':
                    self.report({'ERROR'}, "RaceTrack object not found or is not a MESH.")
                    return {'CANCELLED'}

                race_track_vertices = race_track_object.data.vertices
                race_track_count = len(race_track_vertices)
                track_line_count = len(new_vertices)

                # Проверка чтобы не допустить ошибок по количеству вершин
                if race_track_count == 0 or track_line_count == 0:
                    self.report({'ERROR'}, "One of the objects has no vertices.")
                    return {'CANCELLED'}

                total_needed_points = race_track_count  # Всего точек в RaceTrack
                segment_length = total_needed_points / track_line_count  # Длина сегмента для интерполяции

                # Обновление координат для RaceTrack
                for i in range(track_line_count - 1):
                    start_point = new_vertices[i]
                    end_point = new_vertices[i + 1]

                    # Вычисляем направление и нормализацию
                    direction_vector = (end_point - start_point).normalized()
                    rotation_quaternion = direction_vector.to_track_quat('Z', 'Y')
                    side_vector = rotation_quaternion @ Vector((1, 0, 0)) * (width / 2)

                    # Количество промежуточных точек на основе сегмента
                    num_intermediate_points = round(segment_length)

                    # Заполнение промежуточных точек
                    for j in range(num_intermediate_points):
                        factor = j / num_intermediate_points  # Нормализация от 0 до 1
                        current_point = start_point.lerp(end_point, factor)

                        # Определяем левую и правую точки
                        left_vert = current_point + side_vector
                        right_vert = current_point - side_vector

                        # Зеркаливание по оси Y
                        left_vert.y = -left_vert.y
                        right_vert.y = -right_vert.y

                        # Индекс для RaceTrack
                        race_track_index = i * num_intermediate_points + j

                        # Обновляем оригинальные вершины, если в пределах
                        if race_track_index < race_track_count:
                            # Убедимся, что мы чередуем, чтобы не писать один и тот же индекс...
                            if j % 2 == 0:
                                race_track_vertices[race_track_index].co = left_vert
                            else:
                                race_track_vertices[race_track_index].co = right_vert

                # Обновляем меш
                race_track_object.data.update()

                self.report({'INFO'}, "RaceTrack reshaped successfully using the Track_Line spline.")
                return {'FINISHED'}

        self.report({'ERROR'}, "Track_Line not found or is not a curve.")
        return {'CANCELLED'}
        
class F1TrackBuilderPanel(bpy.types.Panel):
    """Creates a panel for the F1 Track Builder Toolkit"""
    bl_label = "F1 Track Builder Toolkit"
    bl_idname = "PT_F1_Track_Builder"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = 'F1 Track Builder Toolkit'

    @classmethod
    def poll(cls, context):
        return context.scene is not None

    def draw(self, context):
        layout = self.layout
        
        # Операторы импорта и экспорта
        layout.operator(F1ImportTrackOperator.bl_idname, text="Import Track")
        layout.operator(F1ExportTrackOperator.bl_idname, text="Export Track")
        
        layout.label(text="Convert Track_Line to RaceTrack Mesh")

        # Добавим свойство для выбора Track_Line
        row = layout.row(align=True)
        row.prop_search(context.scene, "track_line_object", bpy.data, "objects", text="Track Line")
        
        # Кнопка переноса
        row.operator(TRANSFER_OT_spline_to_mesh.bl_idname, text="Transfer", icon='ARROW_LEFTRIGHT')

        # Поле для ширины трека
        layout.prop(context.scene, "track_width", text="Width")
        

def register():
    bpy.utils.register_class(F1ImportTrackOperator)
    bpy.utils.register_class(F1ExportTrackOperator)
    bpy.utils.register_class(F1TrackBuilderPanel)
    bpy.utils.register_class(TRANSFER_OT_spline_to_mesh)
    
    bpy.types.Scene.track_line_object = bpy.props.PointerProperty(type=bpy.types.Object)
    bpy.types.Scene.track_width = bpy.props.FloatProperty(name="Track Width", default=15.0, min=0.0)

def unregister():
    bpy.utils.unregister_class(F1ImportTrackOperator)
    bpy.utils.unregister_class(F1ExportTrackOperator)
    bpy.utils.unregister_class(F1TrackBuilderPanel)
    bpy.utils.unregister_class(TRANSFER_OT_spline_to_mesh)

    del bpy.types.Scene.track_line_object
    del bpy.types.Scene.track_width
    
    

if __name__ == "__main__":
    register()