插件結(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()
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()