World data issue



  • On 30/06/2013 at 07:47, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:   R14 
    Platform:   Windows  ;   
    Language(s) :     C++  ;

    ---------
    Hi Folks,

    I've got a little issue with my plugin. I have some structs holding some data that are used between different classes. The plugin is an objectdata plugin with some other buried classes (e.g. a dialog).

    The problem is that if I add two or more objects into the scene (two or more of my object plugin) all the additional objects I add seem to read the struct data from the first object. How do I stop this from happening?

    Example of how it's setup:

      
    // The data is inited in the plugin's main class constructor   
      
    struct MyStruct   
    {   
        LONG Count;   
        LONG Width;   
        LONG Height;   
    }MStr;   
      
    // I use "MStr.Count = 10" to access/change the data from other classes etc   
    

    Thanks,

    WP.



  • On 30/06/2013 at 08:43, xxxxxxxx wrote:

    They're all accessing the same object. What you describe is the expected behaviour. Have you heard
    about class members/attributes?

    -Niklas



  • On 30/06/2013 at 08:53, xxxxxxxx wrote:

    Hi Niklas,

    are you referring to class level variables?

    WP.



  • On 30/06/2013 at 15:59, xxxxxxxx wrote:

    class MyPluginObject::ObjectData  
    {  
    public:  
    MyStruct  m_cMyStruct;  
    ...  
    };  
      
    // Inside your class instance methods:  
    m_cMyStruct.Count = 10;  
      
    // From other classes:  
    MyPluginObject* pMyPluginObject = something;  // passed in as a method argument perhaps  
    pMyPluginObject->m_cMyStruct.Count = 10;
    

    Of course, this is not the most secure way to do this.  We're supposed to make member variables private or protected and access them using public methods in the class (the so-called Get/Set type of methods).



  • On 02/07/2013 at 06:02, xxxxxxxx wrote:

    Ok, after many hours of copying/pasting and building a new "data centre", I'm left with a crashing instance that's occurring when I try to access the struct through another class that's following a pre-declaration. Probably doesn't make much sense, so, here's an example!:

      
    struct MyStruct   
    {   
        LONG Number;   
    };   
      
    class MainClass; // pre-declared MainClass   
      
    class MyDialog : public GeDialog   
    {   
        MainClass *MC;   
        MyFunction(void);   
    };   
      
    class MainClass : public ObjectData   
    {   
        MyStruct MyStr;   
        MainClass(void)   
        {   
            MyStr.Number = 10; // this appears to be working fine   
        }   
    };   
      
    MyDialog::MyFunction(void)   
    {   
        GePrint("Structs number = " + LongToString(MC->MyStr.Number)); // crashes cinema   
    }   
    

    The code compiles, but crashes cinema when the dialog is called. GePrint's show it's crashing at the first line to do with MC->MyStr etc... In the example case above, the GePrint would not print. How do you solve this?

    EDIT 1: Or, instead of pre-declaring, am I going to have to declare the MainClass above the MyDialog, but put it's functions below?
    EDIT 2: nope, the above didn't work.

    WP.



  • On 02/07/2013 at 12:02, xxxxxxxx wrote:

    You are accessing a Null (or un-initialized) pointer.  If you change "*MC" to "MC" to make it an instance of the class instead of a pointer to one, it'll work...

      
    struct MyStruct  
      
    {  
      LONG Number;  
    };  
      
    class MainClass;  // pre-declared MainClass  
      
    class MyDialog : public GeDialog  
    {  
      MainClass MC;        // <-- changed to instance, from pointer  
      MyFunction(void);  
    };  
      
    class MainClass : public ObjectData  
    {  
      MyStruct MyStr;  
      MainClass(void)  
      {  
          MyStr.Number = 10;  // this appears to be working fine  
      }  
    };  
      
    MyDialog::MyFunction(void)  
    {  
      GePrint("Structs number = " + LongToString(MC.MyStr.Number)); // (no longer) crashes cinema  
    }  
    


  • On 04/07/2013 at 01:56, xxxxxxxx wrote:

    Thanks Giblet, that's done the trick.

    It's taken some time to shuffle everything around, but it appears to be heading in the right direction now. Thanks all,

    WP.



  • On 04/07/2013 at 03:13, xxxxxxxx wrote:

    Are you sure it did the trick? For this code to compile, the "MainClass" must have already been
    defined (not only declared) to participate as a direct member in the GeDialog class. So you either
    write

    class MainClass : public ObjectData {
        MyStruct MyStr;
        // ...
    };
    class MyDialog : public GeDialog {
        MainClass MC;
        // ...
    };
    

    Or you keep the pointer and allocate it before accessing it.

    class MainClass : public ObjectData {
        MyStruct MyStr;
        // ...
    };
    class MyDialog : public GeDialog {
        MainClass* MC;
        // ...
        void MyFunction();
    };
    void MyDialog::MyFunction()
    {
        if (!MC) MC = gNew MainClass;
        GePrint("Structs number = " + LongToString(MC->MyStr.Number)); // (no longer) crashes cinema
    }
    

    Be sure to deallocated it when it is no longer needed. Though one last question: Do you really
    want to store an ObjectData in your dialog? Why?

    -Niklas



  • On 04/07/2013 at 09:59, xxxxxxxx wrote:

    Hi Niklas,

    it compiled, and earlier today it seemed to be doing what I had wanted... but trying it just then again and it may not be working correctly. I did make an adjustment to another part of the plugin code earlier today (after I thought I saw it working) so not sure if that has done something. Will need to investigate.

    Re: your last question. It's a dialog buried in an ObjectData. I've done it just to limit the amount of plugin ID's I'm using. Not particularly a fan of having to register everything.

    WP.



  • On 04/07/2013 at 12:34, xxxxxxxx wrote:

    Hi.

    Caution. You are not supposed to create instances of ObjectData or derived classes just like that. Cinema does this for you when a object of your plugin is created and also associates it with the corresponding BaseObject.

    IIRC there is a message which can be used to retrieve arbitrary data. MSG_RETRIEVEPRIVATEDATA.

    But i think you can also retrieve a pointer to your ObjectData via
    NodeData* GeListNode::GetNodeData(LONG index = 0) const = 0
    You have to cast the result and also make sure that the object is really from your plugin of course.

    kuroyume0161's example was just right for attaching individual data to each of your objects. See above for how to access the data from the dialog.



  • On 04/07/2013 at 16:01, xxxxxxxx wrote:

    I have to concur with others above... when I made my other post above, I quite frankly didn't even notice that it was a ObjectData derived class.  I also didn't try compiling my 'fix'... I simply looked at your code and noted that you were accessing an uninitialized pointer and gave a 'quick fix' answer.



  • On 05/07/2013 at 10:52, xxxxxxxx wrote:

    Just to be clear - the dialog is not registered. By 'buried' I don't mean it's inside the ObjectData class code, it has it's own GeDialog class.

    But never-the-less, is that an issue? Should I be registering* the GeDialog class as a separate plugin (with a plugin ID)?

    It doesn't really make any difference to me, was just a coding perk I thought I could get away with by not having to register everything..

    WP.

    *EDIT: I mean register a commanddata to open the dialog... the terms and intricicies of this programming business are quite the maze in the learning process...!



  • On 05/07/2013 at 19:34, xxxxxxxx wrote:

    The only time you really need an ID (does not need to be a plugin ID) for a dialog is if you intend for it to be restorable (in the layout) which is limited to Command plugins.  Only plugins need a plugin ID.



  • On 11/07/2013 at 12:13, xxxxxxxx wrote:

    I nervously think I've managed to get (stumble over..!) how to do this one. Please correct me if I'm wrong, but for any other newbies who may be interested, I did:

      
    MYPLUGIN *MYP = (MYPLUGIN* )obj->GetNodeData();   
    

    It's turned out to be two lines of code (MYP is declared at class level). Thanks for the above help folks - I got there! - cheers,

    WP.



  • On 26/09/2013 at 03:10, xxxxxxxx wrote:

    Hi Folks,

    what would cause a struct like the example below to stop my plugin from displaying in Cinema's menus?

      
    // this compiles & works fine:   
    struct MyStruct   
    {   
        LONG SCount;   
    };   
      
    // this compiles, but then the plugin won't   
    // show up in menus or as toolbar shortcuts   
    struct MyStruct   
    {   
        LONG SCount;   
    }MStr;    // the difference being this line - so I can access it on a world level   
    

    I've spent weeks on trying to rectify one struct, that's coded no differently from all the others I have (except for it's name and what's in it). When I put the "}MStr;" at the end of any other struct, it works fine, but for one struct only it stops the plugin from coming up in Cinema.

    I don't use "}MStr;" on every struct btw. =)

    The struct isn't being used anywhere at present. There's nothing else in the plugin with the same name, it's not referenced anywhere, no instance of it is made anywhere...

    What are some possible scenarios that could be causing this to happen? It's happening on one struct only... that's not even used, and is in the same location as other structs that are being used (i.e. all are in one header file)!?

    WP.



  • On 26/09/2013 at 04:52, xxxxxxxx wrote:

    Hi WP,

    Are you absolutely sure your struct only contains a LONG data member? This issue usually happens
    when using a class from the Cinema 4D API globally (eg. a String ). The actual reason for this is, that
    the String class constructor is called before the function-pointer table is loaded.

    Best,
    -Niklas



  • On 26/09/2013 at 05:11, xxxxxxxx wrote:

    Niklas, I'd be a mess without some of the input you've given!

    This does indeed seem to be the cause. There are two Strings in the struct. With them both commented out, it shows.

    What is the correct way to include the struct in this case then? Or where is the best place?

    Two things to note:

    1 - The c4d_strings.h file is included before the struct header.
    2 - Other structs have strings too, but they're instanced/made in other classes.

    WP.



  • On 26/09/2013 at 20:33, xxxxxxxx wrote:

    Ok, I've noticed that using a std::vector < String > seems to counter the non-displaying issue. So, I'm using the [0] index to hold my string value. Don't know if this is a particularly elegant solution, but it's working enough for me to see things again...

    WP.



  • On 27/09/2013 at 00:40, xxxxxxxx wrote:

    You just have to make sure to not construct a String object before the C4DOS pointer is initialized.
    An std::vector<String> is just an array internally, and when it is being constructed it does not contain
    any items, therefore no String is constructed. The best place to construct the Strings you need is probably
    in PluginStart(). However, you need to deallocate them before the C4DOS pointer becomes invalid!

    class MyStruct {
        String a;
        String b;
    } *MyStr = NULL;
      
    Bool PluginStart() {
        MyStr = gNew MyStruct;
    }
      
    void PluginEnd() {
        gDelete(MyStr);
    }
    

    If you use an std::vector, you must flush it in PluginEnd().

    https://plugincafe.maxon.net/topic/7188/8217_cinema-not-loading-plugin-with-global-string&KW=string+global&PID=34231#34231

    Best,
    -Niklas


Log in to reply