Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Problems with R16 [SOLVED]

    SDK Help
    0
    16
    1.1k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • H
      Helper
      last edited by

      On 10/10/2014 at 04:43, xxxxxxxx wrote:

      Nope, the sdk examples compile fine. I only noticed this when I ported my own project to R16. In a scenehook it is triggered so often that it makes debugging impossible that's why it started bothering me and when I got a crash at bt->TestBreak() I thought I'd better ask.

      I am only checking under windows myself right now.

      1 Reply Last reply Reply Quote 0
      • H
        Helper
        last edited by

        On 10/10/2014 at 04:45, xxxxxxxx wrote:

        Ah, if you are under Windows, could you provide me with a plugin compiled in debug mode? This may be faster, than me having to set something up first. Just the binary should be fine for a first shot.
        By the way, are you porting to R16 changing the code or are you trying to go with __LEGACY_API define?

        1 Reply Last reply Reply Quote 0
        • H
          Helper
          last edited by

          On 10/10/2014 at 04:57, xxxxxxxx wrote:

          Calling GetInputState() from any other but the main thread causes a breakpoint to be triggered.

          The BaseContainer getter methods trigger breakpoints, for instance, if you call GetVector(id) but the
          data at the specified id is not a vector.

          This is one reason why it is important to properly initialize the node's container in Init().

          1 Reply Last reply Reply Quote 0
          • H
            Helper
            last edited by

            On 10/10/2014 at 05:13, xxxxxxxx wrote:

            Andreas:
            Sure, where can I send it? And yep, I have changed the code and am not running with __LEGACY_API (though I do have some typedefs and #defines used myself).

            Niklas: Shouldn't bt be the main thread here? It's not explicitly stated but I may want to check this myself. How do I get a pointer to the C4D main thread or is it the main thread if bt is nullptr?

            Thanks for the tip about GetVector(id) as well but I have this element intialised correctly and the id is also correct and it is definetly a VECTOR element (and if it wasn't shouldn't that break point also be triggered in R13?)

            1 Reply Last reply Reply Quote 0
            • H
              Helper
              last edited by

              On 10/10/2014 at 05:24, xxxxxxxx wrote:

              We mailed already, that address would be fine.

              1 Reply Last reply Reply Quote 0
              • H
                Helper
                last edited by

                On 10/10/2014 at 05:58, xxxxxxxx wrote:

                Ok, at least I could find the culprit for the vector and Niklas was right. Although in the Init() of my object the vector was correctly initialised, I have a macro command where that element was set as a float! When I generated my object without the macro...no trigger 🙂

                Thanks for that Niklas! Worth an entry in the docs I'd say..

                Still the problem with GetInputState persists. Why is it triggering a break in R16 but not in R13 (during debugging). Hope you find a clue Andreas. Thanks for the effort!

                1 Reply Last reply Reply Quote 0
                • H
                  Helper
                  last edited by

                  On 10/10/2014 at 06:21, xxxxxxxx wrote:

                  Glad it helped. 🙂

                  Afaik, Execute() is not called from the main thread. The main thread would not have pointer (the OS
                  thread ID is 0 for the main thread). You can use GeIsMainThread() to check if you're in the main thread
                  at any time.

                  Afaik (again), the BaseThread pointer is only passed so you can call TestBreak(). For instance, you
                  can tell the RenderDocument() function by returning True from your own C4DThread::TestDBreak()
                  implementation and passing the C4DThread's BaseThread pointer to the RenderDocument()
                  function.

                  I've never tried to use BaseThread::TestBreak() from Execute(), maybe that returns True already
                  if ESC is pressed or something like that. 🙂

                  Best,
                  -Niklas

                  1 Reply Last reply Reply Quote 0
                  • H
                    Helper
                    last edited by

                    On 10/10/2014 at 06:45, xxxxxxxx wrote:

                    Thanks Niklas. And again right, it's definetly not the main thread (just checked with GeIsMainThread). Also I found the threading information in the docs stating that SceneHookData::Execute is indeed called in a threaded context and probably that's not necessarily the main thread. Makes sense.

                    Furthermore it seems the TestBreak call does not crash now anymore! Re-run several times now without a crash triggering so I guess that solved that issue already (so glad!).

                    In my own threads (executed within Execute of the scene hook) I override TestDBreak and that's also where I am calling GetInputState checking for a the ESC key (always triggering a break...very annoying! :). I guess I could pass the bt to the thread class and simply check for a break with it as  bt->TestBreak does indeed work when the user hits ESC (if I remember correctly).

                    At the beginning of the Execute however I also need the left mouse button so I kind of don't get around using GetInputState. Is there an alternative to it? (though I surely can outcomment it for debugging purposes with a preprocessor directive)

                    1 Reply Last reply Reply Quote 0
                    • H
                      Helper
                      last edited by

                      On 10/10/2014 at 06:45, xxxxxxxx wrote:

                      Niklas is right (of course I might add).
                      The first breakpoint is triggered, because GetInputState() is called from a thread.

                      1 Reply Last reply Reply Quote 0
                      • H
                        Helper
                        last edited by

                        On 10/10/2014 at 06:49, xxxxxxxx wrote:

                        Thanks Andreas for confirming. I guess if there is no alternative I will go with my _DEBUG preprocessor solution to avoid the break points.

                        1 Reply Last reply Reply Quote 0
                        • H
                          Helper
                          last edited by

                          On 10/10/2014 at 06:51, xxxxxxxx wrote:

                          I've noted two things for SDK Docs:
                          - a hint on internal breakpoint for using wrong datatype functions for a certain ID
                          - some more explanation on threading, the dos and don'ts, plus info on the threadcontext PluginStart gets called in

                          Katachi, do you mind, marking this as solved?

                          1 Reply Last reply Reply Quote 0
                          • H
                            Helper
                            last edited by

                            On 10/10/2014 at 06:55, xxxxxxxx wrote:

                            Thanks both of you and yep, consider it solved!

                            1 Reply Last reply Reply Quote 0
                            • H
                              Helper
                              last edited by

                              On 10/10/2014 at 09:45, xxxxxxxx wrote:

                              Glad I could help. 🙂

                              @Andreas: good to read you're taking notes on things to be added to the documentation! 🙂

                              Originally posted by xxxxxxxx

                              so I kind of don't get around using GetInputState. Is there an alternative to it? (though I surely can outcomment it for debugging purposes with a preprocessor directive)

                              Maybe you can get this data from the main thread (eg. in a MessageData plugin) and request it
                              from a scene hook.

                              I did not try to compile this code, it is completely from scratch! Just to give you an idea of
                              what I'm talking about. It might need to a bit of performance adjusting, like "only re-get the
                              input state if at least 200 milliseconds passed since the last time the state was retreived".

                              Edit : AAAAaaaand you should probably add a lock/semaphore to the InputStateData structure, or
                              return a copy of the data from GetRecentInputState(). 🙂

                              >
                              > /// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                              > /// RecentInputState.h
                              > /// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                              >
                              > #include "c4d.h"
                              > #pragma once
                              >
                              > struct InputStateData
                              > {
                              > Int32 timestamp; // current timestamp returned by GeGetMilliSeconds();
                              > BaseContainer bc; // filled by GetInputState();
                              > InputStateData() : timestamp(-1), bc() { }
                              > };
                              >
                              > const InputStateData* GetRecentInputState(Int32 pluginid);
                              > Bool RegisterRecentInputStateHook(Int32 pluginid, Int32 askdevice, Int32 askchannel);
                              >
                              > /// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                              > /// RecentInputState.cpp
                              > /// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                              >
                              > #include "RecentInputState.h"
                              >
                              > #include "c4d.h"
                              > #include "HashMap.h"
                              >
                              > class InputStateHook;
                              > static maxon::HashMap<Int32, InputStateHook*> g_map;
                              >
                              > class InputStateHook : public MessageData
                              > {
                              > public:
                              > InputStateHook(Int32 askdevice, Int32 askchannel);
                              > virtual const InputStateData* GetData() const;
                              > virtual Bool CoreMessage(Int32 id, const BaseContainer& msg) override;
                              > private:
                              > Int32 _askdevice, _askchannel;
                              > InputStateData _data;
                              > };
                              >
                              > InputStateHook::InputStateHook(Int32 askdevice, Int32 askchannel)
                              > : _askdevice(askdevice), _askchannel(askchannel)
                              > {
                              > }
                              >
                              > Bool InputStateHook::CoreMessage(Int32 id, const BaseContainer& msg)
                              > {
                              > if (GetInputState(_askdevice, _askchannel, _data.bc))
                              > {
                              > _data.timestamp = GeGetMilliSeconds();
                              > }
                              > return true;
                              > }
                              >
                              > const InputStateData* InputStateHook::GetData() const
                              > {
                              > if (_data.timestamp > 0)
                              > return &_data;
                              > else
                              > return nullptr;
                              > }
                              >
                              > static const InputStateHook* GetRecentInputState(Int32 pluginid)
                              > {
                              > maxon::HashMap<Int32, InputStateHook*>::Entry* entry = g_map.FindEntry(pluginid);
                              > if (entry && entry->GetValue())
                              > {
                              > InputStateHook* hook = entry->GetValue();
                              > return hook->GetData();
                              > }
                              > return nullptr;
                              > }
                              >
                              > Bool RegisterRecentInputStateHook(Int32 pluginid, Int32 askdevice, Int32 askchannel)
                              > {
                              > InputStateHook* hook = NewObj(InputStateHook, askdevice, askchannel);
                              > if (hook)
                              > {
                              > String name = "InputStateHook:" + String::IntToString(askdevice) +
                              > String::IntToString(askchannel);
                              > Bool success = RegisterMessagePlugin(pluginid, name, 0, hook);
                              > if (success)
                              > g_map.Put(pluginid, hook);
                              > return success;
                              > }
                              > return false;
                              > }

                              Best,
                              -Niklas

                              1 Reply Last reply Reply Quote 0
                              • H
                                Helper
                                last edited by

                                On 10/10/2014 at 10:02, xxxxxxxx wrote:

                                Hey Niklas, thanks. That's quite a clever workaround idea!

                                1 Reply Last reply Reply Quote 0
                                • First post
                                  Last post