How to save plugin preferences to 3dm file

Hi everyone,

I have preferences in my plugin like language, unit, default values for objects and these objects can change by user in file. But when I save, close and open file again, of course these changed preferences return default values, because I didn’t save them anywhere. I am wondering what is the best practice to save some .json preferences to .3dm file. There is File3dm object but, it’s not clear for me how to use it.

I basically want to achieve to save this file to 3dm file.

{
   "Preferences": {
   "Unit" : "SI",
   "Language" : "English",
   "DefaultObjectProperty1" : 5,
   "DefaultObjectProperty2" : 3,
   "DefaultObjectProperty3" : 2.5,
   }
}

Then, when user open file again, I want to read preferences from file3dm.

Should I initialize this object or 3dmFile has some implicit methods to save without initalizing?

File3dm file = new File3dm();

Thanks in advance
-Oğuzhan

Hi @oguzhankoral,
One simple way to do it would be to set the properties as document user strings

 File3dm file = new File3dm();
 file.Strings.SetString("Preferences", "Unit", "SI");
 file.Strings.SetString("Preferences", "Language", "English");
 file.Strings.SetString("Preferences", "DefaultObjectProperty1", "5");
 file.Strings.SetString("Preferences", "DefaultObjectProperty2", "3");
 file.Strings.SetString("Preferences", "DefaultObjectProperty3", "2.5");
 file.Write(@"D:\myFile.3dm", 6);

It would show up in Rhino Document as user strings, which can be parsed
image

You could also read it from File3dm

 File3dm myFile = File3dm.Read(@"D:\myFile.3dm");
 string[] entryNames =  myFile.Strings.GetEntryNames("Preferences");

Hi @Darryl_Menezes,

Thanks for your answer. You are basically open file and save it in code lines, and read again. It’s totally clear. But I want to reach file in runtime and manipulate values while user changes. How can I reach File3dm object in runtime by using RhinoDoc.ActiveDoc instead of initialize it by new File3dm() ?

FileWriteOptions fileWriteOptions = new FileWriteOptions();
fileWriteOptions.WriteUserData = true;
RhinoDoc.ActiveDoc.Write3dmFile("a", fileWriteOptions); 

What does it? Is there any relation between File3dm and ActiveDoc ?

Best

You could set user strings to RhinoDoc as well. And when you save file, the strings will be saved as well.

RhinoDoc.ActiveDoc.Strings.SetString("Preferences", "Unit", "SI");

the Write3dmFile() writes your active Rhino document to a given path. Just like the “SaveAs” button.

1 Like

Hi @Darryl_Menezes,

This can help, thanks. I want to extend this discussion with PlugInData class. What about it? Is it possible to keep this values inside of it more elegant way. Because I am wondering this preferences have actionability with anyone by using Document User Text panel. Everyone can change values in this time. They can change 5 to “dsdfsj” string. And it can cause runtime errors for my plugin.

@dale, do you have any additional insight about this besides suggestion of @Darryl_Menezes’s ?

Best,
-Oğuzhan

There are virtual functions on your plugin class specifically for this purpose. I would recommend using these for writing your custom document data instead of the above approach. See the document userdata section in this article and please let us know if you still have questions.

2 Likes

Hi @stevebaer,

Thanks for your advice. It seems your advice will work. But I have small problem with ArchivableDictionary. I am simply tries to save plugin values ArchivableDictionary at runtime and save them by using overriden WriteDocument methods. When I open saved file and try to read values, they coming like object typed whatever their type are. I couldn’t Set values when I read. I put note foreach loop in the ReadDocument method.

private ArchivableDictionary archivableDictionary;

/// <summary>
/// Called when Rhino is saving a .3dm file to allow the plug-in to save document user data.
/// </summary>
public void WriteDocument(RhinoDoc doc, BinaryArchiveWriter archive, FileWriteOptions options)
{
    archive.Write3dmChunkVersion(MAJOR, MINOR);
    archive.WriteDictionary(archivableDictionary);
}

/// <summary>
/// Called whenever a Rhino document is being loaded and plug-in user data was
/// encountered written by a plug-in with this plug-in's GUID.
/// </summary>
public void ReadDocument(RhinoDoc doc, BinaryArchiveReader archive, FileReadOptions options)
{
   archive.Read3dmChunkVersion(out var major, out var minor);
    if (MAJOR == major && MINOR == minor)
    {
        // Always read user data even though you might not use it...
        var dic = archive.ReadDictionary();

         if (null != dic && !options.ImportMode && !options.ImportReferenceMode)
          {
                foreach (var item in dic)
                {
                    // I want to set them back again, but Set method
                    // doesn't cast automatically object typed types.
                    archivableDictionary.Set(item.Key, item.Value);          
                }
            }
      }
}

OR, do you have any other advice instead of using ArchivableDictionary.

Best,
-Oğuzhan

Why aren’t you just setting archivableDictionary to what you read from the archive?

archivableDictionary = archive.ReadDictionary();

@stevebaer,

I exactly did like this, sorry for ignoring update the topic that is already solved.
Thanks