Solved Bug with GetLink/SetLink & Hyperfile

Hello,
I think that I've found a bug. This is a variation of the same unsolved issue from this topic from a month ago. In the code example below, it is writing an object's CTrack (Position . X/Track) to a Hyperfile, so for it to work an object must have an animation track in position X and be selected. It prints correctly from the BaseContainer prior to saving. When loading the Hyperfile however, the link prints as None. As mentioned in the previous topic, CTracks are of type C4DAtom and I'm passing/retrieving it with the same ID, so it should be writing and reading correctly. If I use BaseContainer.SetString instead of BaseContainer.SetLink, it works.

If there is a workaround storing a CTrack to a Hyperfile, I'd really appreciate the help. This is a very important part of my current project. Thank you.

import c4d, os
from c4d import documents, gui

key = 12345
OBJ_BC_ID = 90210

desktopPath = c4d.storage.GeGetC4DPath(c4d.C4D_PATH_DESKTOP)
defaultFilepath = os.path.join(desktopPath, "test.file")

def load_hyperfile():
    global doc
    path = c4d.storage.LoadDialog(def_file=defaultFilepath)

    hf = c4d.storage.HyperFile()
    if not hf.Open(ident=key, filename=path, mode=c4d.FILEOPEN_READ,
                   error_dialog=c4d.FILEDIALOG_NONE):
        print "Could not read file."
        return False
    bc = hf.ReadContainer()

    for cid, value in bc[OBJ_BC_ID]:
        print cid, value

    hf.Close()


def save_hyperfile(obj):
    path = c4d.storage.SaveDialog(title="Save your Hyperfile",force_suffix="file",def_file=defaultFilepath)

    bc = c4d.BaseContainer()
    objBc = c4d.BaseContainer()
    xPos = c4d.DescID(c4d.DescLevel(903, 23, 5155), c4d.DescLevel(1000, 19, 23))
    pxTrack = obj.FindCTrack(xPos)
    objBc.SetLink(OBJ_BC_ID,pxTrack)
    #objBc.SetString(OBJ_BC_ID,"Test String") # The Hyperfile works when using a String.
    bc.SetContainer(OBJ_BC_ID, objBc)
    print objBc[OBJ_BC_ID]

    hf = c4d.storage.HyperFile()
    if not hf.Open(ident=key, filename=path, mode=c4d.FILEOPEN_WRITE,
                   error_dialog=c4d.FILEDIALOG_ANY):
        print "Could not write file."
        return False
    else:
        print "Wrote file at %s"%path

    hf.WriteContainer(bc)

    for cid, value in bc[OBJ_BC_ID]:
        print cid, value

    hf.Close()

class Dlg(gui.GeDialog):
    def __init__(self):
        global doc,obj

    def CreateLayout(self):
        self.SetTitle('Hyperfile')
        self.GroupBegin(1001, c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, 1, 2)
        self.AddButton(1002, c4d.BFH_CENTER | c4d.BFH_SCALE | c4d.BFV_TOP, initw=0, inith=20, name="Save Hyperfile")
        self.AddButton(1003, c4d.BFH_CENTER | c4d.BFH_SCALE | c4d.BFV_TOP, initw=0, inith=20, name="Load Hyperfile")
        self.GroupEnd()
        return True

    def Command(self, id, msg):
        if id == 1002:
            save_hyperfile(obj)
        elif id == 1003:
            load_hyperfile()
        return True

def main():
    global doc,obj,dlg
    doc = documents.GetActiveDocument()
    obj = doc.GetActiveObject()
    if obj is None:
        gui.MessageDialog("Please select an object to save.")
        return
    dlg = Dlg()
    dlg.Open(c4d.DLG_TYPE_ASYNC, xpos=-2, ypos=-2, defaultw=200, defaulth=130)

if __name__=='__main__':
    main()

hello,

A BaseLink is like a shortcut or an alias. if you only save the shortcut you will have nothing. If i save my shortcut and send it to you, you will not be able to start the application.

Instead what i suggest is

  • isolate the object (as in the previous post) in a temporary document. (or create a null, and copy the track on it)
  • create in the BaseContainer of the document a BaseLink that will point to your track.
  • save the temporary document.

This way, when you open the file, you know where to get your BaseLink.
You can also have different BaseLink pointing to different tracks of different objects.

you can have a look at the BaseLink Manual

Cheers,
Manuel

MAXON SDK Specialist

MAXON Registered Developer

hello,

A BaseLink is like a shortcut or an alias. if you only save the shortcut you will have nothing. If i save my shortcut and send it to you, you will not be able to start the application.

Instead what i suggest is

  • isolate the object (as in the previous post) in a temporary document. (or create a null, and copy the track on it)
  • create in the BaseContainer of the document a BaseLink that will point to your track.
  • save the temporary document.

This way, when you open the file, you know where to get your BaseLink.
You can also have different BaseLink pointing to different tracks of different objects.

you can have a look at the BaseLink Manual

Cheers,
Manuel

MAXON SDK Specialist

MAXON Registered Developer

My apologies: I didn't understand how BaseLink worked and this clarified things. Thank you!