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
    1. Maxon Developers Forum
    2. CJtheTiger
    3. Posts
    • Profile
    • Following 0
    • Followers 0
    • Topics 17
    • Posts 53
    • Best 6
    • Controversial 0
    • Groups 0

    Posts made by CJtheTiger

    • RE: Reset Tool in Interaction Tag

      Hi @ferdinand,

      Thank you for another great response.

      Yes, my question is indeed about how to reset the tool to the state it had before my script tinkered with it. I was hoping there is an easy way to do this judging by the doc paragraph I quoted, but it sounds like there isn't. I'll try and be clearer about my question in the future.


      Your two suggestions both seem fine, so thank you very much for those!

      Being responsible with what we know is part of what makes this job fun. 🙂


      This here:

      I'm also not sure whether this shared-axis-behavior is intentional?

      was aimed towards the behavior and intention of the Interaction Tag, not towards the default value of the tool flag. Let me explain:

      From my understanding one of the purposes of the Interaction Tag is to manipulate the object Proxy through the object Controller which holds the Interaction Tag. Since the tag effectively prevents the Controller from being manipulated and instead directs all of this to Proxy I believe that the origin of the manipulation matrix should not be in the middle of Proxy and Controller (which it is as you can see in my previous gif) but directly on the object axis of Proxy instead.

      But if this should be a support ticket instead of a forum discussion I can go ahead and do that of course, I just figured you might know of a good reason why the way it is may actually be intended.

      Cheers,
      Daniel

      posted in Cinema 4D SDK
      CJtheTigerC
      CJtheTiger
    • RE: How to properly load async data into C++ generator plugin?

      Hi guys,

      I might be completely off here but let me throw this into the room:

      • These two lines in Message of the SceneHookData of @ferdinand 's pseudo code will block the current thread:
            while (AssetIsLoading(url))
              continue;
      
      • This means that Message in the SceneHookData will only ever finish once the asset has in fact finished loading.
      • This means that GVO of the calling ObjectData will also block until it has finished loading.

      Let's just assume the worst case where a user creates a large number of ObjectDatas and sets all their URLs at once to different values, and loading and processing a single URL would take multiple seconds. Would this cause issues for C4D since so many threads would be blocking?

      Please correct me if I misunderstood something.

      Cheers,
      Daniel

      EDIT
      Adding to @Havremunken 's response: Threads like this one really help a ton for building up that basic understanding of how C4D works, and @ferdinand provides in-depth answers explaining everything we need to know. I can't thank this man enough.

      posted in Cinema 4D SDK
      CJtheTigerC
      CJtheTiger
    • Reset Tool in Interaction Tag

      Hello coders,

      I was playing around with the Interaction Tag. I'll call the object holding the Interaction Tag the Controller and the proxy object the Proxy. Here's what I want to do:

      • When the user drags the Controller using the left mouse button the Proxy should be moved.
      • When the user drags the Controller using the right mouse button the Proxy should be scaled.

      So first I enable Use Right Mouse Button in the Output tab, then in the Scripting tab in the Python script in mouseDown() I check for the right mouse button and eventually set the relevant tool:

      def mouseDown():    
              bc = c4d.BaseContainer()    
              c4d.gui.GetInputState(c4d.BFM_INPUT_MOUSE, c4d.BFM_INPUT_MOUSERIGHT, bc)    
              right_mouse_down = bc[c4d.BFM_INPUT_VALUE] == True  
          
              if right_mouse_down:    
                  doc.SetAction(200000089) # Scale    
              else:    
                  doc.SetAction(200000088) # Move
      

      So far so good. But when right-click-dragging the Proxy will be scaled using the shared axis of the Proxy and the Controller:
      1c6c1554-adca-4d51-8634-a821e46c419d-Cinema_4D_pl2YX5S7O9.gif
      This already seemed weird but I tried to work around it because obviously I want to scale the object on its own axis. So I added this line to the script to enable the Per-Object Transform of the scale tool after activating it:

              tool_data = doc.GetActiveToolData()
              tool_data[c4d.MDATA_AXIS_LOCALMANIPULATION] = True
      

      eb64552e-5282-4ae8-ada0-4f12b896a3da-Cinema_4D_fFuoaUeo2J.gif

      Works fine. However being a good little developer I want to reset the tool to its original state after we're done. The C4D help states for the function mouseUp() of the Interaction Tag:

      mouseUp
      This is called when the user releases the mouse button and signals the end of the user interaction. You can reset tools or kill off any memory-hungry objects that have been allocated in mouseDown or mouseDrag at this point.

      But how do I reset the tool? I do not want to just set the flag to False since the user might've set it to True deliberately regardless of my Interaction Tag so it should regain this expected state.


      Demo

      Here's a simple demo scene (2024.2.0) on my personal OneDrive:
      https://1drv.ms/u/s!At78FKXjEGEomLQx70lV4DUgjN5dbw?e=iwNum5

      To see the behavior:

      1. Activate the Scale tool.
      2. Set the flag Per-Object-Transform to True.
      3. Activate another tool (for example move or rotate).
      4. Make sure no object is selected, then right-click-drag the sphere which will scale the cube.
      5. After releasing the right mouse button, activate the Scale tool and check the flag Per-Object-Transform. It is now unset.

      Intentional Shared-Axis-Behavior?

      I'm also not sure whether this shared-axis-behavior is intentional? Because if you're trying to manipulate a proxy using this tag you most likely want to do it while completely disregarding the axis of the object holding the tag. Correct me if I'm wrong.

      Cheers,
      Daniel

      posted in Cinema 4D SDK 2024 python
      CJtheTigerC
      CJtheTiger
    • RE: How to properly load async data into C++ generator plugin?

      Good morning @Havremunken,

      Is there a particular message I am listening for? Or is there another way to be notified of a parameter change outside of GetVirtualObjects?

      In order to listen to parameter changes you can implement the Message function in your plugin and listen for the MSG_DESCRIPTION_POSTSETPARAMETER message. Cast the incoming data argument to DescriptionPostSetValue to extract the ID of the changed parameter and get the value through the node argument.

      Sample code taken from here and adjusted slightly:

      Bool OMyPlugin::Message(GeListNode* node, Int32 type, void* data) {
          BaseContainer* bc;
          ...
          if (type == MSG_DESCRIPTION_POSTSETPARAMETER)
          {
              // Get message data
              DescriptionPostSetValue* dparm = (DescriptionPostSetValue*)data;
              Int32 parameterId = (*(dparm->descid))[0].id;
              bc = static_cast<BaseObject*>(node)->GetDataInstance();
      
              switch (parameterId)
              {
              case FILE_PATH: // Check for the parameter ID of the file path parameter.
                  // Load the file via bc->GetString(FILE_PATH).
                  ApplicationOutput(bc->GetString(FILE_PATH));
                  break;
              }
          }
          ...
      }
      

      This way you could also initiate the cancellation of the current loading process in case the file path is being changed while a file is already being loaded. Alternatively you could lock the parameter in the description using GetDEnabling while the file is being loaded.

      From a UX point of view I recommend indicating the current processing status to the user so the user knows whether a file is loading or if the loading has finished/failed.

      And a personal flavor hint: I'm used to providing control buttons (Load/Start/Import/... and Cancel) for potential long running operations. This way it is clear and intuitive to the user how to use your object.

      Cheers,
      Daniel

      posted in Cinema 4D SDK
      CJtheTigerC
      CJtheTiger
    • RE: 3D -> 2D and back with perspective

      Good morning Ilia,

      Thanks for your detailed response even though this is out of support scope!


      Let me explain what I meant by this:

      involve more computations than I'd like it to

      Using ProjectPointOnLine() the calculations by the script are as follows:

      1. Transform 3D points to 2D screen space using WS().
      2. Calculate my desired new point in screen space.
      3. Transform the new point to 3D world space by projecting the new point onto the 3D line using ProjectPointOnLine().
      4. Transform the new point back from 3D world space to 2D screen space using WS().
      5. Do more things using these correct 2D coordinates of the new point.

      The issue of this topic is addressed by step 3 but to further work properly with the point in 2D space I also need step 4. I in fact do not only need the 2D coordinates but the z component as well. I feel like there must be a mathematical formula to get the correct Z value without transforming all three vector components back and forth in steps 3 and 4. So the issue I have with the "hacky" solution is purely to reduce the amount of performed calculations to a bare minimum which to be completely honest is just a means to satisfy this itch of mine to optimize as much as possible. It's part of what makes programming fun to me. 🙂

      Also it would really be interesting to grasp the mathematical concept behind this. As someone who taught himself 3D programming by reading a bunch of game dev tutorials 15 years ago this is super interesting. But enough rambling.


      Regarding your question:

      Why can't you first do your computations in screen space and only then use the ProjectPointOnLine() function?

      In my example the script I'm currently working on takes the new point as a base and creates some more points around that which are not on the line so I can't use ProjectPointOnLine() for those. For that the new point must have the correct coordinates already so I can derive the other new points correctly, otherwise their position in the world will be skewed as well.


      The frustum concept is something I'll have to take some time to fully understand how I can utilize that. Thanks for the hint.

      Have a nice weekend,
      Daniel

      posted in General Talk
      CJtheTigerC
      CJtheTiger
    • RE: 3D -> 2D and back with perspective

      Hacky Solution

      I stumbled across BaseView.ProjectPointOnLine. This takes a line in 3D space and tries to project "a given mouse coordinate" onto it. Don't know why they'd specifically point out that this is for mouse coordinates when it seems to also work for any camera screen coordinates.

      So here's what I did:

      1. Calculate the screen position of the desired point new_point_s.
      2. Call BaseView.ProjectPointOnLine. Use the world position of Start and Target for the line and new_point_s for the point to project onto the line like this:
      new_point_w = bd.ProjectPointOnLine(start_pos_w, target_pos_w - start_pos_w, new_point_s.x, new_point_s.y)
      

      While this technically works it does involve more computations than I'd like it to because it does include all of this overhead of projecting that screen position onto the line which I don't believe to be the best solution to this. Imagine I actually want to work with the point in screen space before translating it back to world space, I'd have to do another round-trip of WS-ing (to actually get the correct new_point_s with the correct z component) and finally SW-ing that back to world again. Yikes.

      Proper

      I stumbled across this document which I think talks about what I need:
      https://www.comp.nus.edu.sg/~lowkl/publications/lowk_persp_interp_techrep.pdf
      And while I don't expect you to read through those two pages what is important is (12) on page 2 which I think should translate to this:

      new_z = 1.0 / ( (1.0 / start_pos_w.z) + length_s_flat_delta * ( (1.0 - target_pos_w.z) - (1.0 / start_pos_w.z) ) )
      

      However this does not produce the correct result. Isn't this document talking about what I need?

      Cheers,
      Daniel

      posted in General Talk
      CJtheTigerC
      CJtheTiger
    • 3D -> 2D and back with perspective

      Hello coders,

      since this is a question about algorithms I figured I'd post this here. Also this is mostly me hoping that someone will drop some wisdom on me in terms of 3D programming.

      Problem

      So I got two different positions in 3D space, Start and Target. When I look at them in the C4D viewport I need to calculate a new point which is between the two points, but 30 pixels before the target.

      Take a look at this example where the distance in pixels on the screen is 298, so I need a new point which is 268 pixels away from Start (298px - 30px), blue X marks the desired spot.
      af599930-9005-43c7-a0e6-19532e6b5b02-image.png
      However this point must exist in world space.

      So my thought process was this:

      1. Get screen coordinates of both points using BaseView.WS.
      2. Calculate how far away the new point is from Start in percent relative to the screen distance to Target.
      3. Create a new point in screen space using this calculated ratio by doing Start + Direction * Distance * Ratio.
      4. Transform to world coordinates using BaseView.SW.

      The new point will be in the correct screen coordinates, so x and y are fine. However z is messed up which I can only assume is because of the camera perspective.
      1ed14989-5288-47c1-8dd0-f41c3f3ab471-image.png
      Note in the following demo how both the target and the new point are always the same distance apart from each other in Perspective View while the z coordinate in Top View prevents the point from being on the desired pink line between the two points:
      52d7d72d-d3aa-4632-8644-ddff9f0bba7f-Cinema_4D_VliCT7fk6O.gif
      This gets more apparent when moving the target closer to the camera.

      Using a parallel camera (instead of perspective) of course does not have this issue.
      778887e1-a768-47c1-8b5b-e29779e56232-Cinema_4D_RryWEthfdm.gif
      See how it's always nicely on the pink line?

      And that's where I'm stuck. How do I fix this? Can anyone give me a hint?

      Here's my code and a demo scene.

      import c4d
      import math
      
      doc: c4d.documents.BaseDocument # The document the object `op` is contained in.
      op: c4d.BaseObject # The Python generator object holding this code.
      hh: "PyCapsule" # A HierarchyHelp object, only defined when main is executed.
      
      def main() -> c4d.BaseObject:
          bd = doc.GetRenderBaseDraw()
          if bd is None:
              return c4d.BaseObject(c4d.Onull)
      
          # Note for variable names postix:
          # > _w      = World
          # > _s      = Screen
          # > _s_flat = Screen without z coordinate
      
          # World positions of start and target.
          start_pos_w = doc.SearchObject('Start').GetAbsPos()
          target_pos_w = doc.SearchObject('Target').GetAbsPos()
      
          # The distance in pixels the new point should be away from point 2.
          distance_from_target = 30.0
      
          # Calculate the screen coordinates of the points.
          start_pos_s = bd.WS(start_pos_w)
          target_pos_s = bd.WS(target_pos_w)
      
          # Calling WS creates a z coordinate to describe the distance of the
          # point to the camera. To correctly calculate the 2D distance the
          # z axis must be ignored.
          start_pos_s_flat = c4d.Vector(start_pos_s.x, start_pos_s.y, 0)
          target_pos_s_flat = c4d.Vector(target_pos_s.x, target_pos_s.y, 0)
      
          # Get the direction and distance of both points in flat screen space.
          direction_s_flat = (target_pos_s_flat - start_pos_s_flat).GetNormalized()
          length_s_flat = (target_pos_s_flat - start_pos_s_flat).GetLength()
      
          # Calculate the position of the new point in screen space with respect
          # to the z coordinate:
          # 1.  Calculate the ratio how far away the new point is from the
          #     target in percent.
          # 1.a Subtract the distance_from_target from the flat length.
          length_s_flat_delta = length_s_flat - distance_from_target
          # 1.b Divide delta by the flat length to get the ratio.
          ratio = length_s_flat_delta / length_s_flat
          # 2.  Calculate the new point in "deep" screen space.
          # 2.a Get direction and length of the screen space positions.
          direction_s = (target_pos_s - start_pos_s).GetNormalized()
          length_s = (target_pos_s - start_pos_s).GetLength()
          # 2.b Use the ratio to calculate the new point in "deep" screen space.
          new_point_s = start_pos_s + (direction_s * length_s * ratio)
      
          # Transform the new point to world coordinates.
          new_point_w = bd.SW(new_point_s)
      
          # Create some output to visualize the result.
          points = [start_pos_w, new_point_w, target_pos_w]
      
          poly_obj = c4d.BaseObject(c4d.Opolygon)
          poly_obj.ResizeObject(len(points), 0)
      
          for i, point in enumerate(points):
              poly_obj.SetPoint(i, point)
      
          return poly_obj
      

      Link to demo scene (2024.2.0) on my OneDrive:
      https://1drv.ms/u/s!At78FKXjEGEomLMOaoZcJaA2TSwblg?e=8wfev1

      Cheers,
      Daniel

      posted in General Talk programming
      CJtheTigerC
      CJtheTiger
    • RE: Object Plugin - Generator Objects - Hiding the child objects in Editor View

      Hi @ThomasB,

      ~~these generators are (probably) plugins of type ObjectData. These plugins implement the GetVirtualObjects method which returns what will be drawn on the screen, and only this will be drawn with complete disregard of the children. They do use their children as inputs to generate the result which you then see but the children themselves are not returned by GetVirtualObjects.

      See also the documentation on ObjectData.~~

      Seems I was wrong about this, sorry. Maybe this plays together with TouchDependenceList but I'm not sure so I'll just keep my mouth shut now.

      Cheers,
      Daniel

      posted in Cinema 4D SDK
      CJtheTigerC
      CJtheTiger
    • RE: Controlling drag&drop using MSG_DESCRIPTION_CHECKDRAGANDDROP

      Hi @m_adam,

      thanks a lot, that did the trick.

      To close this topic off here's a snippet to allow other objects but not the current object to be dropped in there:

      def Message(self, node: GeListNode, type: int, data: object) -> bool:
      
          if type == c4d.MSG_DESCRIPTION_CHECKDRAGANDDROP:
      
              relevant_id = c4d.DescID(c4d.YOUR_PARAM) # Use the ID of the parameter of your object that you want to check.
              current_id: c4d.DescID = data['id']
              
              if relevant_id.IsPartOf(current_id)[0]:        
                  dragged_element = data["element"]        
                  is_same_object = node == dragged_element        
                  data['result'] = not is_same_object        
                  return True
              
              return True
      

      Cheers,
      Daniel

      posted in Cinema 4D SDK
      CJtheTigerC
      CJtheTiger
    • RE: Python Linting in VSCode?

      Hi @m_adam,

      I coincidentally followed the steps on there when I installed the VS Code extension way back. It's pretty straight forward.

      PyLint in VS Code immediately ramped up my CPU usage so I got rid of that extension. But maybe there's a trick that someone else knows about that could help me out. I'm always open for suggestions and alternatives.

      What IDE are you using if I may ask? Did you setup anything special to make life easier?

      Best regards,
      Daniel

      posted in General Talk
      CJtheTigerC
      CJtheTiger
    • RE: How to create python plugin in 2024?

      Hello @BretBays,

      for me it's a matter of looking through the documentation and the samples on GitHub (I can especially recommend the Rounded Tube). I create all the .h and .res files for my plugins by hand.

      The C++ documentation is definitely more in-depth especially when it comes to Description Resources and there's generally a lot in there you can just carry over to Python. Still there's a lot to just kind of figure out as you go and a lot of digging through the forums.

      To be completely honest I feel like there should be a guide to get started since there's a lot you can mess up while getting not very descriptive errors especially with the .res files. I'm interested to see what the others say, maybe I'm just making a mountain out of a molehill.

      Cheers,
      Daniel

      posted in Cinema 4D SDK
      CJtheTigerC
      CJtheTiger
    • RE: Controlling drag&drop using MSG_DESCRIPTION_CHECKDRAGANDDROP

      Hello @spedler,

      Thanks, this totally works.

      However this refuses to take any of my plugin objects, while in the end I only want to refuse the current plugin object; I still want to be able to drag other instances of my plugin object in there.

      So in the end I'd still like to solve this using advanced logic in the MSG_DESCRIPTION_CHECKDRAGANDDROP message.

      Best regards,
      Daniel

      posted in Cinema 4D SDK
      CJtheTigerC
      CJtheTiger
    • Controlling drag&drop using MSG_DESCRIPTION_CHECKDRAGANDDROP

      Hello coders. Me again.

      In a Python ObjectData plugin I added a LINK parameter. I want all BaseObjects except for the plugin object itself to be droppable in here. So I put this in my .res file:

      LINK OMYOBJECT_LINK { ACCEPT { Obase; } }
      

      According to the documentation of MSG_DESCRIPTION_CHECKDRAGANDDROP I should listen to this message and if I want the drop to not be acceptable I should return False. So this is in my code:

      def Message(self, node: GeListNode, type: int, data: object) -> bool:
      
          if type == c4d.MSG_DESCRIPTION_CHECKDRAGANDDROP:
              return False
      
          return True
      

      Just to try it out I always return False. And that's where my issue is: I can still drop any object in there. It is limited to BaseObjects so the ACCEPT { Obase; } seems to work but returning False seems to not prevent the user from dropping something in the link.

      What am I doing wrong?

      I tried removing ACCEPT { Obase; } from the .res file to no effect.

      As an addition: How do I control what the picker of a LINK is allowed to pick? Since it's technically not a drag&drop action it should be something other than MSG_DESCRIPTION_CHECKDRAGANDDROP right?

      posted in Cinema 4D SDK 2024 python
      CJtheTigerC
      CJtheTiger
    • Python Linting in VSCode?

      Hello coders.

      Are you linting your Python code?

      My IDE is Visual Studio Code and I tried PyLint but got immediately shot down when it didn't recognize the values I declared in the .h files but tried to reference them in the python code.
      2af6a64d-6854-41a2-aaa1-9be3da20c68f-image.png
      I can't imagine putting # pylint: disable=no-member anywhere I'm using these just to get around this rule for these values.

      From what I understand I also can't get around this with Stubbs?

      It also seems to simply use wrong metadata for its linting, like when calling c4d.utils.DegToRad it says that the function has no return while it very clearly has:
      df82985c-6668-4589-854f-b7711c9068ed-image.png
      Does not make any sense to me.

      Oh, and on top of that it's super slow to recognize any changes. I'm used to near instant feedback from C# development using Visual Studio. This should be possible for Python as well right?

      Are there any linters or settings you can recommend?

      Best regards,
      Daniel

      posted in General Talk programming
      CJtheTigerC
      CJtheTiger
    • Include same container multiple times in .res

      Hello coders.

      I'd like to include the Oprimitiveaxis container multiple times in the .res file of my ObjectData plugin where the first inclusion should be called the same as the default Orientation while the second inclusion should be called something else like Alternative Orientation. To access both values in my plugin code they of course need separate IDs as well.

      For the first inlcusion I can simply do this in the .res file:

      CONTAINER omyobject
      {
      	NAME Omyobject;
      	INCLUDE Obase;
      
      	INCLUDE Oprimitiveaxis;
      }
      

      and access it via:

      orientation = op[c4d.PRIM_AXIS]
      

      What would I need to do to include this a second and possibly even more times? Is this even possible? In my head I'd have to define an alternative name and ID right with the INCLUDE statement. Or do I simply have copy and paste the CYCLE myself?

      Best regards,
      Daniel

      posted in Cinema 4D SDK 2024 python c++
      CJtheTigerC
      CJtheTiger
    • RE: Python: Localized Plugin Name

      It seems like I found the working combination.

      The STRINGTABLE in res\strings_en-US\c4d_strings.str must not be named. In my previous response I pasted the contents which as you can see started with STRINGTABLE omyobject whereas it should simply be STRINGTABLE without a name.

      • I guess this str-file cannot contain named STRINGTABLEs. My first suspicion was that the error was caused by trying to define two STRINGTABLEs with the same name (since I had another STRINGTABLE with that name in the description folder) but even choosing another name in the c4d_strings.str resulted in the same error. Only when removing the name did I get rid of the error.

      I added the plugin ID to both the res\c4d_symbols.h and the res\description\omyobject.h as an enum member called Omyobject.

      • Having the ID in res\c4d_symbols.h allows for having a value outside of description resources (i.e. dialogs) which I required for the plugin name, as @m_adam already explained.
      • Having the ID in res\description\omyobject.h allows for description resources to access an accordingly named value in the STRINGTABLE in res\strings_xx-XX\description\omyobject.str. It also defines c4d.Omyobject which I'm now using in c4d.plugins.RegisterObjectPlugin to access the plugin name in res\strings_xx-XX\c4d_strings.str.
        • Note that this requires the plugin ID to be defined in two places (res\c4d_symbols.h and res\description\omyobject.h) which decreases maintainability.
        • Also note that I'm using the plugin ID from the description header to get a value from a non-description STRINGTABLE which sure enough does work but is probably not the cleanest solution.

      Does this sort of sound right? Is this the intended way?

      posted in Cinema 4D SDK
      CJtheTigerC
      CJtheTiger
    • RE: Python: Localized Plugin Name

      Thank you for your response @m_adam.

      Unfortunately I'm still struggling even though I think I did what you suggested. I'm getting this error:

      Error reading resource file '...\res\strings_en-US\c4d_strings.str'
      Line 2

      The res\strings_en-US\c4d_strings.str has these contents:

      STRINGTABLE omyobject
      {
          Omyobject                    "My Object";
      }
      

      Removed link to my repo since it's no longer relevant and will be outdated soon.

      posted in Cinema 4D SDK
      CJtheTigerC
      CJtheTiger
    • Python: Localized Plugin Name

      I've read quite a few posts in the forum on how to use GeLoadString to get a localized string. I'm trying to do this for the name of an object generator plugin written in Python yet I'm always getting StrNotFound when calling GeLoadString during RegisterObjectPlugin.

      Let me show you what I got. Keep in mind that I excluded stuff that's irrelevant to this topic.

      This is my folder structure:

      • res
        • description
          • omyobject.h
          • omyobject.res
        • strings_en-US
          • description
            • omyobject.str
        • strings_de-DE
          • description
            • omyobject.str
        • c4d_symbols.h
      • Omyobject.pyp

      In res/description/omyobject.h is this:

      #ifndef _omyobject_H_
      #define _omyobject_H_
      
      enum
      {
          Omyobject                        = <mypluginid>
      }
      
      #endif
      

      ...where <mypluginid> is my plugin ID.

      In res/strings_**-**/description/omyobject.str is this:

      STRINGTABLE omyobject
      {
          Omyobject "My Object";
      }
      

      And finally in Omyobject.pyp I'm trying to register to plugin using this code:

          c4d.plugins.RegisterObjectPlugin(id=c4d.Omyobject,
                                           str=c4d.plugins.GeLoadString(c4d.Omyobject),
                                           g=Omyobject,
                                           description="omyobject",
                                           icon=bmp,
                                           info=c4d.OBJECT_GENERATOR|c4d.PLUGINFLAG_HIDEPLUGINMENU)
      

      str=c4d.plugins.GeLoadString(c4d.Omyobject) returns StrNotFound and I don't know why.

      What is the intended way to do this?

      posted in Cinema 4D SDK 2024 python
      CJtheTigerC
      CJtheTiger
    • RE: New Forum Announcement

      @justinleduc said in New Forum Announcement:

      I'm using Chrome 120.0.6099.63 (WIN). It seems like the behavior I described only happens when I am logged in. To expand on what I said above, when pressing CTRL+F, the website's search function (i.e. the search bar that opens when pressing the magnifying glass in the website's header) opens/expands and forces you to insert your search terms in there as opposed to being able to type them in the browser-level page search function.

      Same on Firefox 120.0.1.

      posted in News & Information
      CJtheTigerC
      CJtheTiger