一、创建自定义属性类型及代码分析

向插件的构造函数中添加一些代码,其中,第5-23行为新添加代码

class PLUGINDEMO_API Plugindemo : public kanzi::Node3D
{
public://字符串属性static kanzi::PropertyType<kanzi::string> StringProperty;//引用节点的字符串static kanzi::PropertyType<kanzi::string> NodeRefByStringProperty;//引用预设件的字符串static kanzi::PropertyType<kanzi::string> PrefabRefByStringProperty;//引用预设件的共享指针static kanzi::PropertyType<kanzi::ResourceSharedPtr> PrefabRefBySharedPtrProperty;//引用材质的共享指针static kanzi::PropertyType<kanzi::ResourceSharedPtr> MaterialRefBySharedPtrProperty;KZ_METACLASS_BEGIN(Plugindemo, Node3D, "MyNode")//将属性类型添加到类元数据。KZ_METACLASS_PROPERTY_TYPE(StringProperty)KZ_METACLASS_PROPERTY_TYPE(NodeRefByStringProperty)KZ_METACLASS_PROPERTY_TYPE(PrefabRefByStringProperty)KZ_METACLASS_PROPERTY_TYPE(PrefabRefBySharedPtrProperty)KZ_METACLASS_PROPERTY_TYPE(MaterialRefBySharedPtrProperty)KZ_METACLASS_END()static kanzi::PropertyTypeEditorInfoSharedPtr makeEditorInfo();// Creates a Plugindemo.static PlugindemoSharedPtr create(kanzi::Domain* domain, kanzi::string_view name);protected:// Constructor.explicit Plugindemo(kanzi::Domain* domain, kanzi::string_view name):kanzi::Node3D(domain, name){}// Initializes the created Kanzi Engine plugin.// Kanzi node classes typically have a static create() member function, which creates the instance of a node,// initializes it, and returns a shared pointer to the instance. To initialize the instance, the initialize()// function is called on it. You must initialize a node in the initialize() function, not in the constructor.void initialize();
};

上述代码中PropertyType是一个模板类,利用该模板类声明了五个属性对象。在

KZ_METACLASS_BEGIN(Plugindemo, Node3D, "MyNode")
KZ_METACLASS_END()

中间添加了五个宏,宏展开的代码如下

#define KZ_METACLASS_PROPERTY_TYPE(propertyType)\metaclass.addPropertyType(propertyType);addPropertyType实现如下void addPropertyType(AbstractPropertyType propertyType)
{kzAssert(propertyType);checkSealed();m_propertyTypes.push_back(propertyType);
}

其中m_propertyTypes的类型是一个容器

PropertyTypeContainer m_propertyTypes;
typedef vector<AbstractPropertyType> PropertyTypeContainer;

这个类型实质就是vector<AbstractPropertyType>的别名,当把各个属性添加到容器中时,会调用PropertyType中的类型转换运算符将各个属性统一成AbstractPropertyType对象

operator AbstractPropertyType() const
{return AbstractPropertyType(m_propertyType);
}

所以,这五个宏的作用就是将这五个属性添加到元类对象中

之后,在类外对这五个static成员进行初始化,初始化的代码如下

PropertyType<string> Plugindemo::StringProperty(kzMakeFixedString("Plugindemo.String"), "", 0, false,KZ_DECLARE_EDITOR_METADATA(metadata.displayName = "String";
));PropertyType<string> Plugindemo::NodeRefByStringProperty(kzMakeFixedString("Plugindemo.NodeRefByString"), "", 0, false,KZ_DECLARE_EDITOR_METADATA(metadata.displayName = "Node Reference by String";metadata.valueProvider = "ProjectObject:Node3D";
));PropertyType<string> Plugindemo::PrefabRefByStringProperty(kzMakeFixedString("Plugindemo.PrefabRefByString"), "", 0, false,KZ_DECLARE_EDITOR_METADATA(metadata.displayName = "Prefab Reference by String";      metadata.valueProvider = "ProjectObject:PrefabTemplate";
));PropertyType<ResourceSharedPtr> Plugindemo::PrefabRefBySharedPtrProperty(kzMakeFixedString("Plugindemo.PrefabRefBySharedPtr"), ResourceSharedPtr(), 0, false,KZ_DECLARE_EDITOR_METADATA(metadata.displayName = "Prefab Reference by Shared Pointer";  metadata.valueProvider = "ProjectObject:PrefabTemplate";
));PropertyType<ResourceSharedPtr> Plugindemo::MaterialRefBySharedPtrProperty(kzMakeFixedString("Plugindemo.MaterialRefBySharedPtr"), ResourceSharedPtr(), 0, false,KZ_DECLARE_EDITOR_METADATA(metadata.displayName = "Material Reference by Shared Pointer";metadata.valueProvider = "ProjectObject:Material";
));

