mirror of
https://github.com/godotengine/godot.git
synced 2025-11-03 07:01:06 +00:00
Added ability to create custom nodes from script.
This commit is contained in:
parent
0b8f0670c5
commit
cfbdeeffec
5 changed files with 320 additions and 0 deletions
|
|
@ -60,6 +60,7 @@ void register_visual_script_types() {
|
||||||
ObjectTypeDB::register_type<VisualScriptSceneTree>();
|
ObjectTypeDB::register_type<VisualScriptSceneTree>();
|
||||||
ObjectTypeDB::register_type<VisualScriptResourcePath>();
|
ObjectTypeDB::register_type<VisualScriptResourcePath>();
|
||||||
ObjectTypeDB::register_type<VisualScriptSelf>();
|
ObjectTypeDB::register_type<VisualScriptSelf>();
|
||||||
|
ObjectTypeDB::register_type<VisualScriptCustomNode>();
|
||||||
|
|
||||||
ObjectTypeDB::register_type<VisualScriptFunctionCall>();
|
ObjectTypeDB::register_type<VisualScriptFunctionCall>();
|
||||||
ObjectTypeDB::register_type<VisualScriptPropertySet>();
|
ObjectTypeDB::register_type<VisualScriptPropertySet>();
|
||||||
|
|
|
||||||
|
|
@ -2548,6 +2548,9 @@ void VisualScriptLanguage::get_registered_node_names(List<String> *r_names) {
|
||||||
VisualScriptLanguage::VisualScriptLanguage() {
|
VisualScriptLanguage::VisualScriptLanguage() {
|
||||||
|
|
||||||
notification="_notification";
|
notification="_notification";
|
||||||
|
_get_output_port_unsequenced="_get_output_port_unsequenced";
|
||||||
|
_step="_step";
|
||||||
|
|
||||||
singleton=this;
|
singleton=this;
|
||||||
#ifndef NO_THREADS
|
#ifndef NO_THREADS
|
||||||
lock = Mutex::create();
|
lock = Mutex::create();
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,8 @@ friend class VisualScript;
|
||||||
Array _get_default_input_values() const;
|
Array _get_default_input_values() const;
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
virtual bool _use_builtin_script() const { return false; }
|
||||||
|
|
||||||
void _notification(int p_what);
|
void _notification(int p_what);
|
||||||
void ports_changed_notify();
|
void ports_changed_notify();
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
|
@ -466,6 +468,8 @@ class VisualScriptLanguage : public ScriptLanguage {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
StringName notification;
|
StringName notification;
|
||||||
|
StringName _get_output_port_unsequenced;
|
||||||
|
StringName _step;
|
||||||
|
|
||||||
static VisualScriptLanguage* singleton;
|
static VisualScriptLanguage* singleton;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2037,6 +2037,266 @@ VisualScriptSelf::VisualScriptSelf() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////
|
||||||
|
////////////////CUSTOM (SCRIPTED)///////////
|
||||||
|
//////////////////////////////////////////
|
||||||
|
|
||||||
|
int VisualScriptCustomNode::get_output_sequence_port_count() const {
|
||||||
|
|
||||||
|
if (get_script_instance() && get_script_instance()->has_method("_get_output_sequence_port_count")) {
|
||||||
|
return get_script_instance()->call("_get_output_sequence_port_count");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VisualScriptCustomNode::has_input_sequence_port() const{
|
||||||
|
|
||||||
|
if (get_script_instance() && get_script_instance()->has_method("_has_input_sequence_port")) {
|
||||||
|
return get_script_instance()->call("_has_input_sequence_port");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int VisualScriptCustomNode::get_input_value_port_count() const{
|
||||||
|
|
||||||
|
if (get_script_instance() && get_script_instance()->has_method("_get_input_value_port_count")) {
|
||||||
|
return get_script_instance()->call("_get_input_value_port_count");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int VisualScriptCustomNode::get_output_value_port_count() const{
|
||||||
|
|
||||||
|
if (get_script_instance() && get_script_instance()->has_method("_get_output_value_port_count")) {
|
||||||
|
return get_script_instance()->call("_get_output_value_port_count");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
String VisualScriptCustomNode::get_output_sequence_port_text(int p_port) const {
|
||||||
|
|
||||||
|
if (get_script_instance() && get_script_instance()->has_method("_get_output_sequence_port_text")) {
|
||||||
|
return get_script_instance()->call("_get_output_sequence_port_text",p_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyInfo VisualScriptCustomNode::get_input_value_port_info(int p_idx) const{
|
||||||
|
|
||||||
|
PropertyInfo info;
|
||||||
|
if (get_script_instance() && get_script_instance()->has_method("_get_input_value_port_type")) {
|
||||||
|
info.type=Variant::Type(int(get_script_instance()->call("_get_input_value_port_type",p_idx)));
|
||||||
|
}
|
||||||
|
if (get_script_instance() && get_script_instance()->has_method("_get_input_value_port_name")) {
|
||||||
|
info.name=get_script_instance()->call("_get_input_value_port_name",p_idx);
|
||||||
|
}
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyInfo VisualScriptCustomNode::get_output_value_port_info(int p_idx) const{
|
||||||
|
|
||||||
|
PropertyInfo info;
|
||||||
|
if (get_script_instance() && get_script_instance()->has_method("_get_output_value_port_type")) {
|
||||||
|
info.type=Variant::Type(int(get_script_instance()->call("_get_output_value_port_type",p_idx)));
|
||||||
|
}
|
||||||
|
if (get_script_instance() && get_script_instance()->has_method("_get_output_value_port_name")) {
|
||||||
|
info.name=get_script_instance()->call("_get_output_value_port_name",p_idx);
|
||||||
|
}
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
String VisualScriptCustomNode::get_caption() const {
|
||||||
|
|
||||||
|
if (get_script_instance() && get_script_instance()->has_method("_get_caption")) {
|
||||||
|
return get_script_instance()->call("_get_caption");
|
||||||
|
}
|
||||||
|
return "CustomNode";
|
||||||
|
}
|
||||||
|
|
||||||
|
String VisualScriptCustomNode::get_text() const {
|
||||||
|
|
||||||
|
if (get_script_instance() && get_script_instance()->has_method("_get_text")) {
|
||||||
|
return get_script_instance()->call("_get_text");
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
String VisualScriptCustomNode::get_category() const {
|
||||||
|
|
||||||
|
if (get_script_instance() && get_script_instance()->has_method("_get_category")) {
|
||||||
|
return get_script_instance()->call("_get_category");
|
||||||
|
}
|
||||||
|
return "custom";
|
||||||
|
}
|
||||||
|
|
||||||
|
class VisualScriptNodeInstanceCustomNode : public VisualScriptNodeInstance {
|
||||||
|
public:
|
||||||
|
|
||||||
|
VisualScriptInstance* instance;
|
||||||
|
VisualScriptCustomNode *node;
|
||||||
|
int in_count;
|
||||||
|
int out_count;
|
||||||
|
int work_mem_size;
|
||||||
|
Vector<bool> out_unsequenced;
|
||||||
|
|
||||||
|
virtual int get_working_memory_size() const { return work_mem_size; }
|
||||||
|
virtual bool is_output_port_unsequenced(int p_idx) const { return out_unsequenced[p_idx]; }
|
||||||
|
virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const {
|
||||||
|
|
||||||
|
if (!node->get_script_instance() || !node->get_script_instance()->has_method(VisualScriptLanguage::singleton->_get_output_port_unsequenced)) {
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
r_error=RTR("Custom node has no _get_output_port_unsequenced(idx,wmem), but unsequenced ports were specified.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Array work_mem(true);
|
||||||
|
work_mem.resize(work_mem_size);
|
||||||
|
|
||||||
|
*r_value = node->get_script_instance()->call(VisualScriptLanguage::singleton->_get_output_port_unsequenced,p_idx,work_mem);
|
||||||
|
|
||||||
|
|
||||||
|
for(int i=0;i<work_mem_size;i++) {
|
||||||
|
if (i<work_mem.size()) {
|
||||||
|
p_working_mem[i]=work_mem[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
|
||||||
|
|
||||||
|
if (node->get_script_instance()) {
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
if (!node->get_script_instance()->has_method(VisualScriptLanguage::singleton->_step)) {
|
||||||
|
r_error_str=RTR("Custom node has no _step() method, can't process graph.");
|
||||||
|
r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
Array in_values(true);
|
||||||
|
Array out_values(true);
|
||||||
|
Array work_mem(true);
|
||||||
|
|
||||||
|
in_values.resize(in_count);
|
||||||
|
|
||||||
|
for(int i=0;i<in_count;i++) {
|
||||||
|
in_values[i]=p_inputs[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
out_values.resize(in_count);
|
||||||
|
|
||||||
|
work_mem.resize(work_mem_size);
|
||||||
|
|
||||||
|
for(int i=0;i<work_mem_size;i++) {
|
||||||
|
work_mem[i]=p_working_mem[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret_out;
|
||||||
|
|
||||||
|
Variant ret = node->get_script_instance()->call(VisualScriptLanguage::singleton->_step,in_values,out_values,p_start_mode,work_mem);
|
||||||
|
if (ret.get_type()==Variant::STRING) {
|
||||||
|
r_error_str=ret;
|
||||||
|
r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
|
||||||
|
return 0;
|
||||||
|
} else if (ret.is_num()) {
|
||||||
|
ret_out=ret;
|
||||||
|
} else {
|
||||||
|
r_error_str=RTR("Invalid return value from _step(), must be integer (seq out), or string (error).");
|
||||||
|
r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i=0;i<out_count;i++) {
|
||||||
|
if (i<out_values.size()) {
|
||||||
|
*p_outputs[i]=out_values[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i=0;i<work_mem_size;i++) {
|
||||||
|
if (i<work_mem.size()) {
|
||||||
|
p_working_mem[i]=work_mem[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret_out;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
VisualScriptNodeInstance* VisualScriptCustomNode::instance(VisualScriptInstance* p_instance) {
|
||||||
|
|
||||||
|
VisualScriptNodeInstanceCustomNode * instance = memnew(VisualScriptNodeInstanceCustomNode );
|
||||||
|
instance->instance=p_instance;
|
||||||
|
instance->in_count=get_input_value_port_count();
|
||||||
|
instance->out_count=get_output_value_port_count();
|
||||||
|
|
||||||
|
for(int i=0;i<instance->out_count;i++) {
|
||||||
|
bool unseq = get_script_instance() && get_script_instance()->has_method("_is_output_port_unsequenced") && bool(get_script_instance()->call("_is_output_port_unsequenced",i));
|
||||||
|
instance->out_unsequenced.push_back(unseq);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (get_script_instance() && get_script_instance()->has_method("_get_working_memory_size")) {
|
||||||
|
instance->work_mem_size = get_script_instance()->call("_get_working_memory_size");
|
||||||
|
} else {
|
||||||
|
instance->work_mem_size=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void VisualScriptCustomNode::_bind_methods() {
|
||||||
|
|
||||||
|
BIND_VMETHOD( MethodInfo(Variant::INT,"_get_output_sequence_port_count") );
|
||||||
|
BIND_VMETHOD( MethodInfo(Variant::BOOL,"_has_input_sequence_port") );
|
||||||
|
|
||||||
|
BIND_VMETHOD( MethodInfo(Variant::STRING,"_get_output_sequence_port_text",PropertyInfo(Variant::INT,"idx")) );
|
||||||
|
BIND_VMETHOD( MethodInfo(Variant::INT,"_get_input_value_port_count") );
|
||||||
|
BIND_VMETHOD( MethodInfo(Variant::INT,"_get_output_value_port_count") );
|
||||||
|
|
||||||
|
BIND_VMETHOD( MethodInfo(Variant::INT,"_get_input_value_port_type",PropertyInfo(Variant::INT,"idx")) );
|
||||||
|
BIND_VMETHOD( MethodInfo(Variant::STRING,"_get_input_value_port_name",PropertyInfo(Variant::INT,"idx")) );
|
||||||
|
|
||||||
|
BIND_VMETHOD( MethodInfo(Variant::INT,"_get_output_value_port_type",PropertyInfo(Variant::INT,"idx")) );
|
||||||
|
BIND_VMETHOD( MethodInfo(Variant::STRING,"_get_output_value_port_name",PropertyInfo(Variant::INT,"idx")) );
|
||||||
|
|
||||||
|
BIND_VMETHOD( MethodInfo(Variant::STRING,"_get_caption") );
|
||||||
|
BIND_VMETHOD( MethodInfo(Variant::STRING,"_get_text") );
|
||||||
|
BIND_VMETHOD( MethodInfo(Variant::STRING,"_get_category") );
|
||||||
|
|
||||||
|
BIND_VMETHOD( MethodInfo(Variant::INT,"_get_working_memory_size") );
|
||||||
|
BIND_VMETHOD( MethodInfo(Variant::INT,"_is_output_port_unsequenced",PropertyInfo(Variant::INT,"idx")) );
|
||||||
|
BIND_VMETHOD( MethodInfo(Variant::INT,"_get_output_port_unsequenced",PropertyInfo(Variant::INT,"idx"),PropertyInfo(Variant::ARRAY,"work_mem")) );
|
||||||
|
BIND_VMETHOD( MethodInfo(Variant::NIL,"_step:Variant",PropertyInfo(Variant::ARRAY,"inputs"),PropertyInfo(Variant::ARRAY,"outputs"),PropertyInfo(Variant::INT,"start_mode"),PropertyInfo(Variant::ARRAY,"working_mem")) );
|
||||||
|
|
||||||
|
BIND_CONSTANT( START_MODE_BEGIN_SEQUENCE );
|
||||||
|
BIND_CONSTANT( START_MODE_CONTINUE_SEQUENCE );
|
||||||
|
BIND_CONSTANT( START_MODE_RESUME_YIELD );
|
||||||
|
|
||||||
|
BIND_CONSTANT( STEP_PUSH_STACK_BIT );
|
||||||
|
BIND_CONSTANT( STEP_GO_BACK_BIT );
|
||||||
|
BIND_CONSTANT( STEP_NO_ADVANCE_BIT );
|
||||||
|
BIND_CONSTANT( STEP_EXIT_FUNCTION_BIT );
|
||||||
|
BIND_CONSTANT( STEP_YIELD_BIT );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
VisualScriptCustomNode::VisualScriptCustomNode() {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void register_visual_script_nodes() {
|
void register_visual_script_nodes() {
|
||||||
|
|
||||||
|
|
@ -2050,6 +2310,7 @@ void register_visual_script_nodes() {
|
||||||
VisualScriptLanguage::singleton->add_register_func("data/scene_tree",create_node_generic<VisualScriptSceneTree>);
|
VisualScriptLanguage::singleton->add_register_func("data/scene_tree",create_node_generic<VisualScriptSceneTree>);
|
||||||
VisualScriptLanguage::singleton->add_register_func("data/resource_path",create_node_generic<VisualScriptResourcePath>);
|
VisualScriptLanguage::singleton->add_register_func("data/resource_path",create_node_generic<VisualScriptResourcePath>);
|
||||||
VisualScriptLanguage::singleton->add_register_func("data/self",create_node_generic<VisualScriptSelf>);
|
VisualScriptLanguage::singleton->add_register_func("data/self",create_node_generic<VisualScriptSelf>);
|
||||||
|
VisualScriptLanguage::singleton->add_register_func("custom/custom_node",create_node_generic<VisualScriptCustomNode>);
|
||||||
|
|
||||||
|
|
||||||
VisualScriptLanguage::singleton->add_register_func("index/get_index",create_node_generic<VisualScriptIndexGet>);
|
VisualScriptLanguage::singleton->add_register_func("index/get_index",create_node_generic<VisualScriptIndexGet>);
|
||||||
|
|
|
||||||
|
|
@ -559,6 +559,57 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class VisualScriptCustomNode: public VisualScriptNode {
|
||||||
|
|
||||||
|
OBJ_TYPE(VisualScriptCustomNode,VisualScriptNode)
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
virtual bool _use_builtin_script() const { return true; }
|
||||||
|
|
||||||
|
static void _bind_methods();
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum StartMode { //replicated for step
|
||||||
|
START_MODE_BEGIN_SEQUENCE,
|
||||||
|
START_MODE_CONTINUE_SEQUENCE,
|
||||||
|
START_MODE_RESUME_YIELD
|
||||||
|
};
|
||||||
|
|
||||||
|
enum { //replicated for step
|
||||||
|
STEP_SHIFT=1<<24,
|
||||||
|
STEP_MASK=STEP_SHIFT-1,
|
||||||
|
STEP_PUSH_STACK_BIT=STEP_SHIFT, //push bit to stack
|
||||||
|
STEP_GO_BACK_BIT=STEP_SHIFT<<1, //go back to previous node
|
||||||
|
STEP_NO_ADVANCE_BIT=STEP_SHIFT<<2, //do not advance past this node
|
||||||
|
STEP_EXIT_FUNCTION_BIT=STEP_SHIFT<<3, //return from function
|
||||||
|
STEP_YIELD_BIT=STEP_SHIFT<<4, //yield (will find VisualScriptFunctionState state in first working memory)
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual int get_output_sequence_port_count() const;
|
||||||
|
virtual bool has_input_sequence_port() const;
|
||||||
|
|
||||||
|
|
||||||
|
virtual String get_output_sequence_port_text(int p_port) const;
|
||||||
|
|
||||||
|
|
||||||
|
virtual int get_input_value_port_count() const;
|
||||||
|
virtual int get_output_value_port_count() const;
|
||||||
|
|
||||||
|
|
||||||
|
virtual PropertyInfo get_input_value_port_info(int p_idx) const;
|
||||||
|
virtual PropertyInfo get_output_value_port_info(int p_idx) const;
|
||||||
|
|
||||||
|
virtual String get_caption() const;
|
||||||
|
virtual String get_text() const;
|
||||||
|
virtual String get_category() const;
|
||||||
|
|
||||||
|
virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
|
||||||
|
|
||||||
|
VisualScriptCustomNode();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
void register_visual_script_nodes();
|
void register_visual_script_nodes();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue