diff --git a/core/error_macros.h b/core/error_macros.h index 76da88287bb..cc88686301a 100644 --- a/core/error_macros.h +++ b/core/error_macros.h @@ -207,6 +207,11 @@ extern bool _err_error_exists; _err_error_exists=false;\ } \ +#define ERR_PRINTS(m_string) \ + { \ + _err_print_error(FUNCTION_STR,__FILE__,__LINE__,String(m_string).utf8().get_data()); \ + _err_error_exists=false;\ + } \ /** Print a warning string. */ diff --git a/core/object.cpp b/core/object.cpp index 3a4c06e7e7b..96f0c868321 100644 --- a/core/object.cpp +++ b/core/object.cpp @@ -314,6 +314,7 @@ void Object::set(const StringName& p_name, const Variant& p_value, bool *r_valid _edited=true; #endif + if (script_instance) { if (script_instance->set(p_name,p_value)) { @@ -326,9 +327,9 @@ void Object::set(const StringName& p_name, const Variant& p_value, bool *r_valid //try built-in setgetter { - if (ObjectTypeDB::set_property(this,p_name,p_value)) { - if (r_valid) - *r_valid=true; + if (ObjectTypeDB::set_property(this,p_name,p_value,r_valid)) { + //if (r_valid) + // *r_valid=true; return; } } @@ -1694,6 +1695,26 @@ void Object::get_translatable_strings(List *p_strings) const { } +Variant::Type Object::get_static_property_type(const StringName& p_property, bool *r_valid) const { + + bool valid; + Variant::Type t = ObjectTypeDB::get_property_type(get_type_name(),p_property,&valid); + if (valid) { + if (r_valid) + *r_valid=true; + return t; + } + + if (get_script_instance()) { + return get_script_instance()->get_property_type(p_property,r_valid); + } + if (r_valid) + *r_valid=false; + + return Variant::NIL; + +} + bool Object::is_queued_for_deletion() const { return _is_queued_for_deletion; } diff --git a/core/object.h b/core/object.h index 981a83958cb..5b6361796f8 100644 --- a/core/object.h +++ b/core/object.h @@ -606,6 +606,8 @@ public: void set_block_signals(bool p_block); bool is_blocking_signals() const; + Variant::Type get_static_property_type(const StringName& p_property,bool *r_valid=NULL) const; + virtual void get_translatable_strings(List *p_strings) const; virtual void get_argument_options(const StringName& p_function,int p_idx,List*r_options) const; diff --git a/core/object_type_db.cpp b/core/object_type_db.cpp index a64b3d27151..f8ba0a9b15e 100644 --- a/core/object_type_db.cpp +++ b/core/object_type_db.cpp @@ -612,6 +612,7 @@ void ObjectTypeDB::add_property(StringName p_type,const PropertyInfo& p_pinfo, c psg._setptr=mb_set; psg._getptr=mb_get; psg.index=p_index; + psg.type=p_pinfo.type; type->property_setget[p_pinfo.name]=psg; @@ -634,7 +635,7 @@ void ObjectTypeDB::get_property_list(StringName p_type,List *p_lis } } -bool ObjectTypeDB::set_property(Object* p_object,const StringName& p_property, const Variant& p_value) { +bool ObjectTypeDB::set_property(Object* p_object,const StringName& p_property, const Variant& p_value,bool *r_valid) { TypeInfo *type=types.getptr(p_object->get_type_name()); @@ -643,13 +644,17 @@ bool ObjectTypeDB::set_property(Object* p_object,const StringName& p_property, c const PropertySetGet *psg = check->property_setget.getptr(p_property); if (psg) { - if (!psg->setter) + if (!psg->setter) { + if (r_valid) + *r_valid=false; return true; //return true but do nothing + } + + Variant::CallError ce; if (psg->index>=0) { Variant index=psg->index; const Variant* arg[2]={&index,&p_value}; - Variant::CallError ce; // p_object->call(psg->setter,arg,2,ce); if (psg->_setptr) { psg->_setptr->call(p_object,arg,2,ce); @@ -660,13 +665,16 @@ bool ObjectTypeDB::set_property(Object* p_object,const StringName& p_property, c } else { const Variant* arg[1]={&p_value}; - Variant::CallError ce; if (psg->_setptr) { psg->_setptr->call(p_object,arg,1,ce); } else { p_object->call(psg->setter,arg,1,ce); } } + + if (r_valid) + *r_valid=ce.error==Variant::CallError::CALL_OK; + return true; } @@ -718,6 +726,29 @@ bool ObjectTypeDB::get_property(Object* p_object,const StringName& p_property, V return false; } +Variant::Type ObjectTypeDB::get_property_type(const StringName& p_type, const StringName& p_property,bool *r_is_valid) { + + TypeInfo *type=types.getptr(p_type); + TypeInfo *check=type; + while(check) { + const PropertySetGet *psg = check->property_setget.getptr(p_property); + if (psg) { + + if (r_is_valid) + *r_is_valid=true; + + return psg->type; + } + + check=check->inherits_ptr; + } + if (r_is_valid) + *r_is_valid=false; + + return Variant::NIL; + +} + void ObjectTypeDB::set_method_flags(StringName p_type,StringName p_method,int p_flags) { diff --git a/core/object_type_db.h b/core/object_type_db.h index bfa0f921e50..319e3ec02cb 100644 --- a/core/object_type_db.h +++ b/core/object_type_db.h @@ -117,6 +117,7 @@ class ObjectTypeDB { StringName getter; MethodBind *_setptr; MethodBind *_getptr; + Variant::Type type; }; struct TypeInfo { @@ -456,8 +457,9 @@ public: static void add_property(StringName p_type,const PropertyInfo& p_pinfo, const StringName& p_setter, const StringName& p_getter, int p_index=-1); static void get_property_list(StringName p_type,List *p_list,bool p_no_inheritance=false); - static bool set_property(Object* p_object,const StringName& p_property, const Variant& p_value); + static bool set_property(Object* p_object, const StringName& p_property, const Variant& p_value, bool *r_valid=NULL); static bool get_property(Object* p_object,const StringName& p_property, Variant& r_value); + static Variant::Type get_property_type(const StringName& p_type, const StringName& p_property,bool *r_is_valid=NULL); diff --git a/core/script_language.cpp b/core/script_language.cpp index 35c50b10222..b7a0f579f4c 100644 --- a/core/script_language.cpp +++ b/core/script_language.cpp @@ -267,6 +267,20 @@ void PlaceHolderScriptInstance::get_property_list(List *p_properti } } +Variant::Type PlaceHolderScriptInstance::get_property_type(const StringName& p_name,bool *r_is_valid) const { + + if (values.has(p_name)) { + if (r_is_valid) + *r_is_valid=true; + return values[p_name].get_type(); + } + if (r_is_valid) + *r_is_valid=false; + + return Variant::NIL; +} + + void PlaceHolderScriptInstance::update(const List &p_properties,const Map& p_values) { diff --git a/core/script_language.h b/core/script_language.h index 5a0f673b94c..9660f141c7b 100644 --- a/core/script_language.h +++ b/core/script_language.h @@ -82,6 +82,7 @@ public: virtual StringName get_instance_base_type() const=0; // this may not work in all scripts, will return empty if so virtual ScriptInstance* instance_create(Object *p_this)=0; virtual bool instance_has(const Object *p_this) const=0; + virtual bool has_source_code() const=0; virtual String get_source_code() const=0; @@ -109,6 +110,7 @@ public: virtual bool set(const StringName& p_name, const Variant& p_value)=0; virtual bool get(const StringName& p_name, Variant &r_ret) const=0; virtual void get_property_list(List *p_properties) const=0; + virtual Variant::Type get_property_type(const StringName& p_name,bool *r_is_valid=NULL) const=0; virtual void get_method_list(List *p_list) const=0; virtual bool has_method(const StringName& p_method) const=0; @@ -208,6 +210,7 @@ public: virtual bool set(const StringName& p_name, const Variant& p_value); virtual bool get(const StringName& p_name, Variant &r_ret) const; virtual void get_property_list(List *p_properties) const; + virtual Variant::Type get_property_type(const StringName& p_name,bool *r_is_valid=NULL) const; virtual void get_method_list(List *p_list) const {} virtual bool has_method(const StringName& p_method) const { return false; } diff --git a/core/variant.h b/core/variant.h index 8fd9662c36c..e75a2b1c920 100644 --- a/core/variant.h +++ b/core/variant.h @@ -390,7 +390,7 @@ public: Variant call(const StringName& p_method,const Variant** p_args,int p_argcount,CallError &r_error); Variant call(const StringName& p_method,const Variant& p_arg1=Variant(),const Variant& p_arg2=Variant(),const Variant& p_arg3=Variant(),const Variant& p_arg4=Variant(),const Variant& p_arg5=Variant()); - static Variant construct(const Variant::Type,const Variant** p_args,int p_argcount,CallError &r_error); + static Variant construct(const Variant::Type,const Variant** p_args,int p_argcount,CallError &r_error,bool p_strict=true); void get_method_list(List *p_list) const; bool has_method(const StringName& p_method) const; diff --git a/core/variant_call.cpp b/core/variant_call.cpp index 48c38f05f99..0d0248ef285 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -959,7 +959,7 @@ Variant Variant::call(const StringName& p_method,const Variant** p_args,int p_ar #define VCALL(m_type,m_method) _VariantCall::_call_##m_type##_##m_method -Variant Variant::construct(const Variant::Type p_type,const Variant** p_args,int p_argcount,CallError &r_error) { +Variant Variant::construct(const Variant::Type p_type, const Variant** p_args, int p_argcount, CallError &r_error, bool p_strict) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; ERR_FAIL_INDEX_V(p_type,VARIANT_MAX,Variant()); @@ -1035,7 +1035,7 @@ Variant Variant::construct(const Variant::Type p_type,const Variant** p_args,int } else if (p_argcount==1 && p_args[0]->type==p_type) { return *p_args[0]; //copy construct - } else if (p_argcount==1 && Variant::can_convert(p_args[0]->type,p_type)) { + } else if (p_argcount==1 && (!p_strict || Variant::can_convert(p_args[0]->type,p_type))) { //near match construct switch(p_type) { diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp index 8746f92c9ee..c3cc779bce4 100644 --- a/modules/gdscript/gd_script.cpp +++ b/modules/gdscript/gd_script.cpp @@ -2274,6 +2274,26 @@ bool GDInstance::get(const StringName& p_name, Variant &r_ret) const { return false; } + +Variant::Type GDInstance::get_property_type(const StringName& p_name,bool *r_is_valid) const { + + + const GDScript *sptr=script.ptr(); + while(sptr) { + + if (sptr->member_info.has(p_name)) { + if (r_is_valid) + *r_is_valid=true; + return sptr->member_info[p_name].type; + } + sptr = sptr->_base; + } + + if (r_is_valid) + *r_is_valid=false; + return Variant::NIL; +} + void GDInstance::get_property_list(List *p_properties) const { // exported members, not doen yet! diff --git a/modules/gdscript/gd_script.h b/modules/gdscript/gd_script.h index 850ffec05f4..3d16b590651 100644 --- a/modules/gdscript/gd_script.h +++ b/modules/gdscript/gd_script.h @@ -373,6 +373,8 @@ public: virtual bool set(const StringName& p_name, const Variant& p_value); virtual bool get(const StringName& p_name, Variant &r_ret) const; virtual void get_property_list(List *p_properties) const; + virtual Variant::Type get_property_type(const StringName& p_name,bool *r_is_valid=NULL) const; + virtual void get_method_list(List *p_list) const; virtual bool has_method(const StringName& p_method) const; diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index c2ea1c8bb60..b040e59d16c 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -268,6 +268,7 @@ void AnimationPlayer::_generate_node_caches(AnimationData* p_anim) { TrackNodeCacheKey key; key.id=id; key.bone_idx=bone_idx; + if (node_cache_map.has(key)) { @@ -278,6 +279,7 @@ void AnimationPlayer::_generate_node_caches(AnimationData* p_anim) { node_cache_map[key]=TrackNodeCache(); p_anim->node_cache[i]=&node_cache_map[key]; + p_anim->node_cache[i]->path=a->track_get_path(i); p_anim->node_cache[i]->node=child; p_anim->node_cache[i]->resource=resource; p_anim->node_cache[i]->node_2d=child->cast_to(); @@ -320,6 +322,7 @@ void AnimationPlayer::_generate_node_caches(AnimationData* p_anim) { pa.prop=property; pa.object=resource.is_valid()?(Object*)resource.ptr():(Object*)child; pa.special=SP_NONE; + pa.owner=p_anim->node_cache[i]; if (false && p_anim->node_cache[i]->node_2d) { if (pa.prop==SceneStringNames::get_singleton()->transform_pos) @@ -410,7 +413,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData* p_anim,float p TrackNodeCache::PropertyAnim *pa = &E->get(); - if (a->value_track_is_continuous(i) || p_delta==0) { + if (a->value_track_is_continuous(i) || p_delta==0) { //delta == 0 means seek Variant value=a->value_track_interpolate(i,p_time); @@ -436,10 +439,42 @@ void AnimationPlayer::_animation_process_animation(AnimationData* p_anim,float p Variant value=a->track_get_key_value(i,F->get()); switch(pa->special) { - case SP_NONE: pa->object->set(pa->prop,value); break; //you are not speshul - case SP_NODE2D_POS: static_cast(pa->object)->set_pos(value); break; - case SP_NODE2D_ROT: static_cast(pa->object)->set_rot(Math::deg2rad(value)); break; - case SP_NODE2D_SCALE: static_cast(pa->object)->set_scale(value); break; + case SP_NONE: { + bool valid; + pa->object->set(pa->prop,value,&valid); //you are not speshul +#ifdef DEBUG_ENABLED + if (!valid) { + ERR_PRINTS("Failed setting track value '"+String(pa->owner->path)+"'. Check if property exists or the type of key is valid"); + } +#endif + + } break; + case SP_NODE2D_POS: { +#ifdef DEBUG_ENABLED + if (value.get_type()!=Variant::VECTOR2) { + ERR_PRINTS("Position key at time "+rtos(p_time)+" in Animation Track '"+String(pa->owner->path)+"' not of type Vector2()"); + } +#endif + static_cast(pa->object)->set_pos(value); + } break; + case SP_NODE2D_ROT: { +#ifdef DEBUG_ENABLED + if (value.is_num()) { + ERR_PRINTS("Rotation key at time "+rtos(p_time)+" in Animation Track '"+String(pa->owner->path)+"' not numerical"); + } +#endif + + static_cast(pa->object)->set_rot(Math::deg2rad(value)); + } break; + case SP_NODE2D_SCALE: { +#ifdef DEBUG_ENABLED + if (value.get_type()!=Variant::VECTOR2) { + ERR_PRINTS("Scale key at time "+rtos(p_time)+" in Animation Track '"+String(pa->owner->path)+"' not of type Vector2()"); + } +#endif + + static_cast(pa->object)->set_scale(value); + } break; } } @@ -607,13 +642,53 @@ void AnimationPlayer::_animation_update_transforms() { ERR_CONTINUE( pa->accum_pass!=accum_pass ); #if 1 - switch(pa->special) { +/* switch(pa->special) { case SP_NONE: pa->object->set(pa->prop,pa->value_accum); break; //you are not speshul case SP_NODE2D_POS: static_cast(pa->object)->set_pos(pa->value_accum); break; case SP_NODE2D_ROT: static_cast(pa->object)->set_rot(Math::deg2rad(pa->value_accum)); break; case SP_NODE2D_SCALE: static_cast(pa->object)->set_scale(pa->value_accum); break; + }*/ + + switch(pa->special) { + + case SP_NONE: { + bool valid; + pa->object->set(pa->prop,pa->value_accum,&valid); //you are not speshul +#ifdef DEBUG_ENABLED + if (!valid) { + ERR_PRINTS("Failed setting key at time "+rtos(playback.current.pos)+" in Animation '"+get_current_animation()+"', Track '"+String(pa->owner->path)+"'. Check if property exists or the type of key is right for the property"); + } +#endif + + } break; + case SP_NODE2D_POS: { +#ifdef DEBUG_ENABLED + if (pa->value_accum.get_type()!=Variant::VECTOR2) { + ERR_PRINTS("Position key at time "+rtos(playback.current.pos)+" in Animation '"+get_current_animation()+"', Track '"+String(pa->owner->path)+"' not of type Vector2()"); + } +#endif + static_cast(pa->object)->set_pos(pa->value_accum); + } break; + case SP_NODE2D_ROT: { +#ifdef DEBUG_ENABLED + if (pa->value_accum.is_num()) { + ERR_PRINTS("Rotation key at time "+rtos(playback.current.pos)+" in Animation '"+get_current_animation()+"', Track '"+String(pa->owner->path)+"' not numerical"); + } +#endif + + static_cast(pa->object)->set_rot(Math::deg2rad(pa->value_accum)); + } break; + case SP_NODE2D_SCALE: { +#ifdef DEBUG_ENABLED + if (pa->value_accum.get_type()!=Variant::VECTOR2) { + ERR_PRINTS("Scale key at time "+rtos(playback.current.pos)+" in Animation '"+get_current_animation()+"', Track '"+String(pa->owner->path)+"' not of type Vector2()"); + } +#endif + + static_cast(pa->object)->set_scale(pa->value_accum); + } break; } #else diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h index 1e3c37c4d60..18cedee7964 100644 --- a/scene/animation/animation_player.h +++ b/scene/animation/animation_player.h @@ -68,6 +68,7 @@ private: struct TrackNodeCache { + NodePath path; uint32_t id; RES resource; Node *node; @@ -84,6 +85,7 @@ private: struct PropertyAnim { + TrackNodeCache *owner; SpecialProperty special; //small optimization StringName prop; Object *object; diff --git a/tools/editor/animation_editor.cpp b/tools/editor/animation_editor.cpp index ace6fda6965..4ccb612a39b 100644 --- a/tools/editor/animation_editor.cpp +++ b/tools/editor/animation_editor.cpp @@ -34,6 +34,7 @@ #include "pair.h" #include "scene/gui/separator.h" #include "editor_node.h" +#include "tools/editor/plugins/animation_player_editor_plugin.h" /* Missing to fix: *Set @@ -903,6 +904,23 @@ void AnimationKeyEditor::_menu_track(int p_type) { optimize_dialog->popup_centered(Size2(250,180)); } break; + case TRACK_MENU_CLEAN_UP: { + + cleanup_dialog->popup_centered_minsize(Size2(300,0)); + } break; + case TRACK_MENU_CLEAN_UP_CONFIRM: { + + if (cleanup_all->is_pressed()) { + List names; + AnimationPlayerEditor::singleton->get_player()->get_animation_list(&names); + for (List::Element *E=names.front();E;E=E->next()) { + _cleanup_animation(AnimationPlayerEditor::singleton->get_player()->get_animation(E->get())); + } + } else { + _cleanup_animation(animation); + + } + } break; case CURVE_SET_LINEAR: { curve_edit->force_transition(1.0); @@ -933,6 +951,57 @@ void AnimationKeyEditor::_menu_track(int p_type) { } +void AnimationKeyEditor::_cleanup_animation(Ref p_animation) { + + + for(int i=0;iget_track_count();i++) { + + bool prop_exists=false; + Variant::Type valid_type=Variant::NIL; + Object *obj=NULL; + + RES res; + Node *node = root->get_node_and_resource(animation->track_get_path(i),res); + + if (res.is_valid()) { + obj=res.ptr(); + } else if (node) { + obj=node; + } + + if (obj && animation->track_get_type(i)==Animation::TYPE_VALUE) { + valid_type=obj->get_static_property_type(animation->track_get_path(i).get_property(),&prop_exists); + } + + if (!obj && cleanup_tracks->is_pressed()) { + + animation->remove_track(i); + i--; + continue; + } + + if (!prop_exists || animation->track_get_type(i)!=Animation::TYPE_VALUE || cleanup_keys->is_pressed()==false) + continue; + + for(int j=0;jtrack_get_key_count(i);j++) { + + Variant v = animation->track_get_key_value(i,j); + + if (!Variant::can_convert(v.get_type(),valid_type)) { + animation->track_remove_key(i,j); + j--; + } + } + + if (animation->track_get_key_count(i)==0 && cleanup_tracks->is_pressed()) { + animation->remove_track(i); + i--; + } + } + + undo_redo->clear_history(); + _update_paths(); +} void AnimationKeyEditor::_animation_optimize() { @@ -1042,6 +1111,7 @@ void AnimationKeyEditor::_track_editor_draw() { timecolor = Color::html("ff4a414f"); Color hover_color = Color(1,1,1,0.05); Color select_color = Color(1,1,1,0.1); + Color invalid_path_color = Color(1,0.6,0.4,0.5); Color track_select_color =Color::html("ffbd8e8e"); Ref remove_icon = get_icon("Remove","EditorIcons"); @@ -1068,6 +1138,9 @@ void AnimationKeyEditor::_track_editor_draw() { get_icon("KeyCall","EditorIcons") }; + Ref invalid_icon = get_icon("KeyInvalid","EditorIcons"); + Ref invalid_icon_hover = get_icon("KeyInvalidHover","EditorIcons"); + Ref hsize_icon = get_icon("Hsize","EditorIcons"); Ref type_hover=get_icon("KeyHover","EditorIcons"); @@ -1254,6 +1327,23 @@ void AnimationKeyEditor::_track_editor_draw() { break; int y = h+i*h+sep; + bool prop_exists=false; + Variant::Type valid_type=Variant::NIL; + Object *obj=NULL; + + RES res; + Node *node = root->get_node_and_resource(animation->track_get_path(idx),res); + + if (res.is_valid()) { + obj=res.ptr(); + } else if (node) { + obj=node; + } + + if (obj && animation->track_get_type(idx)==Animation::TYPE_VALUE) { + valid_type=obj->get_static_property_type(animation->track_get_path(idx).get_property(),&prop_exists); + } + if (/*mouse_over.over!=MouseOver::OVER_NONE &&*/ idx==mouse_over.track) { Color sepc=hover_color; @@ -1274,6 +1364,8 @@ void AnimationKeyEditor::_track_editor_draw() { ncol=track_select_color; te->draw_string(font,Point2(ofs+Point2(type_icon[0]->get_width()+sep,y+font->get_ascent()+(sep/2))).floor(),np,ncol,name_limit-(type_icon[0]->get_width()+sep)-5); + if (!obj) + te->draw_line(ofs+Point2(0,y+h/2),ofs+Point2(name_limit,y+h/2),invalid_path_color); te->draw_line(ofs+Point2(0,y+h),ofs+Point2(size.width,y+h),sepcolor); @@ -1339,6 +1431,8 @@ void AnimationKeyEditor::_track_editor_draw() { int kc=animation->track_get_key_count(idx); bool first=true; + + for(int i=0;idraw_texture(tex,ofs+Point2(x,y+key_vofs).floor()); + if (prop_exists && !Variant::can_convert(value.get_type(),valid_type)) { + te->draw_texture(invalid_icon,ofs+Point2(x,y+key_vofs).floor()); + } + + if (prop_exists && !Variant::can_convert(value.get_type(),valid_type)) { + if (tex==type_hover) + te->draw_texture(invalid_icon_hover,ofs+Point2(x,y+key_vofs).floor()); + else + te->draw_texture(invalid_icon,ofs+Point2(x,y+key_vofs).floor()); + } else { + + te->draw_texture(tex,ofs+Point2(x,y+key_vofs).floor()); + } + + first=false; } @@ -2555,6 +2663,8 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) { String text; text="time: "+rtos(animation->track_get_key_time(idx,mouse_over.over_key))+"\n"; + + switch(animation->track_get_type(idx)) { case Animation::TYPE_TRANSFORM: { @@ -2569,8 +2679,33 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) { } break; case Animation::TYPE_VALUE: { - Variant v = animation->track_get_key_value(idx,mouse_over.over_key); - text+="value: "+String(v)+"\n"; + Variant v = animation->track_get_key_value(idx,mouse_over.over_key);; + //text+="value: "+String(v)+"\n"; + + bool prop_exists=false; + Variant::Type valid_type=Variant::NIL; + Object *obj=NULL; + + RES res; + Node *node = root->get_node_and_resource(animation->track_get_path(idx),res); + + if (res.is_valid()) { + obj=res.ptr(); + } else if (node) { + obj=node; + } + + if (obj) { + valid_type=obj->get_static_property_type(animation->track_get_path(idx).get_property(),&prop_exists); + } + + text+="type: "+Variant::get_type_name(v.get_type())+"\n"; + if (prop_exists && !Variant::can_convert(v.get_type(),valid_type)) { + text+="value: "+String(v)+" (Invalid, expected type: "+Variant::get_type_name(valid_type)+")\n"; + } else { + text+="value: "+String(v)+"\n"; + } + } break; case Animation::TYPE_METHOD: { @@ -2593,6 +2728,9 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) { } break; } text+="easing: "+rtos(animation->track_get_key_transition(idx,mouse_over.over_key)); + + + track_editor->set_tooltip(text); return; @@ -2703,6 +2841,7 @@ void AnimationKeyEditor::_notification(int p_what) { //menu_track->get_popup()->add_submenu_item("Set Transitions..","Transitions"); //menu_track->get_popup()->add_separator(); menu_track->get_popup()->add_item("Optimize Animation",TRACK_MENU_OPTIMIZE); + menu_track->get_popup()->add_item("Clean-Up Animation",TRACK_MENU_CLEAN_UP); curve_linear->set_icon(get_icon("CurveLinear","EditorIcons")); curve_in->set_icon(get_icon("CurveIn","EditorIcons")); @@ -3862,6 +4001,32 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h add_child(call_select); call_select->set_title("Call Functions in Which Node?"); + cleanup_dialog = memnew( ConfirmationDialog ); + add_child(cleanup_dialog); + VBoxContainer *cleanup_vb = memnew( VBoxContainer ); + cleanup_dialog->add_child(cleanup_vb); + cleanup_dialog->set_child_rect(cleanup_vb); + cleanup_keys = memnew( CheckButton ); + cleanup_keys->set_text("Remove invalid keys"); + cleanup_keys->set_pressed(true); + cleanup_vb->add_child(cleanup_keys); + + cleanup_tracks = memnew( CheckButton ); + cleanup_tracks->set_text("Remove unresolved and empty tracks"); + cleanup_tracks->set_pressed(true); + cleanup_vb->add_child(cleanup_tracks); + + cleanup_all = memnew( CheckButton ); + cleanup_all->set_text("Clean-Up all animations"); + cleanup_vb->add_child(cleanup_all); + + cleanup_dialog->set_title("Clean up Animation(s) (NO UNDO!)"); + cleanup_dialog->get_ok()->set_text("Clean-Up"); + + cleanup_dialog->connect("confirmed",this,"_menu_track",varray(TRACK_MENU_CLEAN_UP_CONFIRM)); + + + } AnimationKeyEditor::~AnimationKeyEditor() { diff --git a/tools/editor/animation_editor.h b/tools/editor/animation_editor.h index 629377d78ef..743242fe949 100644 --- a/tools/editor/animation_editor.h +++ b/tools/editor/animation_editor.h @@ -89,6 +89,8 @@ class AnimationKeyEditor : public VBoxContainer { TRACK_MENU_NEXT_STEP, TRACK_MENU_PREV_STEP, TRACK_MENU_OPTIMIZE, + TRACK_MENU_CLEAN_UP, + TRACK_MENU_CLEAN_UP_CONFIRM, CURVE_SET_LINEAR, CURVE_SET_IN, CURVE_SET_OUT, @@ -190,6 +192,11 @@ class AnimationKeyEditor : public VBoxContainer { SpinBox *optimize_angular_error; SpinBox *optimize_max_angle; + ConfirmationDialog *cleanup_dialog; + CheckButton *cleanup_keys; + CheckButton *cleanup_tracks; + CheckButton *cleanup_all; + SpinBox *step; MenuButton *menu_add_track; @@ -284,6 +291,7 @@ class AnimationKeyEditor : public VBoxContainer { void _animation_changed(); void _animation_optimize(); + void _cleanup_animation(Ref p_animation); void _scroll_changed(double); diff --git a/tools/editor/icons/icon_key_invalid.png b/tools/editor/icons/icon_key_invalid.png new file mode 100644 index 00000000000..e8e6c87180d Binary files /dev/null and b/tools/editor/icons/icon_key_invalid.png differ diff --git a/tools/editor/icons/icon_key_invalid_hover.png b/tools/editor/icons/icon_key_invalid_hover.png new file mode 100644 index 00000000000..6f0396d96a0 Binary files /dev/null and b/tools/editor/icons/icon_key_invalid_hover.png differ diff --git a/tools/editor/plugins/animation_player_editor_plugin.cpp b/tools/editor/plugins/animation_player_editor_plugin.cpp index 6542fc8b4a8..dc2c241d2fa 100644 --- a/tools/editor/plugins/animation_player_editor_plugin.cpp +++ b/tools/editor/plugins/animation_player_editor_plugin.cpp @@ -1250,8 +1250,15 @@ void AnimationPlayerEditor::_bind_methods() { } +AnimationPlayerEditor *AnimationPlayerEditor::singleton=NULL; + +AnimationPlayer *AnimationPlayerEditor::get_player() const { + + return player; +} AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor) { editor=p_editor; + singleton=this; updating=false; diff --git a/tools/editor/plugins/animation_player_editor_plugin.h b/tools/editor/plugins/animation_player_editor_plugin.h index ac4d1ab6ba5..839df3ddcc3 100644 --- a/tools/editor/plugins/animation_player_editor_plugin.h +++ b/tools/editor/plugins/animation_player_editor_plugin.h @@ -162,6 +162,7 @@ class AnimationPlayerEditor : public VBoxContainer { void _animation_tool_menu(int p_option); void _animation_save_menu(int p_option); + AnimationPlayerEditor(); protected: @@ -171,6 +172,9 @@ protected: static void _bind_methods(); public: + AnimationPlayer *get_player() const; + static AnimationPlayerEditor *singleton; + Dictionary get_state() const; void set_state(const Dictionary& p_state);