上述五个属性的初始化分别调用了PropertyType的构造函数,其中被调用到的构造函数实现如下

explicit PropertyType(FixedString name, DataType defaultValue, uint32_t changeFlags, bool inheritable, PropertyTypeEditorInfo* editorInfo) :m_propertyType(create(name, defaultValue, changeFlags, inheritable, PropertyTypeEditorInfoSharedPtr(editorInfo)))
{
}

其中第一个参数的实参是宏kzMakeFixedString展开的结果,kzMakeFixedString的展开如下

#define kzMakeFixedString(x)    x ## _kzfixed

这个展开结果会直接调用operator"" _kzfixed,operator"" _kzfixed的实现如下,可见,最终通过字面值操作符返回的是一个FixedString的临时对象

inline FixedString operator"" _kzfixed(const char* s, std::size_t)
{return FixedString(s);
}

所以,通过上述流程,PropertyType构造函数的第一个参数的实参是一个FixedString的临时对象,其中,FixedString构造函数中的实参是传入宏kzMakeFixedString的参数(也就是Plugindemo.String, Plugindemo.NodeRefByString等等)

第二个参数的类型是一个模板参数类型的别名,如果模板参数类型是一个string,那么直接传入空字符串,如果模板参数类型是一个ResourceSharedPtr,直接传入一个临时对象。

最后一个参数是PropertyTypeEditorInfo的指针,其定义见上一篇,这里通过宏KZ_DECLARE_EDITOR_METADATA展开对PropertyTypeEditorInfo的指针进行初始化

#define KZ_DECLARE_EDITOR_METADATA(x)  new kanzi::PropertyTypeEditorInfo(
[]() -> kanzi::PropertyTypeEditorInfo::AttributeDictionary { kanzi::PropertyTypeEditorInfo::AttributeDictionary metadata; x  return metadata; }()
)

可见,通过该宏展开,最终new了一个PropertyTypeEditorInfo的对象,这个对象是通过一个lambda表达式返回的meta数据进行初始化的

PropertyType的成员m_propertyType的类型定义如下

Descriptor* m_propertyType;

该成员的初始化是靠create函数和传给PropertyType构造函数的参数共同进行初始化

create的实现如下

Descriptor* create(FixedString name, DataType defaultValue, uint32_t changeFlags, bool inherited, PropertyTypeEditorInfoSharedPtr editorInfo)
{return new Descriptor(name, defaultValue, changeFlags, inherited, editorInfo);
}

其中Descriptor的定义如下

typedef PropertyTypeDescriptor<Type> Descriptor;

PropertyTypeDescriptor的部分定义如下

template <typename T>
class PropertyTypeDescriptor : public AbstractPropertyTypeDescriptor
{
public:explicit PropertyTypeDescriptor(FixedString name, typename Traits::ParameterType defaultValue, uint32_t changeFlags, bool inherited, PropertyTypeEditorInfoSharedPtr editorInfo) :AbstractPropertyTypeDescriptor(name, changeFlags, inherited, editorInfo){Traits::write(m_defaultValue, defaultValue);}
};

可见,最终在构造函数执行了一个写入的操作。

Trait的实现如下

typedef PropertyDataTypeTraits<T> Traits;

PropertyDataTypeTraits的特化了多个模板类,其中string和ResourceSharedPtr的特化版本实现如下

template <>
struct PropertyDataTypeTraits<ResourceSharedPtr> : public detail::ComplexDataTypeTraits<ResourceSharedPtr>
{static const PropertyDataType dataType = PropertyDataTypeResource;
};template <>
struct PropertyDataTypeTraits<string>
{typedef string StorageType;typedef string_view ParameterType;typedef string ReturnType;static const PropertyDataType dataType = PropertyDataTypeString;static inline void write(StorageType& storage, ParameterType parameter){storage.assign(cbegin(parameter), cend(parameter));}static inline const string& read(const StorageType& storage){return storage;}
};

ResourceSharedPtr的特化版本没有write,会调用父类中的write,其实现如下

template <typename T>
struct ComplexDataTypeTraits
{typedef T StorageType;typedef const T& ParameterType;typedef T ReturnType;static inline void write(StorageType& storage, ParameterType value){storage = value;}
};

上述两个函数的本质就是一个枚举的初始化和一个赋值,调用完之后,StringProperty就初始化完成了

二、效果

编译插件工程,并更新插件

至此,可以为自定义的节点设置自定义的属性

参考

《Kanzi官方文档》

