C4D 插件結(jié)構(gòu)

插件結(jié)構(gòu)

插件放在用戶(hù)目錄下的plugins目錄。插件后綴該為.pyd, .pypv(加密文件)。 C4D 啟動(dòng)后,尋找并執(zhí)行此目錄下所有以.pyp 或 .pypv結(jié)尾的插件。一個(gè)簡(jiǎn)單的插件如下:

def main():
    print "Hello World!"

main()

這個(gè)插件不好玩,就能輸出個(gè)hello world! 但是,我們可以在程序的各個(gè)部分注冊(cè)插件鉤子。

Hook 鉤子

所有插件的鉤子都從BaseData繼承而來(lái), 這些類(lèi)包含能被C4D調(diào)用的方法。 MessageData的例子:

class SampleData(plugins.MessageData):

    def CoreMessage(self, id, bc):
        pass

Registration 注冊(cè)

向C4D注冊(cè)插件需使用Register() 。 注冊(cè)函數(shù)可接收實(shí)例也能接收類(lèi),在內(nèi)部自己創(chuàng)建對(duì)象:
plugins.RegisterCommandPlugin(id=PLUGIN_ID, str="TestBase-Plugin", info=0, dat=SampleData())

NodeData的注冊(cè)方法需要一個(gè)類(lèi)名:

class SampleData(plugins.ObjectData):
    def GetVirtualObjects(self, op, hierarchyhelp):
        pass

plugins.RegisterObjectPlugin(id=PLUGIN_ID, str="TestNode-Plugin",
                            g=SampleData, description="", icon=None,
                            info=c4d.OBJECT_GENERATOR)

Lifetime 生命周期

數(shù)據(jù)類(lèi)的聲明周期還有點(diǎn)說(shuō)道,上面的例子中將新的實(shí)例傳給了注冊(cè)函數(shù),在C4D的session周期內(nèi)此實(shí)例都存在。其構(gòu)造和析構(gòu)函數(shù)正常調(diào)用,不用多想多做。需要將名字傳給注冊(cè)函數(shù)的數(shù)據(jù)類(lèi)在C4D的節(jié)點(diǎn)上游對(duì)應(yīng)的1:1標(biāo)志,其生命周期和node一樣,分配和刪除都由C4D控制。其構(gòu)造和析構(gòu)也如常調(diào)用,但C4D會(huì)額外調(diào)用NodeData.Init()

Directory Structure 目錄結(jié)構(gòu)

.pyp 或.pypv 可以放在插件目錄,將其組織成層次會(huì)更好。 插件的標(biāo)準(zhǔn)層次結(jié)構(gòu)如下:

myPlugin/
    myPlugin.pyp
    ...
    res/
        c4d_symbols.h
        description/
            myDescription.h
            myDescription.res
            ...
        dialogs/
            myDialog.res
            ...

        strings_us/
            c4d_strings.str
            description/
                myDescription.str
                ...
            dialogs/
                myDialog.str
                ...
            strings_de/
            strings_jp/
            ...
    myIcon.tif
    myWhatever.any
    ...

主文件myPlugin.pyp 注冊(cè)了鉤子。 res目錄包含插件資源,現(xiàn)指dialogs,description, strings。

每個(gè)description都會(huì)有一個(gè).h文件,枚舉了description用到的常量。 查看Descriptions in cinema4D。 每個(gè)dialog包含自己的 .res文件。 c4d_symbols.h包含了.res使用的常量。

可能會(huì)有個(gè)string_xx的目錄來(lái)做國(guó)際化,xx是兩個(gè)目錄,代表一種語(yǔ)言,依據(jù)是iso 639,iso3361-1. 當(dāng)前C4D有一下編碼:

us - American English
de - German
fr - French
it - Italian
jp - Japanese

每種語(yǔ)言的目錄應(yīng)該包含dialog的.str文件。 c4d_string.str是給其他資源用的。 推薦的做法是先做一種語(yǔ)言,翻譯前拷貝一份。最后你可以有很多文件,例如插件的icon和logo,這些可以方便地通過(guò)file訪問(wèn)

dir, file= os.path.split(__file__)

Plugin Messages 插件信息

PluginMessage(id, data)
定義此函數(shù)可以接收插件信息。 可以從C4D或者從其他插件調(diào)用GetPluginMessage()

Paste_Image.png

Command Line Arguments 命令行參數(shù)

隨時(shí)接收C4D的命令行參數(shù),實(shí)現(xiàn)PluginMessage() 填入C4DPL_COMMANDLINEARGS 信息:

import c4d
import sys
def PluginMessage(id, data):
        if id == c4d.C4DPL_COMMANDLINEARGS:
            print sys.argv 
  • 代碼保存到.pyp 文件中,放在插件目錄下。
  • 帶參啟動(dòng) C4D,比如Cinema 4D.exe -hello
  • 打開(kāi)終端,其應(yīng)該包含傳入的參數(shù)。

警告
C4D模塊維護(hù)的參數(shù)被移除了。 例如,”Cinema 4D.exe -hello -paralle" 打開(kāi)終端,paralle不在打印的參數(shù)列表中。

重載python插件

C4D的函數(shù)重載,重編譯.pyp文件。 被pyp文件import的庫(kù)不會(huì)reload. python首先檢查模塊是否導(dǎo)入, 已導(dǎo)入就跳過(guò),并建立引用.

當(dāng)PluginMessage()接收到C4DPL_RELOADPYTHONPLUGINS , 可以用reload()來(lái)強(qiáng)制重載python模塊. 此處可以關(guān)閉以前打開(kāi)的資源(socket,file等)

增強(qiáng)主菜單

添加自己的菜單, 在PluginMessage()中攔截C4DPL_BUILDMENU, 并調(diào)用GetMenuResource()來(lái)接收主菜單容器,下面是一個(gè)完整的例子。

def EnhanceMainMenu():
    mainMenu = gui.GetMenuResource("M_EDITOR")  # Get main menu resource
    pluginsMenu = gui.SearchPluginMenuResource()  # Get 'Plugins' main menu resource

    menu = c4d.BaseContainer()  # Create a container to hold a new menu information

    menu.InsData(c4d.MENURESOURCE_SUBTITLE, "Py-Test")  # Set the name of the menu
    menu.InsData(c4d.MENURESOURCE_COMMAND, "IDM_NEU")  # Add registered default command 'New Scene' to the menu
    menu.InsData(c4d.MENURESOURCE_SEPERATOR, True);  # Add a separator
    menu.InsData(c4d.MENURESOURCE_COMMAND, "PLUGIN_CMD_5159")  # Add command 'Cube' with ID 5159 to the menu

    submenu = c4d.BaseContainer()  # Create a new submenu container
    submenu.InsData(c4d.MENURESOURCE_SUBTITLE, "Submenu")  # This is a submenu
    submenu.InsData(c4d.MENURESOURCE_COMMAND, "IDM_SPEICHERN")  # Add registered default command 'Save' to the menu

    menu.InsData(c4d.MENURESOURCE_SUBMENU, submenu)  # Add the submenu
    if pluginsMenu:
        # Insert menu after 'Plugins' menu
        mainMenu.InsDataAfter(c4d.MENURESOURCE_STRING, menu, pluginsMenu)
    else:
    # Insert menu after the last existing menu ('Plugins' menu was not found)
        mainMenu.InsData(c4d.MENURESOURCE_STRING, menu)

def PluginMessage(id, data):
    if id == c4d.C4DPL_BUILDMENU:
        EnhanceMainMenu()

注意
如果在“C4DPL_BUILDMENU” 消息之外修改了菜單,記得調(diào)用gui.UpdateMenus()

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容