• Drive smooth rotation

    Cinema 4D SDK
    3
    0 Votes
    3 Posts
    624 Views
    J
    Hello @PMenich , without further questions or postings, we will consider this topic as solved by Friday, the 11th of august 2023 and flag it accordingly. Thank you for your understanding, Maxon SDK Group
  • xRef file path is broken if created via python

    Cinema 4D SDK python 2023
    3
    0 Votes
    3 Posts
    688 Views
    B
    Sorry for not making my post as clear as it should have been, next time I will do better The good thing is, I fixed it! The problem was how I loaded my initial master project. # instead of using c4d.documents.LoadDocument() # i replaced it with c4d.documents.LoadFile() ... and now my xRef works just fine! Thank you again!
  • c4d.EventAdd() is not working

    Moved Bugs python 2023
    9
    0 Votes
    9 Posts
    2k Views
    ferdinandF
    Hey everyone, The issue has been fixed and verified in an internal build. It will be shipped with one of the builds of the next major update (i.e., it will not make it into 2023.x.y anymore). Beta testers can already make use of the change in the most recent beta build. Cheers, Ferdinand
  • How to get a port data type?

    Moved Bugs sdk python windows 2023
    6
    1
    0 Votes
    6 Posts
    1k Views
    J
    Hello @Dunhou , you are correct, the issue is not fixed yet. As Ferdinand mentioned in the beginning he has flagged it as "to_fix", so it will be fixed as soon as possible. Thanks and Cheers Maxon SDK Group
  • CRITICAL: Stop when calling SetWorldPluginData

    Cinema 4D SDK python 2023
    5
    0 Votes
    5 Posts
    1k Views
    a_blockA
    Thanks for the offer. much appreciated. But your explanations were good and plenty as usual. I think, I know exactly what is going on.
  • 0 Votes
    7 Posts
    1k Views
    B
    @ferdinand Gotcha. Thanks. Will close this thread now.
  • Get pressed keys in ObjectData plugin

    Cinema 4D SDK c++ 2023
    17
    0 Votes
    17 Posts
    3k Views
    J
    Hello @CJtheTiger , without further questions or postings, we will consider this topic as solved by Friday, the 11th of august 2023 and flag it accordingly. Thank you for your understanding, Maxon SDK Group
  • 0 Votes
    11 Posts
    2k Views
    DunhouD
    Hi @m_adam , I have ask what are main functions in redshift do in redshift forum, but get no reply for week. and the help(redshift) also give me an ambiguous result. But anyway, I have something here, I will update it and publish when I have free times.
  • Getting only the last value of the slider (slide)

    Moved Bugs 2023 python
    5
    1
    0 Votes
    5 Posts
    1k Views
    P
    Great work!!! Thank you. Regards, Pim
  • 0 Votes
    3 Posts
    648 Views
    i_mazlovI
    Hi @pim, Thanks for reaching out to us. The links are document-specific so they only make any sense in the context of the document that they were created in. It means that once stored, restoring them back would only correspond to the exact same objects in the exact same document. If it's not your case, then you'd need to define the criteria of what you mean by two objects being the same (is it only a name or a combination of the name with any other properties, e.g. hierarchy?). However, if the context of these objects stays the same, then you can use the same trick as @ferdinand mentioned in the point selection thread. Namely, using MAXON_CREATOR_ID for extracting the UUIDs of the objects. These UUIDs can be stored in the Hyperfile (just as simple strings). So whenever you need to restore them, you would need to traverse the document tree and compare the actual object UUID with the one you're restoring. One can also use GetClassification() function to retrieve the type of the object, which would make traversing the document a little more efficient. Please find the sample script implementing the explained approach below. Let me know if you have any further questions. Cheers, Ilia [image: 1684233709032-cinema_4d_ifzokeu8lw.gif] import c4d LINK_OBJ_ID = 1001 LINK_MAT_ID = 1002 BTN_SAVE_ID = 1003 BTN_LOAD_ID = 1004 BTN_RESET_ID = 1005 HF_IDENT = 49545 PATH = 'd:\\_tmp\\lnkbox.bin' class MainDialog(c4d.gui.GeDialog): def __init__(self): self.linkBoxes : dict[int, c4d.gui.BaseCustomGui] = {} def CreateLayout(self): self.GroupBegin(2001, c4d.BFH_FIT, cols=1) self.linkBoxes[0] = self.AddCustomGui(LINK_OBJ_ID, c4d.CUSTOMGUI_LINKBOX, "Obj", c4d.BFH_SCALEFIT, 100, 4) self.linkBoxes[1] = self.AddCustomGui(LINK_MAT_ID, c4d.CUSTOMGUI_LINKBOX, "Mat", c4d.BFH_SCALEFIT, 100, 4) self.GroupEnd() self.GroupBegin(2002, c4d.BFH_FIT, cols=3) self._btnSave = self.AddButton(BTN_SAVE_ID, c4d.BFH_SCALEFIT, name="Store links") self._btnLoad = self.AddButton(BTN_RESET_ID, c4d.BFH_SCALEFIT, name="Reset links") self._btnSave = self.AddButton(BTN_LOAD_ID, c4d.BFH_SCALEFIT, name="Load links") self.GroupEnd() return True def Command(self, id, msg): if id == BTN_SAVE_ID: self.save(PATH) elif id == BTN_LOAD_ID: self.load(PATH) elif id == BTN_RESET_ID: self.reset() return True @staticmethod def GetUUID(node: c4d.C4DAtom) -> bytes: """Returns an UUID for #node which identifies it over reallocation boundaries""" if not isinstance(node, c4d.C4DAtom): raise TypeError(f"{node = }") data: memoryview = node.FindUniqueID(c4d.MAXON_CREATOR_ID) if not isinstance(data, memoryview): raise RuntimeError(f"Could not access UUID for: {node}") return bytes(data) @staticmethod def traverseSubtree(bl : c4d.BaseList2D): """Half-recursively iterates over baselist elements and its children""" while bl: yield bl for child in MainDialog.traverseSubtree(bl.GetDown()): yield child bl = bl.GetNext() @staticmethod def traverseDocument(doc : c4d.documents.BaseDocument, callBack, classification): """Executes callback for each document element depending on classification""" if doc is None: raise ValueError("doc is None") bl : c4d.BaseList2D = None if classification == c4d.Obase: bl = doc.GetFirstObject() elif classification == c4d.Mbase: bl = doc.GetFirstMaterial() for op in MainDialog.traverseSubtree(bl): if not callBack(op): # callback returns false if no further traversing needed return def reset(self): """Reset links in the gui""" for lnkbox in self.linkBoxes.values(): lnkbox.SetLink(None) def save(self, path): """Store links UUID and Classification in the Hyperfile""" bcFile = c4d.BaseContainer() hf = c4d.storage.HyperFile() if hf.Open(ident=HF_IDENT, filename=path, mode=c4d.FILEOPEN_WRITE, error_dialog=c4d.FILEDIALOG_NONE): for idx, lnkbox in self.linkBoxes.items(): lnk : c4d.BaseList2D = lnkbox.GetLink(c4d.documents.GetActiveDocument()) if lnk is None: print("No link selected!") continue uuid : str = MainDialog.GetUUID(lnk).hex() bc = c4d.BaseContainer() bc[0], bc[1] = uuid, lnk.GetClassification() bcFile.SetContainer(idx, bc) hf.WriteContainer(bcFile) else: c4d.gui.MessageDialog("Couldn't open file for writing") hf.Close() def load(self, path): """Unpack UUIDS from Hyperfile and search for corresponding objects""" uuid : str = None obj : c4d.BaseObject = None classification : int = 0 def process(op): """Callback lambda: store object once the correct one has been found""" nonlocal obj if op is not None and MainDialog.GetUUID(op).hex() == uuid: obj = op return False return True hf = c4d.storage.HyperFile() if hf.Open(ident=HF_IDENT, filename=path, mode=c4d.FILEOPEN_READ, error_dialog=c4d.FILEDIALOG_NONE): bcFile : c4d.BaseContainer = hf.ReadContainer() for idx, lnkbox in self.linkBoxes.items(): bc : c4d.BaseContainer = bcFile.GetContainer(idx) uuid, classification = bc[0], bc[1] MainDialog.traverseDocument(c4d.documents.GetActiveDocument(), process, classification) if uuid is not None and obj is not None: lnkbox.SetLink(obj) else: c4d.gui.MessageDialog("Couldn't open file for reading") hf.Close() if __name__=='__main__': dlg = MainDialog() dlg.Open(c4d.DLG_TYPE_ASYNC, defaultw=256, xpos=-2, ypos=-2)
  • 0 Votes
    11 Posts
    2k Views
    indexofrefractionI
    @ferdinand first of all, I understand your frustration, we just yesterday talked about the state of the Nodes API and are well aware of its hurdles for anything but super-experts. you can say that aloud! the whole system is very hard to understand. the only thing i got is all we know about traditional materials and even shaders is for the bin. node support evolved over time and most node examples do not work for people still using older c4d versions. also there are misc 3rd-party renderers that use different kinds of nodes / node systems. Drag & drop of attributes to the console doesn't work anymore, as well. the days of easy scripting are gone..
  • Create User Data with Data Type Spline

    Cinema 4D SDK python 2023
    4
    0 Votes
    4 Posts
    916 Views
    ferdinandF
    Hey @pim, It is great to hear that your problem is solved. And to be clear: You can use ChatGPT and Co. to write your code; I would simply ask you to disclose it if you post code (partially) generated by a bot. We understand and agree that chat bots can be a useful tool especially for beginners. But they also have a tendency to write code that is just made up gibberish. When we know that the code has been written by a bot, we can say "that is just noise/garbage". If we do not, we have to point out all problems individually, not only to not offend the author by calling his or her code "garbage", but to also to help the user to understand his or her mistakes. Cheers, Ferdinand
  • Getting the spline from the SplineCustomGui

    Cinema 4D SDK python 2023
    2
    1
    0 Votes
    2 Posts
    513 Views
    ferdinandF
    Hello @pim, Thank you for reaching out to us. As announced here, Maxon is currently conducting a company meeting. Please understand that our capability to answer questions is therefore limited at the moment. The custom GUI for SplineData has its own dedicated GUI type, c4d.gui.SplineCustomGui as pointed out by yourself. So, you must use SplineCustomGui.GetSplineData instead of the generic BaseCustomGui.GetData. Cheers, Ferdinand
  • Cancel Option for Progress Bar Dialog?

    Cinema 4D SDK 2023
    4
    0 Votes
    4 Posts
    973 Views
    ferdinandF
    Hey @bentraje, I would recommend using the example I posted above, only that you replace the MessageData instance with a GeDialog instance. The other thread looks overly specific, a bit overengineered with the decorator, to be a good basic example. I do not have the time to write a full working example right now, but in pseudo code it would look as shown at the end of the posting. I cannot make much out of random error messages you give me. An AttributeError means that an object does not have an attribute, be it a field/property (myObject._data, myObject.Data) or a function (myObject.SendMessage), so it means that you have not declared MyThread.SendMessage and yet try to call it. As always, we also cannot debug your code for you. Cheers, Ferdinand Code: This is untested 'pseudo-code', I wrote this 'blind'. It demonstrates a pattern and is not meant to be executable code. """Provides an example for a thread executing multiple tasks and expressing the execution state to the outside world. """ import c4d import typing class WorkerThread (c4d.threading.C4DThread): """Wraps the execution of multiple tasks expressed by a set of data in a thread. The thread exposes the total amount of tasks, already done tasks, and their results to outside observers. """ def __init__(self, data: typing.Collection) -> None: """Initializes the worker. """ self._data : typing.Collection = data # Stuff to do. self._results: list[any] = [] # Results of stuff that has been done. self._taskCount: int = len(data) # Number of things to do in total. self._finishedTaskCount: int = 0 # Number of things that already have been done. def Main(self) -> None: """Carries out the tasks. """ for item in self._data: self._results.append(self.Compute(item)) # this takes a long time to do. self._finishedTaskCount += 1 def Compute(self, *args) -> any: """Represents a computation step. """ return 0 # Read-only properties to access the data of the thread from another thread. You could also just # let the other thread directly access members (thread._results) or also use fancier things like # locks/semaphores to make this "nicer". This is a question of taste, read-only properties are # somewhat a middle ground. @property def Results(self) -> tuple[any]: return tuple(self._results) @property def TaskCount(self) -> int: return self._taskCount @property def FinishedTaskCount(self) -> int: return self._finishedTaskCount class MyTaskDialog (c4d.gui.GeDialog): """Realizes a dialog that runs a thread wrapping multiple tasks. """ ID_NEW_THREAD: int = 1000 # Id of a gadget which invokes adding a new thread. def __init__(self) -> None: """ """ # The worker thread of the dialog, could also be multiple threads as in the other example, # I kept it simple here. self._workerThread: WorkerThread | None = None super().__init__() def Command(self, mid: int, msg: c4d.BaseContainer) -> bool: """Called by Cinema 4D on GUI interactions. """ # Something with ID_NEW_THREAD has been pressed, we start try to start a new thread with the # dummy data [1, 2, 3]. if mid == MyTaskDialog.ID_NEW_THREAD and not self.StartWorkerThread([1, 2, 3]): # Do something on failure. pass return super().Command(mid, msg) def StartWorkerThread(self, data: typing.Collection, evalFrequency: int = 250) -> bool: """Starts a new worker thread and sets the evaluation frequency. """ # There is already an ongoing thread. if isinstance(self._workerThread, WorkerThread): return False # Create and start the new thread. self._workerThread = WorkerThread(data) self._workerThread.Start() self.SetTimer(max(100, evalFrequency)) return True def Timer(self, msg: c4d.BaseContainer) -> None: """Called by Cinema 4D for each timer tick. """ # Should never happen and (most) GUI functions do this own their own, more a formality. if not c4d.threading.GeIsMainThreadAndNoDrawThread(): return t: WorkerThread = self._workerThread # The thread is still running, just update the UI with the status of the thread. if t.IsRunning(): c4d.StatusSetSpin() c4d.StatusSetText(f"Running tasks: {t.FinishedTaskCount}/{t.TaskCount}") # The thread has finished, do something with the result, shut off the timer, and clear out # the UI. else: results: any = t.Results print(results) t.End() self._workerThread = None self.SetTimer(0) c4d.StatusClear()
  • 0 Votes
    4 Posts
    779 Views
    K
    Hi @m_adam, Sorry for the delay in responding. Yes, the problem has been resolved.
  • wordwrapping difference between r23 and r2023.

    Cinema 4D SDK python r23 2023
    3
    0 Votes
    3 Posts
    802 Views
    D
    hi, thank you - but it has become unnecessary. i did not realize that there is a checkbox in the preferences, called "Script Word Wrap", which was activated while i was working in r23 (probably since the first installation of r23, back in the day), but deactivated (i guess, that's the default setting) in my fresh installation of r2023. it's fine now. i'll mark this one as solved.
  • Need help with Bend-Deformer in Object-Plugin

    Moved Bugs r23 2023 python windows
    6
    0 Votes
    6 Posts
    2k Views
    M
    Hello @ThomasB, without further questions or postings, we will consider this topic as solved by Monday 05/06/2023 and flag it accordingly. Thank you for your understanding, Maxime.
  • Cinema 4D Connector is not working on 2023.2.0

    Moved Bugs
    3
    0 Votes
    3 Posts
    1k Views
    T
    Thank you very much for the quick answer, i effectively forgot to look into the changes notes
  • description.SetParameter() Question

    Cinema 4D SDK r23 2023 python windows
    11
    0 Votes
    11 Posts
    2k Views
    ThomasBT
    @ferdinand At first I wanted to do it exactly like you recommended, but then I thought why, if you save 36 IDs, it's certainly more memory-efficient. And when you just rename it, you've already learned something again. Actually, I wanted to do it with separate IDs. But then I recognized that I need the exact same 3 parameters, just with other Labels. but since renaming was faster, I decided to do it. It's an update of the previous version of the plugin and it was easiest to just change the labels. I'll think about it, I've got time. Thank you because my English is not always the best, I sometimes find it difficult to read your texts. They are already very extensive in some cases. Good evening!
  • PYP script doesn't show up in extensions

    Moved Bugs 2023 python
    4
    1
    0 Votes
    4 Posts
    1k Views
    M
    Hi @kiesi, just replying to confirm that what @C4DS is saying is true. If you need to have a plugin installed elsewhere you can add an additional plugin lookup path in the Cinema 4D preference within the Plugin category. Otherwise you can also execute Cinema 4D with the next argument g_additionalModulePath={YourPath} or define g_additionalModulePath as an environment variable to add an additional python lookup path. Cheers, Maxime.