Привет, вот код аддона для блендер 3.3.0. мне нужно переделать логику экспорта полностью, согласно импорту, так как он выдаёт ошибку. Мне нужно, чтобы перезаписывались те же самые данные, которые были импортированы. Именно в тех же местах. 

Python: Traceback (most recent call last):
  File "C:\Users\USER\AppData\Roaming\Blender Foundation\Blender\3.3\scripts\addons\reducemechanics_editor.py", line 20, in execute
    import_track(self.filepath)
  File "C:\Users\USER\AppData\Roaming\Blender Foundation\Blender\3.3\scripts\addons\reducemechanics_editor.py", line 57, in import_track
    z = struct.unpack('BBB', gate_data[6:9])
struct.error: unpack requires a buffer of 3 bytes


Вот код аддона:

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

import struct
import bpy
from mathutils import Vector

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
            
            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

        # Открытие файла для перезаписи всех нужных данных
        with open(filepath, 'r+b') as f:
            version = struct.unpack('i', f.read(4))[0]  # Чтение версии файла

            # Каждая запись ворот занимает 17 байт
            vertex_size = 17
            position_offset = 4  # Смещение заголовка

            for i in range(len(mesh.vertices) // 2):
                gate_offset = position_offset + (i * vertex_size)

                # Переход к нужному смещению для записи
                f.seek(gate_offset)

                # Получение левой и правой координат из Blender
                left_coord = mesh.vertices[i * 2].co
                right_coord = mesh.vertices[i * 2 + 1].co

                # Преобразование координат для записи в файл
                new_xL = int(((left_coord.x + 0.800000) * 200) + 0x800000)
                new_yL = int(((left_coord.z + 0.800000) * 200) + 0x800000)
                new_zL = int(((left_coord.y + 0.800000) * 200) + 0x800000)

                new_xR = int(((right_coord.x + 0.800000) * 200) + 0x800000)
                new_yR = int(((right_coord.z + 0.800000) * 200) + 0x800000)
                new_zR = int(((right_coord.y + 0.800000) * 200) + 0x800000)

                # Запись новых координат в файл
                f.seek(gate_offset)
                f.write(struct.pack('BBB', (new_xL >> 16) & 0xFF, (new_xL >> 8) & 0xFF, new_xL & 0xFF))
                f.write(struct.pack('BBB', (new_yL >> 16) & 0xFF, (new_yL >> 8) & 0xFF, new_yL & 0xFF))
                f.write(struct.pack('BBB', (new_zL >> 16) & 0xFF, (new_zL >> 8) & 0xFF, new_zL & 0xFF))
                f.write(struct.pack('b', 0))  # Оставляем старый xo
                f.write(struct.pack('b', 0))  # Оставляем старый yo
                f.write(struct.pack('b', 0))  # Оставляем старый zo

                f.write(struct.pack('BBB', (new_xR >> 16) & 0xFF, (new_xR >> 8) & 0xFF, new_xR & 0xFF))
                f.write(struct.pack('BBB', (new_yR >> 16) & 0xFF, (new_yR >> 8) & 0xFF, new_yR & 0xFF))
                f.write(struct.pack('BBB', (new_zR >> 16) & 0xFF, (new_zR >> 8) & 0xFF, new_zR & 0xFF))
                f.write(struct.pack('b', 0))  # Оставляем старый xo
                f.write(struct.pack('b', 0))  # Оставляем старый yo
                f.write(struct.pack('b', 0))  # Оставляем старый zo

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

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'

    def draw(self, context):
        layout = self.layout
        layout.operator(F1ImportTrackOperator.bl_idname, text="Import Track")
        layout.operator(F1ExportTrackOperator.bl_idname, text="Export Track")

def register():
    bpy.utils.register_class(F1ImportTrackOperator)
    bpy.utils.register_class(F1ExportTrackOperator)
    bpy.utils.register_class(F1TrackBuilderPanel)

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

if __name__ == "__main__":
    register()