14、Kanzi插件——通过Kanzi Engine插件创建自定义属性类型及其元数据+代码解析相关推荐

  1. 12、Kanzi插件——创建Kanzi Engine插件的方法

    可以使用模板自动创建Kanzi Engine插件 模板选为含有Kanzi Engine插件的应用 注意:工程名不能叫plugin,因为VS工程会根据该工程名设置定义具体的类,如果命名为plugin,那 ...

  2. 15、Kanzi插件——通过Kanzi Engine插件创建自定义消息类型+代码解析

    一.创建trigger中的自定义消息 比如,想创建一个当汽车燃油量发生变化时对应的消息,可以进行如下操作 首先,在插件工程中的头文件中定义一个嵌套类,下面代码中的第23行和29-44行为新添加代码 # ...

  3. 13、Kanzi插件——通过Kanzi Engine插件创建自定义节点+代码解析

    一.通过插件创建自定义类型的节点 在类Plugindemo 中添加一行 static kanzi::PropertyTypeEditorInfoSharedPtr makeEditorInfo(); ...

  4. 16、Kanzi插件——通过Kanzi Engine插件创建自定义动作+代码解析

    一.创建自定义动作 当收到燃油变化的消息时,相应动作代码整体如下 class PLUGINDEMO_API Plugindemo : public kanzi::Node3D { public://字 ...

  5. 【Flutter】开发 Flutter 包和插件 ( Flutter 包和插件简介 | 创建 Flutter 插件 | 创建 Dart 包 )

    文章目录 一.Flutter 包和插件简介 二.创建 Flutter 插件 1.Android Studio 中可视化创建 2.命令行创建 三.创建 Dart 包 1.Android Studio 中 ...

  6. 【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | 主线程创建 Activity 实例之前使用插件 Activity 类替换占位的组件 )

    Android 插件化系列文章目录 [Android 插件化]插件化简介 ( 组件化与插件化 ) [Android 插件化]插件化原理 ( JVM 内存数据 | 类加载流程 ) [Android 插件 ...

  7. 【Android 插件化】Hook 插件化框架 ( 创建插件应用 | 拷贝插件 APK | 初始化插件包 | 测试插件 DEX 字节码 )

    Android 插件化系列文章目录 [Android 插件化]插件化简介 ( 组件化与插件化 ) [Android 插件化]插件化原理 ( JVM 内存数据 | 类加载流程 ) [Android 插件 ...

  8. 【Android 插件化】“ 插桩式 “ 插件化框架 ( 类加载器创建 | 资源加载 )

    Android 插件化系列文章目录 [Android 插件化]插件化简介 ( 组件化与插件化 ) [Android 插件化]插件化原理 ( JVM 内存数据 | 类加载流程 ) [Android 插件 ...

  9. 从零开始实现ASP.NET Core MVC的插件式开发(二) - 如何创建项目模板

    标题:从零开始实现ASP.NET Core MVC的插件式开发(二) - 如何创建项目模板 作者:Lamond Lu 地址:https://www.cnblogs.com/lwqlun/p/11155 ...

最新文章

  1. java map 红黑树_Java集合-TreeMap和红黑树
  2. springMVC之Interceptor拦截器
  3. 解析rtcm32报文工具_RTCM32编解码中的一些概念及相关文献阅读
  4. java中Object.equals()简单用法
  5. springcloud Feign工程熔断器Hystrix
  6. 军事医学研究院应晓敏组招聘博士后
  7. 【ES6(2015)】Map
  8. webug第十二关:我系统密码忘记了!
  9. jsp a标签传值到action中,action接收不到传值
  10. 在Github上搭建你的博客
  11. (ubuntu 下)tensorflow 的安装及版本升级
  12. python医药数据,PostgreSQL+Python实现药品规格数值与单位拆分
  13. 迅捷cad_迅捷泛型
  14. 10x程序员是如何思考的?
  15. 此笔记只作为自身笔记,结构比较混乱,不建议参考,如有需要请访问其他文献,servlet的基础知识和使用
  16. ios dat 文件读写_玩转你的iphone, IOS 13 NFC标签读写详细步骤
  17. 数据分析统计工具有哪些?
  18. winpe进入linux系统,制作U盘Linux 与WinPE启动
  19. ifconfig 命令使用
  20. python清洗数据去除停用词_python之NLP数据清洗

热门文章

  1. 【课程全解】-UML软件建模设计
  2. typora配置好smms后还是typora上传图片失败:image load failed。
  3. Entrust Datacard完成对泰雷兹旗下市场领先的通用硬件安全公司nCipher Security的收购
  4. Zbrush学习笔记
  5. svg 可视化操作_使用SVG和D3可视化浏览指标
  6. Unity自定义创建文件夹
  7. 看脸的世界:牙齿整齐找工作更容易
  8. 关闭和开启笔记本自带键盘。
  9. Combined Margin loss人脸识别训练笔记
  10. sqlserver分组统计最新一条数据