Best place for a document-specific object store to live

For every object in the scene I want to keep a corresponding instance of MyClass in memory. When new objects are added, deleted, or existing objects are changed, I want to update the corresponding instance.
Right now I have a dict with RhinoObject Guid’s as keys, and MyClass as values. That part works great.

Where is the best place for such a store to live? On the Plugin instance? How should I handle RhinoDoc changes then? Especially I saw a comment in the docs, mentioning RhinoDoc could change on Mac: when does this happen?
How can I ensure my store is scene/document-specific?

Follow up question: am I correct in accessing such a store on the Plugin instance like so:

public class MyOtherClass {
    public MyPlugin MyPlugin;
    public MyStore MyStore { get => MyPlugIn.MyStore; }

    public MyOtherClass() {
        // Find the Plugin instance
        Guid guid = PlugIn.IdFromName("MyPluginName");
        MyPlugIn = (MyPlugin)PlugIn.Find(guid);
    }
}

Hi @aske,

You have several options.

You’ve mentioned the first one, which is to store your data on your plug-in object.

Or, you can use a singleton. For example:

public class MyDataTable
{
  /// <summary>
  /// Private constructor
  /// </summary>
  private MyDataTable() {}

  /// <summary>
  /// The one and only MyDataTable object
  /// </summary>
  private static MyDataTable g_my_table;

  /// <summary>
  /// Returns the one and only MyDataTable object
  /// </summary>
  public static MyDataTable Instance => g_my_table ?? (g_my_table = new MyDataTable());
}

Or, you can store your table in the Rhino document runtime dictionary. For example:

public class MyDataTable
{
  /// <summary>
  /// Public constructor
  /// </summary>
  public MyDataTable(uint documentSerialNumber)
  {
    DocumentSerialNumber = documentSerialNumber;
  }

  /// <summary>
  /// The runtime serial number of the document that owns this table.
  /// </summary>
  public uint DocumentSerialNumber { get; }

  /// <summary>
  /// The document that owns this table.
  /// </summary>
  public RhinoDoc Document => RhinoDoc.FromRuntimeSerialNumber(DocumentSerialNumber);
}

//...

protected override Result RunCommand(RhinoDoc doc, RunMode mode)
{
  var my_table = doc.RuntimeData.GetValue(typeof(MyDataTable), rhinoDoc => new MyDataTable(rhinoDoc.RuntimeSerialNumber));
  if (null != my_table)
  {
    // TODO...
  }
  return Result.Success;
}

Their may be other ways too.

There are a number of document-related events you can subscribe to.

The Mac support multiple documents. So if you intend your plug-in to run in Rhino for Mac, then you need to ensure your plug-in data takes multiple documents into account. A good way of doing this is to store your data in the document’s runtime dictionary (as I have shown above).

Does this help?

– Dale

1 Like

Thanks for the great writeup Dale!
I did my quick and dirty implementation on the plugin. I’ll move it to the runtime dictionary as suggested.

Hi @dale and @aske ,

I was trying to your second suggestion but after save-close and open again same document, this RuntimeData is disappearing. It’s also be emphasized in RhinoDoc.RuntimeData Property "Note well: This data will be dispose with the document and does not get serialized."

How possibly store plugin data in the RuntimeData dictionary alternatively singleton object. Because I don’t want to use global singleton object.

Best,
-Oğuzhan

I think you need to manually handle that in your Plugin.ReadDocument and Plugin.WriteDocument. You can read/write your data there. See this topic:

@aske,

I have already achieve functionality with this methods by using singleton special dictionary object. This methods Plugin.ReadDocument and Plugin.WriteDocument is firing when document is opening before plugin initialized.

protected override void ReadDocument(RhinoDoc doc, BinaryArchiveReader archive, FileReadOptions options)
{
    Doc = doc;
    archive.Read3dmChunkVersion(out var major, out var minor);
    if (MAJOR == major && MINOR == minor)
    {
        // For singleton
        PluginDictionaryTable pluginDictionaryTable = PluginDictionaryTable.Instance;
        pluginDictionaryTable.ReadDocument(doc, archive, options);
    }
}

That’s why global singleton objects is working on this. But I am looking a way get values from document by don’t using singleton objects. Trying to understand it is possible or not.

-Oğuzhan

Hi @oguzhankoral,

I am confused. If storing your plug-in’s document data on your plug-in object, or on a singleton, works, then why just use it?

– Dale

Hi @dale,

You are right, I was just avoid global object. Because every layer of plugin could reach this object. But if there is no any option, I will use it like this…

Thanks,
-Oğuzhan