Plugin Data Guidance

Is there any guidance on reading/writing a growing amount of plugin data?

I’ve gone over some of the code in the samples repo → rhino-developer-samples/rhinocommon/cs/SampleCsUserData/SampleCsUserDataPlugIn.cs at 8 · mcneel/rhino-developer-samples · GitHub but they are pretty simplistic.

Just wanted to know if there’s any tips for managing this, specifically:

  1. How to control a growing number of properties being read/written? We have been serialising classes to JSON and writing as string, is there any reason not to do this? (over read/writing each field?)
  2. Clever tips for to manage versioning? At the moment we keep adding more if statements as we increment minor version numbers.
  3. Approach to gracefully upgrading 3dm files created from previous plugin versions? We have some methods that checks major minor versions and does stuff, but I can see it getting unwieldy…

Any advice would be appreciate!

  1. I wouldn’t worry about growing JSON strings, unless you’re writing hundreds of megabytes of data. If you do, I have a few tips, so let me know if that is the case.
  2. You’re using versioning: that is great! Keep doing that. You want to be prepared for backward compatibility, so if a newer version of your plug-in loads an older file, the user is upgraded gracefully. I remember, like you, having a large number of if-statements to support older versions. You may decide at some point to break your backward compatibility, but that will affect your users so be careful.
  3. Once a user loads an older file in a newer plug-in version, make sure that your in-memory data model is always up to date with the latest version of your plug-in. This means that once they save the file, the information is up-to-date automatically.

It sounds like you’re doing everything right, and having backward compatibility can be non-trivial to support.

2 Likes

Nah, no where near the 100s of MB range, yet :grin:

But thanks @menno for your reply! It’s reassuring, even if its just “keep calm and carry on” – breaking backwards compatibility may actually be beneficial in the short term as we iterate quickly. At the moment its relatively easy for users to recreate models from scratch with new versions of the plugin, rather than having to write a bunch of code to maintain compatibility…

1 Like

@menno maybe you could answer follow up question – should we be using the BeginWrite3dmChunk?

public bool BeginWrite3dmChunk(uint typecode, int majorVersion, int minorVersion), specifically the typecode, basically reserving sections?

Use the Write3dmChunkVersion - it’s takes up less space and you don’t need to call EndWrite3dmChunk. When reading, use Read3dmChunkVersion. It is best to write/read this as the first entry, and when reading decide based on the version what else you need to read.

https://developer.rhino3d.com/api/rhinocommon/rhino.fileio.binaryarchivewriter/write3dmchunkversion

https://developer.rhino3d.com/api/rhinocommon/rhino.fileio.binaryarchivereader/read3dmchunkversion

1 Like

We’re using Write3dmChunkVersion at the moment, but just wondering what the usefulness of setting typecode in BeginWrite3dmChunk:

bool rc = binary_archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK, &major_version, &minor_version);

(this is from one of the C++ examples SampleSharedUserData.cpp, but assume it can be used similarly in C#). The reason I ask is if there’s any benefit from doing something like this? i.e:

public enum MyPluginChunkType : uint
{
    DesignData = 1,
    ProjectData = 2
}

if (archive.BeginWrite3dmChunk((uint)MyPluginChunkType.DesignData, 1, 0))
{
        // Write design data
        archive.EndWrite3dmChunk();
}

Thanks @menno! Appreciate your replies :slightly_smiling_face:

It would allow you to structure your information a bit more in the 3dm file.
Personally, I have never had the need to do this, but I can see the benefit in structuring things, for example if you have various classes with plug-in settings or something like that.

1 Like

Awesome, last questions @menno ~ am I correct in thinking that:

  1. Each class that calls archive.Write3dmChunkVersion(MAJOR, MINOR); manages its own version?

  2. If you’re writing stuff, you have to maintain the order? I write A, B, C – if I no longer need B, I have to leave it there to maintain the order?

    public void WriteDocument(BinaryArchiveWriter archive)
    {
      archive.Write3dmChunkVersion(MAJOR, MINOR);
      archive.WriteString("A");
      archive.WriteString("B");
      archive.WriteString("C");
    }
    public void WriteDocument(BinaryArchiveWriter archive)
    {
      archive.Write3dmChunkVersion(MAJOR, MINOR);
      archive.WriteString("A");
      archive.WriteString(string.Empty); //No longer needed but maintains order
      archive.WriteString("C");
    }

Or is this just a case where you change major number since the format of the chunks changed?

    private const int MAJOR = 2; //Was previously 1
    private const int MINOR = 0;

    public void WriteDocument(BinaryArchiveWriter archive)
    {
      archive.Write3dmChunkVersion(MAJOR, MINOR);
      archive.WriteString("A");
      //archive.WriteString(string.Empty);
      archive.WriteString("C");
    }

At the moment we aren’t incrementing the major number – maybe we should be?