Plugin Update use "disklevel" or new PluginID
-
Hi can you please explain me in a nutshell,
how this disklevel works in RegisterObjectPlugin for instance?So lets say I have a plugin, the user saves the scene.
Then I release an update and added a few things and maybe the description also has changed and maybe some ID's have changed.
The user installes now the new plugin version.
When the user would load the saved scene with the new plugin version, the behavior of the plugin is different because some ID's have changed for instance.Can I use disklevel argument in the RegisterObjectPlugin - Method and increase the number.
Or is it better then to use a new PluginID for a bigger update of the Plugin.I tried this disklevel, in the old version it was not set in the RegisterObjectPlugin Method so it is "0".
In the update I set it to "1".
I placed the updated Plugin Folder also to the Plugin Folder it has a different folder name but same PluginID.
So I thought when the scene was saved with disclevel = 0 he loads the old plugin.
But he loads the new plugin.
Or am I completely misunderstanding something here?Cheers Thomas
-
Hello @ThomasB,
Thank you for reaching out to us. The concept of a disk levels is tied to (manually) serializing scene data with c4d.storage.HyperFile, and is metadata for differentiating reading different versions.
This also means that when for example your ObjectDataplugin is storing all data in its data container, i.e., as parameters reflected in thec4d.BaseContainerreturned byBaseList2D.GetData, the concept of a disk level is meaningless to you.Relevant become disk levels only when a c4d.plugins.NodeData derived plugin hook overwrites
NodeData.Read,.Writeand.CopyTo(you must always implement all three of them). InNodeData.Readyou get then passed in the disk level of the node to be loaded. Disk levels are not a mechanism to run multiple plugin versions in parallel, 'load an older plugin' as your posting seems to imply, but to enable newer versions of a plugin to deal with data serialzed by an older version in a different format.So, let us assume we have for example two versions
V1andV2of a plugin of typeFoo, both saving custom data with aReadandWritemethod. We can now imagine that in a simplified analogy, for the same scene and node:Foo.Write[V1]- Writes{"data": (0, 1, 2)}.Foo.Write[V2]- Writes{"data_collection": [(True, 0), (True, 1), (True, 2)]}.
I.e.,
V2saves more data and data in a different form thanV1. In practice this would be data in the form ofHyperFile, but imagining things asdictdata makes a much more tangible example. Disk levels then allow aV2plugin version to also deal with data written byV1version. But the disk level is just metadata, it does not do anything on its own, theV2Foo.Readwould have to actively support bothV1andV2data, as pseudo code:def Read(self, data: dict, diskLevel: int) -> None: """V1 Foo.Read. Reads only V1 data. The data form is: {"data": (0, 1, 2)} """ if diskLevel != 1: raise IOError("Node data is of unsupported version.") points: list[int] | None = data.get("data", None) if points is None: raise IOError("Node contains malformed data.") # Let the read data contribute to the plugin state. self._points: list[int] = points def Read(self, data: dict, diskLevel: int) -> None: """V2 Foo.Read. Has been fashioned to read both V1 and V2 data. The two hypothetical forms are: V1: {"data": (0, 1, 2)} V2: {"data_collection": [(True, 0), (True, 1), (True, 2)]} In practice this would be data in the HyperFile format, this example just illustrates the principle. """ if diskLevel not in (1, 2): raise IOError("Node data is of unsupported version.") points: list[int] | None = [] states: list[bool] | None = [] # Deal with V1 data. if diskLevel == 1: points: list[int] | None = data.get("data", None) if points is None: raise IOError("Node contains malformed data.") states = [True for _ in points] # Deal with V2 data. elif diskLevel == 2: collection: dict[str, list[tuple[bool, int]]] | None = data.get("data_collection", None) if collection is None: raise IOError("Node contains malformed data.") states = [n[0] for n in collection] points = [n[1] for n in collection] # Let the read data contribute to the plugin state. self._states: list[bool] = states self._points: list[int] = pointsIn the front end, this then bubbles up in the form of
c4d.C4DAtom.Readand.Writebut these call just the respectiveNodeDataimplementations in addition to (de-)serializing the data container itself.Cheers,
Ferdinand -
@ferdinand
thank you very much