Navigation

    • Register
    • Login
    • Search
    1. Home
    2. beatgram
    beatgram

    Shinsuke Matsumoto

    @beatgram

    Beat Driven Creative.
    Freelance Animator Based in Tokyo.
    Friend of After Effects & Toon Boom Harmomy.

    I sometimes write crappy code.
    Newbie to C4D.

    1
    Reputation
    19
    Posts
    21
    Profile views
    0
    Followers
    0
    Following
    Joined Last Online
    Website beatgram.net Location Tokyo Age 46

    • Profile
    • More
      • Following
      • Followers
      • Topics
      • Posts
      • Best
      • Groups
    beatgram Follow

    Best posts made by beatgram

    RE: Python Tag Plugin Doesn't Work Properly With Resource Files

    I double checked my hierarchy / structure and finally I found my mistake!
    The structure below works well and I think it's correct one.

    Test Plugin/
        test_plugin.pyp
        res/
            c4d_symbols.h
            description/
                ttestplugin.h
                ttestplugin.res
            strings_en-US/
                description  -------------------- This folder needed! --------------------
                    ttestplugin.str
    
    posted in Cinema 4D SDK •

    Latest posts made by beatgram

    RE: Attribute Manamger Update Delay When Description Added Dynamically

    @m_adam Oh, that's a little update for many users but huge for tiny developers like me!
    Thank you so much for the heads up. 😳

    posted in Cinema 4D SDK •
    RE: Undo Problem For TagData Plugin

    @m_magalhaes Thank you for your checking, Manuel.

    I didn't think it's a bug! And yep, your workaround with bracket notation works fine.
    So these bracket notation style is safer than using BaseContainer in any case?
    Anyway, let us know if you confirm this is a bug.

    posted in Cinema 4D SDK •
    Undo Problem For TagData Plugin

    Hey folks,

    I encountered Undo related issue again. It might be due to my lack of understanding for undo things but let me ask you a question.

    I wrote a test tag plugin with python which follows another object's position with a little offset.
    It simply works but when I undo, the object that has the tag doesn't react until I click somewhere (see below).

    Is it possible to solve this issue with python?
    I know undo things are prohibited in execute() of tagdata, so is there any workaround?

    Please help me if you know the solution.

    undo_issue_1.gif

    Here's quick code for this.

    testtag.pyp

    import os
    import c4d
    from c4d import plugins, bitmaps, utils
    
    
    PLUGIN_ID = *******
    
    
    class TestTagData(plugins.TagData):
        def Init(self, node):
            pd = c4d.PriorityData()
            if pd is None:
                raise MemoryError("Failed to create a priority data.")
            pd.SetPriorityValue(lValueID = c4d.PRIORITYVALUE_MODE, data = c4d.CYCLE_INITIAL)
            node[c4d.EXPRESSION_PRIORITY] = pd
            return True
    
        def Execute(self, tag, doc, op, bt, priority, flags):
            bc = tag.GetDataInstance()
            obj = bc.GetLink(c4d.TTEST_TARGET_OBJECT)
            if obj is None:
                return False
            mrx = obj.GetMg()
            mrx.off += c4d.Vector(100, 0, 0)
            op.SetMg(mrx)
            return c4d.EXECUTIONRESULT_OK
    
    
    if __name__ == "__main__":
        plugins.RegisterTagPlugin(id = PLUGIN_ID, str = "Test Tag", info = c4d.TAG_EXPRESSION | c4d.TAG_VISIBLE, g = TestTagData, description = "ttest", icon = None)
    

    ttest.res

    CONTAINER Ttest
    {
        NAME Ttest;
        INCLUDE Texpression;
    
        GROUP ID_TAGPROPERTIES
        {
            LINK TTEST_TARGET_OBJECT
            {
                ANIM ON;
                ACCEPT { Obase; };
            }
    }
    
    posted in Cinema 4D SDK •
    RE: How To Add Undo For Description Added Dynamically

    @Cairyn Thank you so much for helping me again! 😊

    posted in Cinema 4D SDK •
    RE: How To Add Undo For Description Added Dynamically

    @m_magalhaes Thank you for your explanation! It's really helpful to know several solutions for a problem.
    C4D python doc is not user friendly for newbies like me but this community is super friendly and pretty awesome! 🤛

    posted in Cinema 4D SDK •
    RE: How To Add Undo For Description Added Dynamically

    So I tried some changes based on a hint @Cairyn points out, my code seems to work now.
    But I'm still not sure this is a proper way to add undo for dynamic descriptions, so please let me know if you know the correct / better way!

    test_tag.pyp

    import os
    import c4d
    from c4d import plugins
    
    
    PLUGIN_ID = *******
    LINK_NO = 1100
    FLOAT_NO = 1200
    
    
    class TestTagData(c4d.plugins.TagData):
        def Init(self, node):
            self.InitAttr(node, int, c4d.TTESTTAG_CONTROLLERS_NUM)  #-------------------- Changed --------------------
            bc = node.GetDataInstance()  #-------------------- Changed --------------------
            bc.SetInt32(c4d.TTESTTAG_CONTROLLERS_NUM, 0)  #-------------------- Changed --------------------
            pd = c4d.PriorityData()
            if pd is None:
                raise MemoryError("Failed to create a priority data.")
            pd.SetPriorityValue(lValueID = c4d.PRIORITYVALUE_MODE, data = c4d.CYCLE_EXPRESSION)
            node[c4d.EXPRESSION_PRIORITY] = pd
            return True
    
        def Execute(self, tag, doc, op, bt, priority, flags):
            return c4d.EXECUTIONRESULT_OK
    
        def Message(self, node, type, data):
            if type == c4d.MSG_DESCRIPTION_COMMAND:
                if data["id"][0].id == c4d.TTESTTAG_BUTTON_ADD:
                    doc = c4d.documents.GetActiveDocument()
                    doc.StartUndo()
                    doc.AddUndo(c4d.UNDOTYPE_CHANGE_SMALL, node)
                    bc = node.GetDataInstance()  #-------------------- Changed --------------------
                    bc.SetInt32(c4d.TTESTTAG_CONTROLLERS_NUM, bc.GetInt32(c4d.TTESTTAG_CONTROLLERS_NUM) + 1)  #-------------------- Changed --------------------
                    doc.EndUndo()
                elif data["id"][0].id == c4d.TTESTTAG_BUTTON_REMOVE:
                    bc = node.GetDataInstance()  #-------------------- Changed --------------------
                    controllers_num = bc.GetInt32(c4d.TTESTTAG_CONTROLLERS_NUM)  #-------------------- Changed --------------------
                    if controllers_num > 0:  #-------------------- Changed --------------------
                        doc = c4d.documents.GetActiveDocument()
                        doc.StartUndo()
                        doc.AddUndo(c4d.UNDOTYPE_CHANGE_SMALL, node)
                        bc.SetInt32(c4d.TTESTTAG_CONTROLLERS_NUM, controllers_num - 1)  #-------------------- Changed --------------------
                        doc.EndUndo()
            return True
    
        def GetDDescription(self, node, description, flags):
            if not description.LoadDescription(node.GetType()):
                return False
            singleId = description.GetSingleDescID()
            groupId = c4d.DescID(c4d.DescLevel(c4d.ID_TAGPROPERTIES))
            bc = node.GetDataInstance()  #-------------------- Changed --------------------
            controllers_num = bc.GetInt32(c4d.TTESTTAG_CONTROLLERS_NUM)  #-------------------- Changed --------------------
            if controllers_num > 0:
                for i in range(controllers_num):
                    linkId = c4d.DescID(c4d.DescLevel(LINK_NO + (i + 1)))
                    if singleId is None or linkId.IsPartOf(singleId)[0]:
                        link_bc = c4d.GetCustomDataTypeDefault(c4d.DTYPE_BASELISTLINK)
                        link_bc.SetString(c4d.DESC_NAME, "Controller " + str(i + 1))
                        link_bc.SetString(c4d.DESC_SHORT_NAME, "Controller " + str(i + 1))
                        link_bc.SetInt32(c4d.DESC_ANIMATE, c4d.DESC_ANIMATE_ON)
                        if not description.SetParameter(linkId, link_bc, groupId):
                            return False
                    floatId = c4d.DescID(c4d.DescLevel(FLOAT_NO + (i + 1)))
                    if singleId is None or floatId.IsPartOf(singleId)[0]:
                        float_bc = c4d.GetCustomDataTypeDefault(c4d.DTYPE_REAL)
                        float_bc.SetString(c4d.DESC_NAME, "Rate")
                        float_bc.SetString(c4d.DESC_SHORT_NAME, "Rate")
                        float_bc.SetFloat(c4d.DESC_DEFAULT, 1)
                        float_bc.SetInt32(c4d.DESC_ANIMATE, c4d.DESC_ANIMATE_ON)
                        float_bc.SetInt32(c4d.DESC_UNIT, c4d.DESC_UNIT_PERCENT)
                        float_bc.SetFloat(c4d.DESC_MIN, -1000)
                        float_bc.SetFloat(c4d.DESC_MAX, 1000)
                        float_bc.SetFloat(c4d.DESC_MINSLIDER, -1)
                        float_bc.SetFloat(c4d.DESC_MAXSLIDER, 1)
                        float_bc.SetFloat(c4d.DESC_STEP, 0.01)
                        float_bc.SetInt32(c4d.DESC_CUSTOMGUI, c4d.CUSTOMGUI_REALSLIDER)
                        if not description.SetParameter(floatId, float_bc, groupId):
                            return False
                    separatorId = c4d.DescID(0)
                    if singleId is None or separatorId.IsPartOf(singleId)[0]:
                        separator_bc = c4d.GetCustomDataTypeDefault(c4d.DTYPE_SEPARATOR)
                        separator_bc.SetInt32(c4d.DESC_CUSTOMGUI, c4d.CUSTOMGUI_SEPARATOR)
                        separator_bc.SetBool(c4d.DESC_SEPARATORLINE, True)
                        if not description.SetParameter(separatorId, separator_bc, groupId):
                            return False
            return (True, flags | c4d.DESCFLAGS_DESC_LOADED)
    
    
    if __name__ == "__main__":
        c4d.plugins.RegisterTagPlugin(id = PLUGIN_ID, str = "Test Tag", info = c4d.TAG_EXPRESSION|c4d.TAG_VISIBLE, g = TestTagData, description = "ttesttag", icon = None)
    

    ttesttag.res

    CONTAINER Ttesttag
    {
        NAME Ttesttag;
        INCLUDE Texpression;
    
        GROUP ID_TAGPROPERTIES
        {
            GROUP TTESTTAG_BUTTONS_GROUP
            {
                COLUMNS 2;
                BUTTON TTESTTAG_BUTTON_ADD { SCALE_H; }
                BUTTON TTESTTAG_BUTTON_REMOVE { SCALE_H; }
                LONG TTESTTAG_CONTROLLERS_NUM { HIDDEN; ANIM OFF; MIN 0; MAX 10000; }  //-------------------- Added --------------------
            }
        }
    }
    

    ttesttag.h

    #ifndef _TTESTTAG_H_
    #define _TTESTTAG_H_
    
    enum
    {
        TTESTTAG_BUTTONS_GROUP = 1001,
        TTESTTAG_BUTTON_ADD = 1002,
        TTESTTAG_BUTTON_REMOVE = 1003,
        TTESTTAG_CONTROLLERS_NUM = 1004,  //-------------------- Added --------------------
    }
    
    #endif
    

    ttesttag.str

    STRINGTABLE Ttesttag
    {
        Ttesttag "Test Tag";
        TTESTTAG_BUTTONS_GROUP "";
        TTESTTAG_BUTTON_ADD "Add";
        TTESTTAG_BUTTON_REMOVE "Remove";
        TTESTTAG_CONTROLLERS_NUM "";  //-------------------- Added --------------------
    }
    
    posted in Cinema 4D SDK •
    RE: Attribute Manamger Update Delay When Description Added Dynamically

    @m_adam Thank you for confirming.
    I already know symbolcache thingy, so it's no problem.

    posted in Cinema 4D SDK •
    RE: How To Add Undo For Description Added Dynamically

    @Cairyn Thank you for your time!

    Hmm, I see. I'm not sure the actual solution for the point you mention but your explanation is so helpful. Anyway, I'll try some workaround on my end.

    posted in Cinema 4D SDK •
    How To Add Undo For Description Added Dynamically

    Hi folks,

    I'm still trying to make a python tag plugin which has 2 buttons in tag property. It dynamically adds new descriptions to tag property when "add" button is clicked, and it dynamically removes those descriptions when "remove" button is clicked. So far my code works but I noticed undo doesn't work for these descriptions (see below).

    Is there a way to add undo for descriptions created dynamically? Please tell me how to add undo for that if it's possible for python plugin.
    I tried to insert basic undo things (StartUndo(), AddUndo(), and EndUndo()) into Message() function but it doesn't seem to work.
    My goal is it works like "IK-Spline" does. (see below)

    "Current Status"
    undo_issue.gif

    "My Goal"
    like_ik_spline.gif

    Here's my code.

    test_tag.pyp

    import os
    import c4d
    from c4d import plugins
    
    
    PLUGIN_ID = *******
    LINK_NO = 1100
    FLOAT_NO = 1200
    
    
    class TestTagData(c4d.plugins.TagData):
        def Init(self, node):
            self.controllers_num = 0
            pd = c4d.PriorityData()
            if pd is None:
                raise MemoryError("Failed to create a priority data.")
            pd.SetPriorityValue(lValueID = c4d.PRIORITYVALUE_MODE, data = c4d.CYCLE_EXPRESSION)
            node[c4d.EXPRESSION_PRIORITY] = pd
            return True
    
        def Execute(self, tag, doc, op, bt, priority, flags):
            return c4d.EXECUTIONRESULT_OK
    
        def Message(self, node, type, data):
            if type == c4d.MSG_DESCRIPTION_COMMAND:
                if data["id"][0].id == c4d.TTESTTAG_BUTTON_ADD:
                    doc = c4d.documents.GetActiveDocument()
                    doc.StartUndo()                    #---------- This doesn't seem to work! ----------
                    doc.AddUndo(c4d.UNDOTYPE_CHANGE_NOCHILDREN, node)
                    self.controllers_num += 1
                    doc.EndUndo()                    #----------------------------------------
                    node.SetDirty(c4d.DIRTYFLAGS_DESCRIPTION)
                elif data["id"][0].id == c4d.TTESTTAG_BUTTON_REMOVE:
                    if self.controllers_num > 0:
                        doc = c4d.documents.GetActiveDocument()
                        doc.StartUndo()                    #---------- This doesn't seem to work! ----------
                        doc.AddUndo(c4d.UNDOTYPE_CHANGE_NOCHILDREN, node)
                        self.controllers_num -= 1
                        doc.EndUndo()                    #----------------------------------------
                        node.SetDirty(c4d.DIRTYFLAGS_DESCRIPTION)
            return True
    
        def GetDDescription(self, node, description, flags):
            if not description.LoadDescription(node.GetType()):
                return False
            singleId = description.GetSingleDescID()
            groupId = c4d.DescID(c4d.DescLevel(c4d.ID_TAGPROPERTIES))
            controllers_num = self.controllers_num
            if controllers_num > 0:
                for i in range(controllers_num):
                    linkId = c4d.DescID(c4d.DescLevel(LINK_NO + (i + 1)))
                    if singleId is None or linkId.IsPartOf(singleId)[0]:
                        link_bc = c4d.GetCustomDataTypeDefault(c4d.DTYPE_BASELISTLINK)
                        link_bc.SetString(c4d.DESC_NAME, "Controller " + str(i + 1))
                        link_bc.SetString(c4d.DESC_SHORT_NAME, "Controller " + str(i + 1))
                        link_bc.SetInt32(c4d.DESC_ANIMATE, c4d.DESC_ANIMATE_ON)
                        if not description.SetParameter(linkId, link_bc, groupId):
                            return False
                    floatId = c4d.DescID(c4d.DescLevel(FLOAT_NO + (i + 1)))
                    if singleId is None or floatId.IsPartOf(singleId)[0]:
                        float_bc = c4d.GetCustomDataTypeDefault(c4d.DTYPE_REAL)
                        float_bc.SetString(c4d.DESC_NAME, "Rate")
                        float_bc.SetString(c4d.DESC_SHORT_NAME, "Rate")
                        float_bc.SetFloat(c4d.DESC_DEFAULT, 1)
                        float_bc.SetInt32(c4d.DESC_ANIMATE, c4d.DESC_ANIMATE_ON)
                        float_bc.SetInt32(c4d.DESC_UNIT, c4d.DESC_UNIT_PERCENT)
                        float_bc.SetFloat(c4d.DESC_MIN, -1000)
                        float_bc.SetFloat(c4d.DESC_MAX, 1000)
                        float_bc.SetFloat(c4d.DESC_MINSLIDER, -1)
                        float_bc.SetFloat(c4d.DESC_MAXSLIDER, 1)
                        float_bc.SetFloat(c4d.DESC_STEP, 0.01)
                        float_bc.SetInt32(c4d.DESC_CUSTOMGUI, c4d.CUSTOMGUI_REALSLIDER)
                        if not description.SetParameter(floatId, float_bc, groupId):
                            return False
                    separatorId = c4d.DescID(0)
                    if singleId is None or separatorId.IsPartOf(singleId)[0]:
                        separator_bc = c4d.GetCustomDataTypeDefault(c4d.DTYPE_SEPARATOR)
                        separator_bc.SetInt32(c4d.DESC_CUSTOMGUI, c4d.CUSTOMGUI_SEPARATOR)
                        separator_bc.SetBool(c4d.DESC_SEPARATORLINE, True)
                        if not description.SetParameter(separatorId, separator_bc, groupId):
                            return False
            return (True, flags | c4d.DESCFLAGS_DESC_LOADED)
    
    
    if __name__ == "__main__":
        c4d.plugins.RegisterTagPlugin(id = PLUGIN_ID, str = "Test Tag", info = c4d.TAG_EXPRESSION|c4d.TAG_VISIBLE, g = TestTagData, description = "ttesttag", icon = None)
    

    ttesttag.res

    CONTAINER Ttesttag
    {
        NAME Ttesttag;
        INCLUDE Texpression;
    
        GROUP ID_TAGPROPERTIES
        {
            GROUP TTESTTAG_BUTTONS_GROUP
            {
                COLUMNS 2;
                BUTTON TTESTTAG_BUTTON_ADD { SCALE_H; }
                BUTTON TTESTTAG_BUTTON_REMOVE { SCALE_H; }
            }
        }
    }
    

    ttesttag.h

    #ifndef _TTESTTAG_H_
    #define _TTESTTAG_H_
    
    enum
    {
        TTESTTAG_BUTTONS_GROUP = 1001,
        TTESTTAG_BUTTON_ADD = 1002,
        TTESTTAG_BUTTON_REMOVE = 1003,
    }
    
    #endif
    

    ttesttag.str

    STRINGTABLE Ttesttag
    {
        Ttesttag "Test Tag";
        TTESTTAG_BUTTONS_GROUP "";
        TTESTTAG_BUTTON_ADD "Add";
        TTESTTAG_BUTTON_REMOVE "Remove";
    }
    

    ---------- User Information ----------

    Cinema 4D version: R23
    OS: Windows 10
    Language: Python

    posted in Cinema 4D SDK •
    RE: Attribute Manamger Update Delay When Description Added Dynamically

    @Cairyn Interesting investigation but it's a bit difficult for newbie like me. 🙄
    Anyway, I appreciate your help!

    posted in Cinema 4D SDK •