go-python / gopy

gopy generates a CPython extension module from a go package.
BSD 3-Clause "New" or "Revised" License
2.05k stars 113 forks source link

gopy: only one function signature arg allowed #332

Open mauserzjeh opened 1 year ago

mauserzjeh commented 1 year ago

First of all, my aim is to be able to load certain assets in memory with multiple goroutines for speed/performance and once an asset is loaded into memory I would like to call a callback function that would be passed from python.

i.e:

What am I doing wrong?

I get the following error when trying to build my package:

gopy: only one function signature arg allowed

$ ./build_importer.sh
go build -v importer

--- Processing package: importer ---
ignoring python incompatible method: importer.func (*importer.Importer).ImportIBSP(assetPath string, filePath string, poolSize uint, callbackIbsp func(importer.LoadedIBSP), callbackMaterial func(importer.LoadedMaterial), callbackXmodel func(importer.LoadedModel)) error: func(assetPath string, filePath string, poolSize uint, callbackIbsp func(importer.LoadedIBSP), callbackMaterial func(importer.LoadedMaterial), callbackXmodel func(importer.LoadedModel)) error: gopy: only one function signature arg allowed: func(assetPath string, filePath string, poolSize uint, callbackIbsp func(importer.LoadedIBSP), callbackMaterial func(importer.LoadedMaterial), callbackXmodel func(importer.LoadedModel)) error
no LibDir -- copy from IncDir: C:/Users/soma/AppData/Local/Programs/Python/Python311/Include
no LibPy -- set to: python311
no LibDir -- copy from IncDir: C:/Users/soma/AppData/Local/Programs/Python/Python311/Include
no LibPy -- set to: python311

--- building package ---
gopy.exe build -output=importer -vm=python importer
goimports -w importer.go
no LibDir -- copy from IncDir: C:/Users/soma/AppData/Local/Programs/Python/Python311/Include
no LibPy -- set to: python311
go build -mod=mod -buildmode=c-shared -o importer_go.pyd .
C:\Users\soma\AppData\Local\Programs\Python\Python311\python.exe build.py
Doing windows sed hack to fix declspec for PyInit
CGO_CFLAGS=-IC:/Users/soma/AppData/Local/Programs/Python/Python311/Include -fPIC -Ofast
CGO_LDFLAGS=-LC:/Users/soma/AppData/Local/Programs/Python/Python311/Include -lpython311
go build -mod=mod -buildmode=c-shared -o _importer.cp311-win_amd64.pyd .

this is the part of the code the error talks about:

// ImportBSP
func (imp *Importer) ImportIBSP(assetPath, filePath string, poolSize uint, callbackIbsp func(LoadedIBSP), callbackMaterial func(LoadedMaterial), callbackXmodel func(LoadedModel)) error {
    ibsp := assets.IBSP{}
    err := ibsp.Load(filePath)
    if err != nil {
        return errorLogAndReturn(err)
    }

    wp := newWorkerPool(poolSize)

    wg := sync.WaitGroup{}
    for _, mat := range ibsp.Materials {
        wg.Add(1)

        wp.addTask(func() {
            defer wg.Done()

            version := assets.VERSION_COD1
            if ibsp.Header.Version == assets.IBSP_VER_v4 {
                version = assets.VERSION_COD2
            }
            loadedMaterial, err := imp.loadMaterial(assetPath, mat.GetName(), version)
            if err != nil {
                errorLog(err)
                return
            }

                        // python callback function
            callbackMaterial(loadedMaterial) // <--
        })

    }

    wg.Wait()

        // python callback function
    callbackIbsp(LoadedIBSP{
        IBSP: ibsp,
    }) // <--

    for _, ent := range ibsp.Entities {
        wg.Add(1)

        wp.addTask(func() {
            defer wg.Done()

            xmodelFilePath := path.Join(assetPath, assets.ASSETPATH_XMODEL, ent.Name)
            loadedModel, err := imp.ImportXModel(assetPath, xmodelFilePath)
            if err != nil {
                errorLog(err)
                return
            }

            loadedModel.Angles = ent.Angles
            loadedModel.Origin = ent.Origin
            loadedModel.Scale = ent.Scale

                        // python callback function
            callbackXmodel(loadedModel) // <--
        })
    }

    wg.Wait()

    wp.stop()
    return nil
}

// ImportXModel
func (imp *Importer) ImportXModel(assetPath, filePath string) (LoadedModel, error) {
    xmodel := assets.XModel{}
    err := xmodel.Load(filePath)
    if err != nil {
        return LoadedModel{}, errorLogAndReturn(err)
    }

    lod0 := xmodel.Lods[0]
    xmodelPartFilePath := path.Join(assetPath, assets.ASSETPATH_XMODELPARTS, lod0.Name)
    xmodelPart := &assets.XModelPart{}
    err = xmodelPart.Load(xmodelPartFilePath)
    if err != nil {
        errorLog(err)
        xmodelPart = nil
    }

    xmodelSurfFilePath := path.Join(assetPath, assets.ASSETPATH_XMODELSURFS, lod0.Name)
    xmodelSurf := assets.XModelSurf{}
    err = xmodelSurf.Load(xmodelSurfFilePath, xmodelPart)
    if err != nil {
        return LoadedModel{}, errorLogAndReturn(err)
    }

    loadedMaterials := []LoadedMaterial{}
    if xmodel.Version == assets.VERSION_COD2 || xmodel.Version == assets.VERSION_COD4 {
        for _, mat := range lod0.Materials {
            loadedMaterial, err := imp.loadMaterial(assetPath, mat, int(xmodel.Version))
            if err != nil {
                errorLog(err)
                continue
            }

            loadedMaterials = append(loadedMaterials, loadedMaterial)
        }
    }

    loadedModel := LoadedModel{
        XModel:     xmodel,
        XModelSurf: xmodelSurf,
        Materials:  loadedMaterials,
        Angles:     assets.Vec3{},
        Origin:     assets.Vec3{},
        Scale: assets.Vec3{
            X: 1,
            Y: 1,
            Z: 1,
        },
    }

    if xmodelPart != nil {
        loadedModel.XModelPart = *xmodelPart
    }

    return loadedModel, nil
}

// loadMaterial
func (imp *Importer) loadMaterial(assetPath, materialName string, version int) (LoadedMaterial, error) {
    materialFilePath := path.Join(assetPath, assets.ASSETPATH_MATERIALS, materialName)
    material := assets.Material{}
    err := material.Load(materialFilePath, version)
    if err != nil {
        return LoadedMaterial{}, errorLogAndReturn(err)
    }

    loadedTextures := map[string]assets.IWI{}
    for _, tex := range material.Textures {
        if _, ok := loadedTextures[tex.Name]; ok {
            continue
        }

        textFilePath := path.Join(assetPath, assets.ASSETPATH_TEXTURES, tex.Name)
        texture := assets.IWI{}
        err := texture.Load(textFilePath)
        if err != nil {
            errorLog(err)
            continue
        }

        loadedTextures[tex.Name] = texture
    }

    return LoadedMaterial{
        Material: material,
        Textures: loadedTextures,
    }, nil
}
mauserzjeh commented 1 year ago

If I only pass one callback function it doesn't throw the error. How could I solve this problem when I need to call multiple callback functions, depending on the type of asset loaded?