C4D 插件结构

插件结构

插件放在用户目录下的plugins目录。插件后缀该为.pyd, .pypv(加密文件)。 C4D 启动后,寻找并执行此目录下所有以.pyp 或 .pypv结尾的插件。一个简单的插件如下:

def main():
    print "Hello World!"

main()

这个插件不好玩,就能输出个hello world! 但是,我们可以在程序的各个部分注册插件钩子。

Hook 钩子

所有插件的钩子都从BaseData继承而来, 这些类包含能被C4D调用的方法。 MessageData的例子:

class SampleData(plugins.MessageData):

    def CoreMessage(self, id, bc):
        pass

Registration 注册

向C4D注册插件需使用Register() 。 注册函数可接收实例也能接收类,在内部自己创建对象:
plugins.RegisterCommandPlugin(id=PLUGIN_ID, str="TestBase-Plugin", info=0, dat=SampleData())

NodeData的注册方法需要一个类名:

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 生命周期

数据类的声明周期还有点说道,上面的例子中将新的实例传给了注册函数,在C4D的session周期内此实例都存在。其构造和析构函数正常调用,不用多想多做。需要将名字传给注册函数的数据类在C4D的节点上游对应的1:1标志,其生命周期和node一样,分配和删除都由C4D控制。其构造和析构也如常调用,但C4D会额外调用NodeData.Init()

Directory Structure 目录结构

.pyp 或.pypv 可以放在插件目录,将其组织成层次会更好。 插件的标准层次结构如下:

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 注册了钩子。 res目录包含插件资源,现指dialogs,description, strings。

每个description都会有一个.h文件,枚举了description用到的常量。 查看Descriptions in cinema4D。 每个dialog包含自己的 .res文件。 c4d_symbols.h包含了.res使用的常量。

可能会有个string_xx的目录来做国际化,xx是两个目录,代表一种语言,依据是iso 639,iso3361-1. 当前C4D有一下编码:

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

每种语言的目录应该包含dialog的.str文件。 c4d_string.str是给其他资源用的。 推荐的做法是先做一种语言,翻译前拷贝一份。最后你可以有很多文件,例如插件的icon和logo,这些可以方便地通过file访问

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

Plugin Messages 插件信息

PluginMessage(id, data)
定义此函数可以接收插件信息。 可以从C4D或者从其他插件调用GetPluginMessage()

Paste_Image.png

Command Line Arguments 命令行参数

随时接收C4D的命令行参数,实现PluginMessage() 填入C4DPL_COMMANDLINEARGS 信息:

import c4d
import sys
def PluginMessage(id, data):
        if id == c4d.C4DPL_COMMANDLINEARGS:
            print sys.argv 
  • 代码保存到.pyp 文件中,放在插件目录下。
  • 带参启动 C4D,比如Cinema 4D.exe -hello
  • 打开终端,其应该包含传入的参数。

警告
C4D模块维护的参数被移除了。 例如,”Cinema 4D.exe -hello -paralle" 打开终端,paralle不在打印的参数列表中。

重载python插件

C4D的函数重载,重编译.pyp文件。 被pyp文件import的库不会reload. python首先检查模块是否导入, 已导入就跳过,并建立引用.

当PluginMessage()接收到C4DPL_RELOADPYTHONPLUGINS , 可以用reload()来强制重载python模块. 此处可以关闭以前打开的资源(socket,file等)

增强主菜单

添加自己的菜单, 在PluginMessage()中拦截C4DPL_BUILDMENU, 并调用GetMenuResource()来接收主菜单容器,下面是一个完整的例子。

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” 消息之外修改了菜单,记得调用gui.UpdateMenus()

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容