summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/node_2d.cpp53
-rw-r--r--scene/2d/node_2d.h6
-rw-r--r--scene/2d/physics_body_2d.cpp77
-rw-r--r--scene/2d/physics_body_2d.h13
-rw-r--r--scene/gui/control.cpp9
-rw-r--r--scene/gui/control.h6
-rw-r--r--scene/gui/graph_edit.cpp196
-rw-r--r--scene/gui/graph_edit.h9
-rw-r--r--scene/gui/graph_node.cpp77
-rw-r--r--scene/gui/graph_node.h14
-rw-r--r--scene/gui/tree.cpp40
-rw-r--r--scene/gui/tree.h6
-rw-r--r--scene/main/node.cpp556
-rw-r--r--scene/main/node.h45
-rw-r--r--scene/main/scene_main_loop.cpp355
-rw-r--r--scene/main/scene_main_loop.h25
-rw-r--r--scene/resources/default_theme/default_theme.cpp5
-rw-r--r--scene/resources/default_theme/graph_node.pngbin752 -> 762 bytes
-rw-r--r--scene/resources/default_theme/graph_node_comment.pngbin0 -> 506 bytes
-rw-r--r--scene/resources/default_theme/graph_node_selected.pngbin920 -> 933 bytes
-rw-r--r--scene/resources/default_theme/theme_data.h14
-rw-r--r--scene/resources/default_theme/window_resizer.pngbin0 -> 181 bytes
22 files changed, 1290 insertions, 216 deletions
diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp
index 134e0153b3..df43e8e373 100644
--- a/scene/2d/node_2d.cpp
+++ b/scene/2d/node_2d.cpp
@@ -295,6 +295,53 @@ void Node2D::set_global_pos(const Point2& p_pos) {
}
}
+
+float Node2D::get_global_rot() const {
+
+ return get_global_transform().get_rotation();
+}
+
+void Node2D::set_global_rot(float p_radians) {
+
+ CanvasItem *pi = get_parent_item();
+ if (pi) {
+ const float parent_global_rot = pi->get_global_transform().get_rotation();
+ set_rot(p_radians - parent_global_rot);
+ } else {
+ set_rot(p_radians);
+ }
+}
+
+
+float Node2D::get_global_rotd() const {
+
+ return Math::rad2deg(get_global_rot());
+}
+
+void Node2D::set_global_rotd(float p_degrees) {
+
+ set_global_rot(Math::deg2rad(p_degrees));
+}
+
+
+Size2 Node2D::get_global_scale() const {
+
+ return get_global_transform().get_scale();
+}
+
+void Node2D::set_global_scale(const Size2& p_scale) {
+
+ CanvasItem *pi = get_parent_item();
+ if (pi) {
+ const Size2 parent_global_scale = pi->get_global_transform().get_scale();
+ set_scale(p_scale - parent_global_scale);
+ } else {
+ set_scale(p_scale);
+ }
+
+}
+
+
void Node2D::set_transform(const Matrix32& p_transform) {
_mat=p_transform;
@@ -398,6 +445,12 @@ void Node2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_global_pos","pos"),&Node2D::set_global_pos);
ObjectTypeDB::bind_method(_MD("get_global_pos"),&Node2D::get_global_pos);
+ ObjectTypeDB::bind_method(_MD("set_global_rot","radians"),&Node2D::set_global_rot);
+ ObjectTypeDB::bind_method(_MD("get_global_rot"),&Node2D::get_global_rot);
+ ObjectTypeDB::bind_method(_MD("set_global_rotd","degrees"),&Node2D::set_global_rotd);
+ ObjectTypeDB::bind_method(_MD("get_global_rotd"),&Node2D::get_global_rotd);
+ ObjectTypeDB::bind_method(_MD("set_global_scale","scale"),&Node2D::set_global_scale);
+ ObjectTypeDB::bind_method(_MD("get_global_scale"),&Node2D::get_global_scale);
ObjectTypeDB::bind_method(_MD("set_transform","xform"),&Node2D::set_transform);
ObjectTypeDB::bind_method(_MD("set_global_transform","xform"),&Node2D::set_global_transform);
diff --git a/scene/2d/node_2d.h b/scene/2d/node_2d.h
index b0c628fd94..aa8d0ef33c 100644
--- a/scene/2d/node_2d.h
+++ b/scene/2d/node_2d.h
@@ -87,11 +87,17 @@ public:
Size2 get_scale() const;
Point2 get_global_pos() const;
+ float get_global_rot() const;
+ float get_global_rotd() const;
+ Size2 get_global_scale() const;
virtual Rect2 get_item_rect() const;
void set_transform(const Matrix32& p_transform);
void set_global_transform(const Matrix32& p_transform);
void set_global_pos(const Point2& p_pos);
+ void set_global_rot(float p_radians);
+ void set_global_rotd(float p_degrees);
+ void set_global_scale(const Size2& p_scale);
void set_z(int p_z);
int get_z() const;
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index 26c4ea385f..75fa6054ad 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -1226,6 +1226,73 @@ Vector2 KinematicBody2D::move(const Vector2& p_motion) {
#endif
}
+
+
+Vector2 KinematicBody2D::move_and_slide(const Vector2& p_linear_velocity,const Vector2& p_floor_direction,int p_max_bounces) {
+
+ Vector2 motion = p_linear_velocity*get_fixed_process_delta_time();
+ Vector2 lv = p_linear_velocity;
+
+ move_and_slide_on_floor=false;
+ move_and_slide_on_ceiling=false;
+ move_and_slide_on_wall=false;
+ move_and_slide_colliders.clear();
+
+ while(motion!=Vector2() && p_max_bounces) {
+
+ motion=move(motion);
+
+ if (is_colliding()) {
+
+ if (p_floor_direction==Vector2()) {
+ //all is a wall
+ move_and_slide_on_wall=true;
+ } else {
+ if ( get_collision_normal().dot(p_floor_direction) > Math::cos(Math::deg2rad(45))) { //floor
+ move_and_slide_on_floor=true;
+ move_and_slide_floor_velocity=get_collider_velocity();
+ } else if ( get_collision_normal().dot(p_floor_direction) < Math::cos(Math::deg2rad(45))) { //ceiling
+ move_and_slide_on_ceiling=true;
+ } else {
+ move_and_slide_on_wall=true;
+ }
+
+ }
+
+ motion=get_collision_normal().slide(motion);
+ lv=get_collision_normal().slide(lv);
+ Variant collider = _get_collider();
+ if (collider.get_type()!=Variant::NIL) {
+ move_and_slide_colliders.push_back(collider);
+ }
+
+ } else {
+ break;
+ }
+
+ p_max_bounces--;
+ }
+
+ return lv;
+}
+
+bool KinematicBody2D::is_move_and_slide_on_floor() const {
+
+ return move_and_slide_on_floor;
+}
+bool KinematicBody2D::is_move_and_slide_on_wall() const{
+
+ return move_and_slide_on_wall;
+}
+bool KinematicBody2D::is_move_and_slide_on_ceiling() const{
+
+ return move_and_slide_on_ceiling;
+}
+Array KinematicBody2D::get_move_and_slide_colliders() const{
+
+ return move_and_slide_colliders;
+}
+
Vector2 KinematicBody2D::move_to(const Vector2& p_position) {
return move(p_position-get_global_pos());
@@ -1300,6 +1367,7 @@ void KinematicBody2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("move","rel_vec"),&KinematicBody2D::move);
ObjectTypeDB::bind_method(_MD("move_to","position"),&KinematicBody2D::move_to);
+ ObjectTypeDB::bind_method(_MD("move_and_slide","linear_velocity","floor_normal","max_bounces"),&KinematicBody2D::move_and_slide,DEFVAL(Vector2(0,0)),DEFVAL(4));
ObjectTypeDB::bind_method(_MD("test_move","rel_vec"),&KinematicBody2D::test_move);
ObjectTypeDB::bind_method(_MD("get_travel"),&KinematicBody2D::get_travel);
@@ -1313,6 +1381,10 @@ void KinematicBody2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_collider:Object"),&KinematicBody2D::_get_collider);
ObjectTypeDB::bind_method(_MD("get_collider_shape"),&KinematicBody2D::get_collider_shape);
ObjectTypeDB::bind_method(_MD("get_collider_metadata:Variant"),&KinematicBody2D::get_collider_metadata);
+ ObjectTypeDB::bind_method(_MD("get_move_and_slide_colliders"),&KinematicBody2D::get_move_and_slide_colliders);
+ ObjectTypeDB::bind_method(_MD("is_move_and_slide_on_floor"),&KinematicBody2D::is_move_and_slide_on_floor);
+ ObjectTypeDB::bind_method(_MD("is_move_and_slide_on_ceiling"),&KinematicBody2D::is_move_and_slide_on_ceiling);
+ ObjectTypeDB::bind_method(_MD("is_move_and_slide_on_wall"),&KinematicBody2D::is_move_and_slide_on_wall);
ObjectTypeDB::bind_method(_MD("set_collision_margin","pixels"),&KinematicBody2D::set_collision_margin);
ObjectTypeDB::bind_method(_MD("get_collision_margin","pixels"),&KinematicBody2D::get_collision_margin);
@@ -1330,6 +1402,11 @@ KinematicBody2D::KinematicBody2D() : PhysicsBody2D(Physics2DServer::BODY_MODE_KI
collider_shape=0;
margin=0.08;
+
+ move_and_slide_on_floor=false;
+ move_and_slide_on_ceiling=false;
+ move_and_slide_on_wall=false;
+
}
KinematicBody2D::~KinematicBody2D() {
diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h
index 5af65bff33..387267cd09 100644
--- a/scene/2d/physics_body_2d.h
+++ b/scene/2d/physics_body_2d.h
@@ -302,6 +302,12 @@ class KinematicBody2D : public PhysicsBody2D {
Variant collider_metadata;
Vector2 travel;
+ Vector2 move_and_slide_floor_velocity;
+ bool move_and_slide_on_floor;
+ bool move_and_slide_on_ceiling;
+ bool move_and_slide_on_wall;
+ Array move_and_slide_colliders;
+
Variant _get_collider() const;
_FORCE_INLINE_ bool _ignores_mode(Physics2DServer::BodyMode) const;
@@ -329,6 +335,13 @@ public:
void set_collision_margin(float p_margin);
float get_collision_margin() const;
+ Vector2 move_and_slide(const Vector2& p_linear_velocity,const Vector2& p_floor_direction=Vector2(0,0),int p_max_bounces=4);
+ bool is_move_and_slide_on_floor() const;
+ bool is_move_and_slide_on_wall() const;
+ bool is_move_and_slide_on_ceiling() const;
+ Array get_move_and_slide_colliders() const;
+
+
KinematicBody2D();
~KinematicBody2D();
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 71ec508c81..97133a2a3b 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -2214,7 +2214,7 @@ void Control::grab_click_focus() {
void Control::minimum_size_changed() {
- if (!is_inside_tree())
+ if (!is_inside_tree() || data.block_minimum_size_adjust)
return;
if (data.pending_min_size_update)
@@ -2374,8 +2374,14 @@ Control *Control::get_root_parent_control() const {
return const_cast<Control*>(root);
}
+void Control::set_block_minimum_size_adjust(bool p_block) {
+ data.block_minimum_size_adjust=p_block;
+}
+bool Control::is_minimum_size_adjust_blocked() const {
+ return data.block_minimum_size_adjust;
+}
void Control::_bind_methods() {
@@ -2603,6 +2609,7 @@ Control::Control() {
data.scale=Vector2(1,1);
data.drag_owner=0;
data.modal_frame=0;
+ data.block_minimum_size_adjust=false;
for (int i=0;i<4;i++) {
diff --git a/scene/gui/control.h b/scene/gui/control.h
index b9ac53067a..e6b0844869 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -128,6 +128,8 @@ private:
bool ignore_mouse;
bool stop_mouse;
+ bool block_minimum_size_adjust;
+
Control *parent;
ObjectID drag_owner;
bool modal;
@@ -396,6 +398,10 @@ public:
Control *get_root_parent_control() const;
+
+ void set_block_minimum_size_adjust(bool p_block);
+ bool is_minimum_size_adjust_blocked() const;
+
Control();
~Control();
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index 458e51b4fd..a7a813d335 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -61,6 +61,7 @@ Error GraphEdit::connect_node(const StringName& p_from, int p_from_port,const St
c.to_port=p_to_port;
connections.push_back(c);
top_layer->update();
+ update();
return OK;
}
@@ -85,6 +86,7 @@ void GraphEdit::disconnect_node(const StringName& p_from, int p_from_port,const
connections.erase(E);
top_layer->update();
+ update();
return;
}
}
@@ -118,10 +120,7 @@ void GraphEdit::_scroll_moved(double) {
_update_scroll_offset();
top_layer->update();
- if (is_using_snap()) {
- //must redraw grid
- update();
- }
+ update();
if (!setting_scroll_ofs) {//in godot, signals on change value are avoided as a convention
emit_signal("scroll_offset_changed",get_scroll_ofs());
@@ -194,6 +193,9 @@ void GraphEdit::_graph_node_raised(Node* p_gn) {
GraphNode *gn=p_gn->cast_to<GraphNode>();
ERR_FAIL_COND(!gn);
gn->raise();
+ if (gn->is_comment()) {
+ move_child(gn,0);
+ }
top_layer->raise();
emit_signal("node_selected",p_gn);
@@ -205,6 +207,7 @@ void GraphEdit::_graph_node_moved(Node *p_gn) {
GraphNode *gn=p_gn->cast_to<GraphNode>();
ERR_FAIL_COND(!gn);
top_layer->update();
+ update();
}
void GraphEdit::add_child_notify(Node *p_child) {
@@ -261,6 +264,7 @@ void GraphEdit::_notification(int p_what) {
}
if (p_what==NOTIFICATION_DRAW) {
+
draw_style_box( get_stylebox("bg"),Rect2(Point2(),get_size()) );
VS::get_singleton()->canvas_item_set_clip(get_canvas_item(),true);
@@ -306,11 +310,60 @@ void GraphEdit::_notification(int p_what) {
}
+ {
+ //draw connections
+ List<List<Connection>::Element* > to_erase;
+ for(List<Connection>::Element *E=connections.front();E;E=E->next()) {
+
+ NodePath fromnp(E->get().from);
+
+ Node * from = get_node(fromnp);
+ if (!from) {
+ to_erase.push_back(E);
+ continue;
+ }
+
+ GraphNode *gfrom = from->cast_to<GraphNode>();
+
+ if (!gfrom) {
+ to_erase.push_back(E);
+ continue;
+ }
+
+ NodePath tonp(E->get().to);
+ Node * to = get_node(tonp);
+ if (!to) {
+ to_erase.push_back(E);
+ continue;
+ }
+
+ GraphNode *gto = to->cast_to<GraphNode>();
+
+ if (!gto) {
+ to_erase.push_back(E);
+ continue;
+ }
+
+ Vector2 frompos=gfrom->get_connection_output_pos(E->get().from_port)+gfrom->get_pos();
+ Color color = gfrom->get_connection_output_color(E->get().from_port);
+ Vector2 topos=gto->get_connection_input_pos(E->get().to_port)+gto->get_pos();
+ Color tocolor = gto->get_connection_input_color(E->get().to_port);
+ _draw_cos_line(this,frompos,topos,color,tocolor);
+
+ }
+
+ while(to_erase.size()) {
+ connections.erase(to_erase.front()->get());
+ to_erase.pop_front();
+ }
+ }
+
}
if (p_what==NOTIFICATION_RESIZED) {
_update_scroll();
top_layer->update();
+
}
}
@@ -466,7 +519,7 @@ void GraphEdit::_top_layer_input(const InputEvent& p_ev) {
connecting_to=Vector2(p_ev.mouse_motion.x,p_ev.mouse_motion.y);
connecting_target=false;
- top_layer->update();
+ top_layer->update();
Ref<Texture> port =get_icon("port","GraphNode");
Vector2 mpos(p_ev.mouse_button.x,p_ev.mouse_button.y);
@@ -526,18 +579,90 @@ void GraphEdit::_top_layer_input(const InputEvent& p_ev) {
}
emit_signal("connection_request",from,from_slot,to,to_slot);
+ } else {
+ String from = connecting_from;
+ int from_slot = connecting_index;
+ Vector2 ofs = Vector2(p_ev.mouse_button.x,p_ev.mouse_button.y);
+ emit_signal("connection_to_empty",from,from_slot,ofs);
}
connecting=false;
top_layer->update();
+ update();
}
}
-void GraphEdit::_draw_cos_line(const Vector2& p_from, const Vector2& p_to,const Color& p_color,const Color& p_to_color) {
+
+template<class Vector2>
+static _FORCE_INLINE_ Vector2 _bezier_interp(real_t t, Vector2 start, Vector2 control_1, Vector2 control_2, Vector2 end) {
+ /* Formula from Wikipedia article on Bezier curves. */
+ real_t omt = (1.0 - t);
+ real_t omt2 = omt*omt;
+ real_t omt3 = omt2*omt;
+ real_t t2 = t*t;
+ real_t t3 = t2*t;
+
+ return start * omt3
+ + control_1 * omt2 * t * 3.0
+ + control_2 * omt * t2 * 3.0
+ + end * t3;
+}
+
+
+void GraphEdit::_bake_segment2d(CanvasItem* p_where,float p_begin, float p_end,const Vector2& p_a,const Vector2& p_out,const Vector2& p_b, const Vector2& p_in,int p_depth,int p_min_depth,int p_max_depth,float p_tol,const Color& p_color,const Color& p_to_color,int &lines) const {
+
+ float mp = p_begin+(p_end-p_begin)*0.5;
+ Vector2 beg = _bezier_interp(p_begin,p_a,p_a+p_out,p_b+p_in,p_b);
+ Vector2 mid = _bezier_interp(mp,p_a,p_a+p_out,p_b+p_in,p_b);
+ Vector2 end = _bezier_interp(p_end,p_a,p_a+p_out,p_b+p_in,p_b);
+
+ Vector2 na = (mid-beg).normalized();
+ Vector2 nb = (end-mid).normalized();
+ float dp = Math::rad2deg(Math::acos(na.dot(nb)));
+
+ if (p_depth>=p_min_depth && ( dp<p_tol || p_depth>=p_max_depth)) {
+
+
+
+ p_where->draw_line(beg,end,p_color.linear_interpolate(p_to_color,mp),2);
+ lines++;
+ } else {
+ _bake_segment2d(p_where,p_begin,mp,p_a,p_out,p_b,p_in,p_depth+1,p_min_depth,p_max_depth,p_tol,p_color,p_to_color,lines);
+ _bake_segment2d(p_where,mp,p_end,p_a,p_out,p_b,p_in,p_depth+1,p_min_depth,p_max_depth,p_tol,p_color,p_to_color,lines);
+ }
+}
+
+
+void GraphEdit::_draw_cos_line(CanvasItem* p_where,const Vector2& p_from, const Vector2& p_to,const Color& p_color,const Color& p_to_color) {
+
+#if 1
+
+ //cubic bezier code
+ float diff = p_to.x-p_from.x;
+ float cp_offset;
+ int cp_len = get_constant("bezier_len_pos");
+ int cp_neg_len = get_constant("bezier_len_neg");
+
+ if (diff>0) {
+ cp_offset=MAX(cp_len,diff*0.5);
+ } else {
+ cp_offset=MAX(MIN(cp_len-diff,cp_neg_len),-diff*0.5);
+ }
+
+ Vector2 c1 = Vector2(cp_offset,0);
+ Vector2 c2 = Vector2(-cp_offset,0);
+
+ int lines=0;
+ _bake_segment2d(p_where,0,1,p_from,c1,p_to,c2,0,5,12,8,p_color,p_to_color,lines);
+ //print_line("used lines: "+itos(lines));
+
+
+#else
static const int steps = 20;
+ //old cosine code
Rect2 r;
r.pos=p_from;
r.expand_to(p_to);
@@ -547,6 +672,7 @@ void GraphEdit::_draw_cos_line(const Vector2& p_from, const Vector2& p_to,const
Vector2 prev;
for(int i=0;i<=steps;i++) {
+
float d = i/float(steps);
float c=-Math::cos(d*Math_PI) * 0.5+0.5;
if (flip)
@@ -555,11 +681,12 @@ void GraphEdit::_draw_cos_line(const Vector2& p_from, const Vector2& p_to,const
if (i>0) {
- top_layer->draw_line(prev,p,p_color.linear_interpolate(p_to_color,d),2);
+ p_where->draw_line(prev,p,p_color.linear_interpolate(p_to_color,d),2);
}
prev=p;
}
+#endif
}
void GraphEdit::_top_layer_draw() {
@@ -589,53 +716,14 @@ void GraphEdit::_top_layer_draw() {
col.g+=0.4;
col.b+=0.4;
}
- _draw_cos_line(pos,topos,col,col);
- }
-
- List<List<Connection>::Element* > to_erase;
- for(List<Connection>::Element *E=connections.front();E;E=E->next()) {
-
- NodePath fromnp(E->get().from);
-
- Node * from = get_node(fromnp);
- if (!from) {
- to_erase.push_back(E);
- continue;
- }
-
- GraphNode *gfrom = from->cast_to<GraphNode>();
-
- if (!gfrom) {
- to_erase.push_back(E);
- continue;
- }
-
- NodePath tonp(E->get().to);
- Node * to = get_node(tonp);
- if (!to) {
- to_erase.push_back(E);
- continue;
- }
-
- GraphNode *gto = to->cast_to<GraphNode>();
- if (!gto) {
- to_erase.push_back(E);
- continue;
+ if (!connecting_out) {
+ SWAP(pos,topos);
}
-
- Vector2 frompos=gfrom->get_connection_output_pos(E->get().from_port)+gfrom->get_pos();
- Color color = gfrom->get_connection_output_color(E->get().from_port);
- Vector2 topos=gto->get_connection_input_pos(E->get().to_port)+gto->get_pos();
- Color tocolor = gto->get_connection_input_color(E->get().to_port);
- _draw_cos_line(frompos,topos,color,tocolor);
-
+ _draw_cos_line(top_layer,pos,topos,col,col);
}
- while(to_erase.size()) {
- connections.erase(to_erase.front()->get());
- to_erase.pop_front();
- }
+
if (box_selecting)
top_layer->draw_rect(box_selecting_rect,Color(0.7,0.7,1.0,0.3));
}
@@ -765,6 +853,7 @@ void GraphEdit::_input_event(const InputEvent& p_ev) {
dragging = false;
top_layer->update();
+ update();
}
if (b.button_index==BUTTON_LEFT && b.pressed) {
@@ -775,6 +864,10 @@ void GraphEdit::_input_event(const InputEvent& p_ev) {
gn=get_child(i)->cast_to<GraphNode>();
if (gn) {
+
+ if (gn->is_resizing())
+ continue;
+
Rect2 r = gn->get_rect();
r.size*=zoom;
if (r.has_point(get_local_mouse_pos()))
@@ -1090,6 +1183,7 @@ void GraphEdit::_bind_methods() {
ADD_SIGNAL(MethodInfo("popup_request", PropertyInfo(Variant::VECTOR2,"p_position")));
ADD_SIGNAL(MethodInfo("duplicate_nodes_request"));
ADD_SIGNAL(MethodInfo("node_selected",PropertyInfo(Variant::OBJECT,"node")));
+ ADD_SIGNAL(MethodInfo("connection_to_empty",PropertyInfo(Variant::STRING,"from"),PropertyInfo(Variant::INT,"from_slot"),PropertyInfo(Variant::VECTOR2,"release_pos")));
ADD_SIGNAL(MethodInfo("delete_nodes_request"));
ADD_SIGNAL(MethodInfo("_begin_node_move"));
ADD_SIGNAL(MethodInfo("_end_node_move"));
@@ -1173,4 +1267,6 @@ GraphEdit::GraphEdit() {
setting_scroll_ofs=false;
+
+
}
diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h
index 6d35e1518f..c3276ceacc 100644
--- a/scene/gui/graph_edit.h
+++ b/scene/gui/graph_edit.h
@@ -112,7 +112,9 @@ private:
bool updating;
List<Connection> connections;
- void _draw_cos_line(const Vector2& p_from, const Vector2& p_to, const Color& p_color, const Color &p_to_color);
+ void _bake_segment2d(CanvasItem* p_where,float p_begin, float p_end, const Vector2& p_a, const Vector2& p_out, const Vector2& p_b, const Vector2& p_in, int p_depth, int p_min_depth, int p_max_depth, float p_tol, const Color& p_color, const Color& p_to_color, int &lines) const;
+
+ void _draw_cos_line(CanvasItem* p_where,const Vector2& p_from, const Vector2& p_to, const Color& p_color, const Color &p_to_color);
void _graph_node_raised(Node* p_gn);
void _graph_node_moved(Node *p_gn);
@@ -128,6 +130,10 @@ private:
Array _get_connection_list() const;
+ bool lines_on_bg;
+
+
+
struct ConnType {
union {
@@ -200,6 +206,7 @@ public:
int get_snap() const;
void set_snap(int p_snap);
+
GraphEdit();
};
diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp
index 66d2725ad2..5ece970936 100644
--- a/scene/gui/graph_node.cpp
+++ b/scene/gui/graph_node.cpp
@@ -188,11 +188,13 @@ void GraphNode::_notification(int p_what) {
if (p_what==NOTIFICATION_DRAW) {
- Ref<StyleBox> sb=get_stylebox(selected ? "selectedframe" : "frame");
+ Ref<StyleBox> sb=get_stylebox(comment? "comment": (selected ? "selectedframe" : "frame"));
+
sb=sb->duplicate();
sb->call("set_modulate",modulate);
Ref<Texture> port =get_icon("port");
Ref<Texture> close =get_icon("close");
+ Ref<Texture> resizer =get_icon("resizer");
int close_offset = get_constant("close_offset");
Ref<Font> title_font = get_font("title_font");
int title_offset = get_constant("title_offset");
@@ -258,6 +260,11 @@ void GraphNode::_notification(int p_what) {
}
}
+
+
+ if (resizeable) {
+ draw_texture(resizer,get_size()-resizer->get_size());
+ }
}
if (p_what==NOTIFICATION_SORT_CHILDREN) {
@@ -594,19 +601,49 @@ void GraphNode::_input_event(const InputEvent& p_ev) {
ERR_EXPLAIN("GraphNode must be the child of a GraphEdit node.");
ERR_FAIL_COND(get_parent_control() == NULL);
- get_parent_control()->grab_focus();
-
if(p_ev.mouse_button.pressed && p_ev.mouse_button.button_index==BUTTON_LEFT) {
Vector2 mpos = Vector2(p_ev.mouse_button.x,p_ev.mouse_button.y);
if (close_rect.size!=Size2() && close_rect.has_point(mpos)) {
emit_signal("close_request");
+ accept_event();
+ return;
+ }
+
+ Ref<Texture> resizer =get_icon("resizer");
+
+ if (resizeable && mpos.x > get_size().x-resizer->get_width() && mpos.y > get_size().y-resizer->get_height()) {
+
+ resizing=true;
+ resizing_from=mpos;
+ resizing_from_size=get_size();
+ accept_event();
return;
}
+
+ //send focus to parent
emit_signal("raise_request");
+ get_parent_control()->grab_focus();
+
}
+
+ if(!p_ev.mouse_button.pressed && p_ev.mouse_button.button_index==BUTTON_LEFT) {
+ resizing=false;
+ }
+
+ }
+
+
+ if (resizing && p_ev.type==InputEvent::MOUSE_MOTION) {
+ Vector2 mpos = Vector2(p_ev.mouse_motion.x,p_ev.mouse_motion.y);
+
+ Vector2 diff = mpos - resizing_from;
+
+ emit_signal("resize_request",resizing_from_size+diff);
+
}
+
}
void GraphNode::set_modulate(const Color &p_color) {
@@ -630,6 +667,30 @@ GraphNode::Overlay GraphNode::get_overlay() const{
return overlay;
}
+void GraphNode::set_comment(bool p_enable) {
+
+ comment=p_enable;
+ update();
+}
+
+bool GraphNode::is_comment() const{
+
+ return comment;
+}
+
+
+void GraphNode::set_resizeable(bool p_enable) {
+
+ resizeable=p_enable;
+ update();
+}
+
+bool GraphNode::is_resizeable() const{
+
+ return resizeable;
+}
+
+
void GraphNode::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_title","title"),&GraphNode::set_title);
@@ -649,6 +710,12 @@ void GraphNode::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_offset","offset"),&GraphNode::set_offset);
ObjectTypeDB::bind_method(_MD("get_offset"),&GraphNode::get_offset);
+ ObjectTypeDB::bind_method(_MD("set_comment","comment"),&GraphNode::set_comment);
+ ObjectTypeDB::bind_method(_MD("is_comment"),&GraphNode::is_comment);
+
+ ObjectTypeDB::bind_method(_MD("set_resizeable","resizeable"),&GraphNode::set_resizeable);
+ ObjectTypeDB::bind_method(_MD("is_resizeable"),&GraphNode::is_resizeable);
+
ObjectTypeDB::bind_method(_MD("get_connection_output_count"),&GraphNode::get_connection_output_count);
ObjectTypeDB::bind_method(_MD("get_connection_input_count"),&GraphNode::get_connection_input_count);
@@ -675,6 +742,7 @@ void GraphNode::_bind_methods() {
ADD_SIGNAL(MethodInfo("dragged",PropertyInfo(Variant::VECTOR2,"from"),PropertyInfo(Variant::VECTOR2,"to")));
ADD_SIGNAL(MethodInfo("raise_request"));
ADD_SIGNAL(MethodInfo("close_request"));
+ ADD_SIGNAL(MethodInfo("resize_request",PropertyInfo(Variant::VECTOR2,"new_minsize")));
BIND_CONSTANT( OVERLAY_DISABLED );
BIND_CONSTANT( OVERLAY_BREAKPOINT );
@@ -688,4 +756,7 @@ GraphNode::GraphNode() {
connpos_dirty=true;
set_stop_mouse(false);
modulate=Color(1,1,1,1);
+ comment=false;
+ resizeable=false;
+ resizing=false;
}
diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h
index e87fb15b93..7357ab5a45 100644
--- a/scene/gui/graph_node.h
+++ b/scene/gui/graph_node.h
@@ -60,6 +60,12 @@ private:
String title;
bool show_close;
Vector2 offset;
+ bool comment;
+ bool resizeable;
+
+ bool resizing;
+ Vector2 resizing_from;
+ Vector2 resizing_from_size;
Rect2 close_rect;
@@ -144,8 +150,16 @@ public:
void set_overlay(Overlay p_overlay);
Overlay get_overlay() const;
+ void set_comment(bool p_enable);
+ bool is_comment() const;
+
+ void set_resizeable(bool p_enable);
+ bool is_resizeable() const;
+
virtual Size2 get_minimum_size() const;
+ bool is_resizing() const { return resizing; }
+
GraphNode();
};
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 487f62ed44..4a9c09d187 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -2328,9 +2328,22 @@ void Tree::_input_event(InputEvent p_event) {
range_drag_enabled=false;
Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
warp_mouse(range_drag_capture_pos);
- } else
- edit_selected();
+ } else {
+
+ if (delayed_text_editor) {
+ uint64_t diff = OS::get_singleton()->get_ticks_msec() - first_selection_time;
+ if (diff >= 400 && diff <= 800)
+ edit_selected();
+ // fast double click
+ else if (diff < 400) {
+ emit_signal("item_double_clicked");
+ }
+ first_selection_time = OS::get_singleton()->get_ticks_msec();
+ } else {
+ edit_selected();
+ }
+ }
pressing_for_editor=false;
}
@@ -2848,7 +2861,6 @@ void Tree::item_changed(int p_column,TreeItem *p_item) {
void Tree::item_selected(int p_column,TreeItem *p_item) {
-
if (select_mode==SELECT_MULTI) {
if (!p_item->cells[p_column].selectable)
@@ -2856,8 +2868,11 @@ void Tree::item_selected(int p_column,TreeItem *p_item) {
p_item->cells[p_column].selected=true;
//emit_signal("multi_selected",p_item,p_column,true); - NO this is for TreeItem::select
+ if (delayed_text_editor)
+ first_selection_time = OS::get_singleton()->get_ticks_msec();
} else {
+
select_single_item(p_item,root,p_column);
}
update();
@@ -3128,7 +3143,7 @@ void Tree::ensure_cursor_is_visible() {
int screenh=get_size().height-h_scroll->get_combined_minimum_size().height;
if (ofs+h>v_scroll->get_val()+screenh)
- v_scroll->set_val(ofs-screenh+h);
+ v_scroll->call_deferred("set_val", ofs-screenh+h);
else if (ofs < v_scroll->get_val())
v_scroll->set_val(ofs);
}
@@ -3503,6 +3518,16 @@ bool Tree::get_allow_rmb_select() const{
return allow_rmb_select;
}
+
+void Tree::set_delayed_text_editor(bool enabled) {
+ delayed_text_editor = enabled;
+}
+
+bool Tree::is_delayed_text_editor_enabled() const {
+ return delayed_text_editor;
+}
+
+
void Tree::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_range_click_timeout"),&Tree::_range_click_timeout);
@@ -3556,6 +3581,9 @@ void Tree::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_allow_rmb_select","allow"),&Tree::set_allow_rmb_select);
ObjectTypeDB::bind_method(_MD("get_allow_rmb_select"),&Tree::get_allow_rmb_select);
+ ObjectTypeDB::bind_method(_MD("set_delayed_text_editor","enable"),&Tree::set_delayed_text_editor);
+ ObjectTypeDB::bind_method(_MD("is_delayed_text_editor_enabled"),&Tree::is_delayed_text_editor_enabled);
+
ObjectTypeDB::bind_method(_MD("set_single_select_cell_editing_only_when_already_selected","enable"),&Tree::set_single_select_cell_editing_only_when_already_selected);
ObjectTypeDB::bind_method(_MD("get_single_select_cell_editing_only_when_already_selected"),&Tree::get_single_select_cell_editing_only_when_already_selected);
@@ -3566,6 +3594,7 @@ void Tree::_bind_methods() {
ADD_SIGNAL( MethodInfo("item_rmb_selected",PropertyInfo(Variant::VECTOR2,"pos")));
ADD_SIGNAL( MethodInfo("empty_tree_rmb_selected",PropertyInfo(Variant::VECTOR2,"pos")));
ADD_SIGNAL( MethodInfo("item_edited"));
+ ADD_SIGNAL( MethodInfo("item_double_clicked"));
ADD_SIGNAL( MethodInfo("item_collapsed",PropertyInfo(Variant::OBJECT,"item")));
//ADD_SIGNAL( MethodInfo("item_doubleclicked" ) );
ADD_SIGNAL( MethodInfo("button_pressed",PropertyInfo(Variant::OBJECT,"item"),PropertyInfo(Variant::INT,"column"),PropertyInfo(Variant::INT,"id")));
@@ -3669,6 +3698,9 @@ Tree::Tree() {
force_select_on_already_selected=false;
allow_rmb_select=false;
+
+ first_selection_time = 0;
+ delayed_text_editor = false;
}
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index f5100ab5b6..ff427dbe65 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -433,6 +433,9 @@ friend class TreeItem;
float last_drag_time;
float time_since_motion;*/
+ bool delayed_text_editor;
+ uint64_t first_selection_time;
+
float drag_speed;
float drag_from;
float drag_accum;
@@ -527,6 +530,9 @@ public:
void set_value_evaluator(ValueEvaluator *p_evaluator);
+ void set_delayed_text_editor(bool enabled);
+ bool is_delayed_text_editor_enabled() const;
+
Tree();
~Tree();
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 0c7d569334..086b69c1c5 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -37,6 +37,7 @@
VARIANT_ENUM_CAST(Node::PauseMode);
VARIANT_ENUM_CAST(Node::NetworkMode);
+VARIANT_ENUM_CAST(Node::RPCMode);
@@ -494,41 +495,57 @@ bool Node::is_network_master() const {
return false;
}
-void Node::allow_remote_call(const StringName& p_method) {
- data.allowed_remote_calls.insert(p_method);
-}
-void Node::disallow_remote_call(const StringName& p_method){
+void Node::_propagate_network_owner(Node*p_owner) {
- data.allowed_remote_calls.erase(p_method);
+ if (data.network_mode!=NETWORK_MODE_INHERIT)
+ return;
+ data.network_owner=p_owner;
+ for(int i=0;i<data.children.size();i++) {
+ data.children[i]->_propagate_network_owner(p_owner);
+ }
}
-void Node::allow_remote_set(const StringName& p_property){
+/***** RPC CONFIG ********/
- data.allowed_remote_set.insert(p_property);
+void Node::rpc_config(const StringName& p_method,RPCMode p_mode) {
+ if (p_mode==RPC_MODE_DISABLED) {
+ data.rpc_methods.erase(p_method);
+ } else {
+ data.rpc_methods[p_method]=p_mode;
+ };
}
-void Node::disallow_remote_set(const StringName& p_property){
- data.allowed_remote_set.erase(p_property);
+void Node::rset_config(const StringName& p_property,RPCMode p_mode) {
+
+ if (p_mode==RPC_MODE_DISABLED) {
+ data.rpc_properties.erase(p_property);
+ } else {
+ data.rpc_properties[p_property]=p_mode;
+ };
}
+/***** RPC FUNCTIONS ********/
-void Node::_propagate_network_owner(Node*p_owner) {
+void Node::rpc(const StringName& p_method,VARIANT_ARG_DECLARE) {
- if (data.network_mode!=NETWORK_MODE_INHERIT)
- return;
- data.network_owner=p_owner;
- for(int i=0;i<data.children.size();i++) {
+ VARIANT_ARGPTRS;
- data.children[i]->_propagate_network_owner(p_owner);
+ int argc=0;
+ for(int i=0;i<VARIANT_ARG_MAX;i++) {
+ if (argptr[i]->get_type()==Variant::NIL)
+ break;
+ argc++;
}
+
+ rpcp(0,false,p_method,argptr,argc);
}
-void Node::remote_call_reliable(const StringName& p_method,VARIANT_ARG_DECLARE) {
+void Node::rpc_id(int p_peer_id,const StringName& p_method,VARIANT_ARG_DECLARE) {
VARIANT_ARGPTRS;
@@ -539,16 +556,26 @@ void Node::remote_call_reliable(const StringName& p_method,VARIANT_ARG_DECLARE)
argc++;
}
- remote_call_reliablep(p_method,argptr,argc);
+ rpcp(p_peer_id,false,p_method,argptr,argc);
}
-void Node::remote_call_reliablep(const StringName& p_method,const Variant** p_arg,int p_argcount){
- ERR_FAIL_COND(!is_inside_tree());
- get_tree()->_remote_call(this,true,false,p_method,p_arg,p_argcount);
+void Node::rpc_unreliable(const StringName& p_method,VARIANT_ARG_DECLARE) {
+
+ VARIANT_ARGPTRS;
+
+ int argc=0;
+ for(int i=0;i<VARIANT_ARG_MAX;i++) {
+ if (argptr[i]->get_type()==Variant::NIL)
+ break;
+ argc++;
+ }
+
+ rpcp(0,true,p_method,argptr,argc);
}
-void Node::remote_call_unreliable(const StringName& p_method,VARIANT_ARG_DECLARE){
+
+void Node::rpc_unreliable_id(int p_peer_id,const StringName& p_method,VARIANT_ARG_DECLARE) {
VARIANT_ARGPTRS;
@@ -559,35 +586,67 @@ void Node::remote_call_unreliable(const StringName& p_method,VARIANT_ARG_DECLARE
argc++;
}
- remote_call_unreliablep(p_method,argptr,argc);
-
+ rpcp(p_peer_id,true,p_method,argptr,argc);
}
-void Node::remote_call_unreliablep(const StringName& p_method,const Variant** p_arg,int p_argcount){
- ERR_FAIL_COND(!is_inside_tree());
+Variant Node::_rpc_bind(const Variant** p_args, int p_argcount, Variant::CallError& r_error) {
- get_tree()->_remote_call(this,false,false,p_method,p_arg,p_argcount);
-}
+ if (p_argcount<1) {
+ r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument=1;
+ return Variant();
+ }
-void Node::remote_set_reliable(const StringName& p_property,const Variant& p_value) {
+ if (p_args[0]->get_type()!=Variant::STRING) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=0;
+ r_error.expected=Variant::STRING;
+ return Variant();
+ }
+ StringName method = *p_args[0];
- ERR_FAIL_COND(!is_inside_tree());
- const Variant *ptr=&p_value;
+ rpcp(0,false,method,&p_args[1],p_argcount-1);
- get_tree()->_remote_call(this,true,true,p_property,&ptr,1);
+ r_error.error=Variant::CallError::CALL_OK;
+ return Variant();
}
-void Node::remote_set_unreliable(const StringName& p_property,const Variant& p_value){
- ERR_FAIL_COND(!is_inside_tree());
- const Variant *ptr=&p_value;
+Variant Node::_rpc_id_bind(const Variant** p_args, int p_argcount, Variant::CallError& r_error) {
+
+ if (p_argcount<2) {
+ r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument=2;
+ return Variant();
+ }
- get_tree()->_remote_call(this,false,true,p_property,&ptr,1);
+ if (p_args[0]->get_type()!=Variant::INT) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=0;
+ r_error.expected=Variant::INT;
+ return Variant();
+ }
+
+ if (p_args[1]->get_type()!=Variant::STRING) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=1;
+ r_error.expected=Variant::STRING;
+ return Variant();
+ }
+
+ int peer_id = *p_args[0];
+ StringName method = *p_args[1];
+
+ rpcp(peer_id,false,method,&p_args[2],p_argcount-2);
+
+ r_error.error=Variant::CallError::CALL_OK;
+ return Variant();
}
-Variant Node::_remote_call_reliable_bind(const Variant** p_args, int p_argcount, Variant::CallError& r_error) {
+
+Variant Node::_rpc_unreliable_bind(const Variant** p_args, int p_argcount, Variant::CallError& r_error) {
if (p_argcount<1) {
r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
@@ -604,12 +663,46 @@ Variant Node::_remote_call_reliable_bind(const Variant** p_args, int p_argcount,
StringName method = *p_args[0];
- remote_call_reliablep(method,&p_args[1],p_argcount-1);
+ rpcp(0,true,method,&p_args[1],p_argcount-1);
+ r_error.error=Variant::CallError::CALL_OK;
+ return Variant();
}
-Variant Node::_remote_call_unreliable_bind(const Variant** p_args, int p_argcount, Variant::CallError& r_error) {
+Variant Node::_rpc_unreliable_id_bind(const Variant** p_args, int p_argcount, Variant::CallError& r_error) {
+
+ if (p_argcount<2) {
+ r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument=2;
+ return Variant();
+ }
+
+ if (p_args[0]->get_type()!=Variant::INT) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=0;
+ r_error.expected=Variant::INT;
+ return Variant();
+ }
+
+ if (p_args[1]->get_type()!=Variant::STRING) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=1;
+ r_error.expected=Variant::STRING;
+ return Variant();
+ }
+
+ int peer_id = *p_args[0];
+ StringName method = *p_args[1];
+
+ rpcp(peer_id,true,method,&p_args[2],p_argcount-2);
+
+ r_error.error=Variant::CallError::CALL_OK;
+ return Variant();
+}
+
+#if 0
+Variant Node::_rpc_bind(const Variant** p_args, int p_argcount, Variant::CallError& r_error) {
if (p_argcount<1) {
r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
@@ -626,8 +719,356 @@ Variant Node::_remote_call_unreliable_bind(const Variant** p_args, int p_argcoun
StringName method = *p_args[0];
- remote_call_unreliablep(method,&p_args[1],p_argcount-1);
+ rpcp(method,&p_args[1],p_argcount-1);
+ r_error.error=Variant::CallError::CALL_OK;
+ return Variant();
+}
+
+#endif
+void Node::rpcp(int p_peer_id,bool p_unreliable,const StringName& p_method,const Variant** p_arg,int p_argcount) {
+
+ ERR_FAIL_COND(!is_inside_tree());
+
+ bool skip_rpc=false;
+
+ if (p_peer_id==0 || p_peer_id==get_tree()->get_network_unique_id() || (p_peer_id<0 && p_peer_id!=-get_tree()->get_network_unique_id())) {
+ //check that send mode can use local call
+
+
+ bool call_local=false;
+
+
+
+ Map<StringName,RPCMode>::Element *E = data.rpc_methods.find(p_method);
+ if (E) {
+
+ switch(E->get()) {
+
+ case RPC_MODE_DISABLED: {
+ //do nothing
+ } break;
+ case RPC_MODE_REMOTE: {
+ //do nothing also, no need to call local
+ } break;
+ case RPC_MODE_SYNC: {
+ //call it, sync always results in call
+ call_local=true;
+ } break;
+ case RPC_MODE_MASTER: {
+ call_local=is_network_master();
+ if (call_local) {
+ skip_rpc=true; //no other master so..
+ }
+ } break;
+ case RPC_MODE_SLAVE: {
+ call_local=!is_network_master();
+ } break;
+
+ }
+ }
+
+
+ if (call_local) {
+ Variant::CallError ce;
+ call(p_method,p_arg,p_argcount,ce);
+ if (ce.error!=Variant::CallError::CALL_OK) {
+ String error = Variant::get_call_error_text(this,p_method,p_arg,p_argcount,ce);
+ error="rpc() aborted in local call: - "+error;
+ ERR_PRINTS(error);
+ return;
+ }
+ } else if (get_script_instance()){
+ //attempt with script
+ ScriptInstance::RPCMode rpc_mode = get_script_instance()->get_rpc_mode(p_method);
+
+ switch(rpc_mode) {
+
+ case ScriptInstance::RPC_MODE_DISABLED: {
+ //do nothing
+ } break;
+ case ScriptInstance::RPC_MODE_REMOTE: {
+ //do nothing also, no need to call local
+ } break;
+ case ScriptInstance::RPC_MODE_SYNC: {
+ //call it, sync always results in call
+ call_local=true;
+ } break;
+ case ScriptInstance::RPC_MODE_MASTER: {
+ call_local=is_network_master();
+ if (call_local) {
+ skip_rpc=true; //no other master so..
+ }
+ } break;
+ case ScriptInstance::RPC_MODE_SLAVE: {
+ call_local=!is_network_master();
+ } break;
+ }
+
+ if (call_local) {
+ Variant::CallError ce;
+ ce.error=Variant::CallError::CALL_OK;
+ get_script_instance()->call(p_method,p_arg,p_argcount,ce);
+ if (ce.error!=Variant::CallError::CALL_OK) {
+ String error = Variant::get_call_error_text(this,p_method,p_arg,p_argcount,ce);
+ error="rpc() aborted in script local call: - "+error;
+ ERR_PRINTS(error);
+ return;
+ }
+ }
+ }
+ }
+
+ if (skip_rpc)
+ return;
+
+
+ get_tree()->_rpc(this,p_peer_id,p_unreliable,false,p_method,p_arg,p_argcount);
+
+}
+
+
+/******** RSET *********/
+
+
+void Node::rsetp(int p_peer_id,bool p_unreliable,const StringName& p_property,const Variant& p_value) {
+
+ ERR_FAIL_COND(!is_inside_tree());
+
+ bool skip_rset=false;
+
+ if (p_peer_id==0 || p_peer_id==get_tree()->get_network_unique_id() || (p_peer_id<0 && p_peer_id!=-get_tree()->get_network_unique_id())) {
+ //check that send mode can use local call
+
+
+ bool set_local=false;
+
+ Map<StringName,RPCMode>::Element *E = data.rpc_properties.find(p_property);
+ if (E) {
+
+ switch(E->get()) {
+
+ case RPC_MODE_DISABLED: {
+ //do nothing
+ } break;
+ case RPC_MODE_REMOTE: {
+ //do nothing also, no need to call local
+ } break;
+ case RPC_MODE_SYNC: {
+ //call it, sync always results in call
+ set_local=true;
+ } break;
+ case RPC_MODE_MASTER: {
+ set_local=is_network_master();
+ if (set_local) {
+ skip_rset=true;
+ }
+
+ } break;
+ case RPC_MODE_SLAVE: {
+ set_local=!is_network_master();
+ } break;
+
+ }
+ }
+
+
+ if (set_local) {
+ bool valid;
+ set(p_property,p_value,&valid);
+
+ if (!valid) {
+ String error="rset() aborted in local set, property not found: - "+String(p_property);
+ ERR_PRINTS(error);
+ return;
+ }
+ } else if (get_script_instance()){
+ //attempt with script
+ ScriptInstance::RPCMode rpc_mode = get_script_instance()->get_rset_mode(p_property);
+
+ switch(rpc_mode) {
+
+ case ScriptInstance::RPC_MODE_DISABLED: {
+ //do nothing
+ } break;
+ case ScriptInstance::RPC_MODE_REMOTE: {
+ //do nothing also, no need to call local
+ } break;
+ case ScriptInstance::RPC_MODE_SYNC: {
+ //call it, sync always results in call
+ set_local=true;
+ } break;
+ case ScriptInstance::RPC_MODE_MASTER: {
+ set_local=is_network_master();
+ if (set_local) {
+ skip_rset=true;
+ }
+ } break;
+ case ScriptInstance::RPC_MODE_SLAVE: {
+ set_local=!is_network_master();
+ } break;
+ }
+
+ if (set_local) {
+
+ bool valid = get_script_instance()->set(p_property,p_value);
+
+ if (!valid) {
+ String error="rset() aborted in local script set, property not found: - "+String(p_property);
+ ERR_PRINTS(error);
+ return;
+ }
+ }
+
+ }
+ }
+
+ if (skip_rset)
+ return;
+
+ const Variant*vptr = &p_value;
+
+ get_tree()->_rpc(this,p_peer_id,p_unreliable,true,p_property,&vptr,1);
+
+}
+
+
+
+void Node::rset(const StringName& p_property,const Variant& p_value) {
+
+ rsetp(0,false,p_property,p_value);
+
+}
+
+void Node::rset_id(int p_peer_id,const StringName& p_property,const Variant& p_value) {
+
+ rsetp(p_peer_id,false,p_property,p_value);
+
+}
+
+void Node::rset_unreliable(const StringName& p_property,const Variant& p_value) {
+
+ rsetp(0,true,p_property,p_value);
+
+}
+
+void Node::rset_unreliable_id(int p_peer_id,const StringName& p_property,const Variant& p_value) {
+
+ rsetp(p_peer_id,true,p_property,p_value);
+
+}
+
+//////////// end of rpc
+
+bool Node::can_call_rpc(const StringName& p_method) const {
+
+ const Map<StringName,RPCMode>::Element *E = data.rpc_methods.find(p_method);
+ if (E) {
+
+ switch(E->get()) {
+
+ case RPC_MODE_DISABLED: {
+ return false;
+ } break;
+ case RPC_MODE_REMOTE: {
+ return true;
+ } break;
+ case RPC_MODE_SYNC: {
+ return true;
+ } break;
+ case RPC_MODE_MASTER: {
+ return is_network_master();
+ } break;
+ case RPC_MODE_SLAVE: {
+ return !is_network_master();
+ } break;
+ }
+ }
+
+
+ if (get_script_instance()){
+ //attempt with script
+ ScriptInstance::RPCMode rpc_mode = get_script_instance()->get_rpc_mode(p_method);
+
+ switch(rpc_mode) {
+
+ case ScriptInstance::RPC_MODE_DISABLED: {
+ return false;
+ } break;
+ case ScriptInstance::RPC_MODE_REMOTE: {
+ return true;
+ } break;
+ case ScriptInstance::RPC_MODE_SYNC: {
+ return true;
+ } break;
+ case ScriptInstance::RPC_MODE_MASTER: {
+ return is_network_master();
+ } break;
+ case ScriptInstance::RPC_MODE_SLAVE: {
+ return !is_network_master();
+ } break;
+ }
+
+ }
+
+ ERR_PRINTS("RPC on unauthorized method attempted: "+String(p_method)+" on base: "+String(Variant(this)));
+ return false;
+}
+
+bool Node::can_call_rset(const StringName& p_property) const {
+
+ const Map<StringName,RPCMode>::Element *E = data.rpc_properties.find(p_property);
+ if (E) {
+
+ switch(E->get()) {
+
+ case RPC_MODE_DISABLED: {
+ return false;
+ } break;
+ case RPC_MODE_REMOTE: {
+ return true;
+ } break;
+ case RPC_MODE_SYNC: {
+ return true;
+ } break;
+ case RPC_MODE_MASTER: {
+ return is_network_master();
+ } break;
+ case RPC_MODE_SLAVE: {
+ return !is_network_master();
+ } break;
+ }
+ }
+
+
+ if (get_script_instance()){
+ //attempt with script
+ ScriptInstance::RPCMode rpc_mode = get_script_instance()->get_rset_mode(p_property);
+
+ switch(rpc_mode) {
+
+ case ScriptInstance::RPC_MODE_DISABLED: {
+ return false;
+ } break;
+ case ScriptInstance::RPC_MODE_REMOTE: {
+ return true;
+ } break;
+ case ScriptInstance::RPC_MODE_SYNC: {
+ return true;
+ } break;
+ case ScriptInstance::RPC_MODE_MASTER: {
+ return is_network_master();
+ } break;
+ case ScriptInstance::RPC_MODE_SLAVE: {
+ return !is_network_master();
+ } break;
+ }
+
+ }
+
+ ERR_PRINTS("RSET on unauthorized property attempted: "+String(p_property)+" on base: "+String(Variant(this)));
+
+ return false;
}
@@ -2444,11 +2885,9 @@ void Node::_bind_methods() {
ObjectTypeDB::bind_method(_MD("is_network_master"),&Node::is_network_master);
- ObjectTypeDB::bind_method(_MD("allow_remote_call","method"),&Node::allow_remote_call);
- ObjectTypeDB::bind_method(_MD("disallow_remote_call","method"),&Node::disallow_remote_call);
+ ObjectTypeDB::bind_method(_MD("rpc_config","method","mode"),&Node::rpc_config);
+ ObjectTypeDB::bind_method(_MD("rset_config","property","mode"),&Node::rset_config);
- ObjectTypeDB::bind_method(_MD("allow_remote_set","method"),&Node::allow_remote_set);
- ObjectTypeDB::bind_method(_MD("disallow_remote_set","method"),&Node::disallow_remote_set);
#ifdef TOOLS_ENABLED
ObjectTypeDB::bind_method(_MD("_set_import_path","import_path"),&Node::set_import_path);
@@ -2459,19 +2898,29 @@ void Node::_bind_methods() {
{
MethodInfo mi;
- mi.name="remote_call_reliable";
+
mi.arguments.push_back( PropertyInfo( Variant::STRING, "method"));
- ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"remote_call_reliable",&Node::_remote_call_reliable_bind,mi);
+ mi.name="rpc";
+ ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"rpc",&Node::_rpc_bind,mi);
+ mi.name="rpc_unreliable";
+ ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"rpc_unreliable",&Node::_rpc_unreliable_bind,mi);
+
+ mi.arguments.push_front( PropertyInfo( Variant::INT, "peer_") );
+
+ mi.name="rpc_id";
+ ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"rpc_id",&Node::_rpc_id_bind,mi);
+ mi.name="rpc_unreliable_id";
+ ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"rpc_unreliable_id",&Node::_rpc_unreliable_id_bind,mi);
- mi.name="remote_call_unreliable";
- ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"remote_call_unreliable",&Node::_remote_call_unreliable_bind,mi);
}
- ObjectTypeDB::bind_method(_MD("remote_set_reliable","property","value:Variant"),&Node::remote_set_reliable);
- ObjectTypeDB::bind_method(_MD("remote_set_unreliable","property","value:Variant"),&Node::remote_set_unreliable);
+ ObjectTypeDB::bind_method(_MD("rset","property","value:Variant"),&Node::rset);
+ ObjectTypeDB::bind_method(_MD("rset_id","peer_id","property","value:Variant"),&Node::rset_id);
+ ObjectTypeDB::bind_method(_MD("rset_unreliable","property","value:Variant"),&Node::rset_unreliable);
+ ObjectTypeDB::bind_method(_MD("rset_unreliable_id","peer_id","property","value:Variant"),&Node::rset_unreliable_id);
BIND_CONSTANT( NOTIFICATION_ENTER_TREE );
@@ -2491,7 +2940,15 @@ void Node::_bind_methods() {
BIND_CONSTANT( NOTIFICATION_PATH_CHANGED);
+ BIND_CONSTANT( NETWORK_MODE_INHERIT );
+ BIND_CONSTANT( NETWORK_MODE_MASTER );
+ BIND_CONSTANT( NETWORK_MODE_SLAVE );
+ BIND_CONSTANT( RPC_MODE_DISABLED );
+ BIND_CONSTANT( RPC_MODE_REMOTE );
+ BIND_CONSTANT( RPC_MODE_SYNC );
+ BIND_CONSTANT( RPC_MODE_MASTER );
+ BIND_CONSTANT( RPC_MODE_SLAVE );
BIND_CONSTANT( PAUSE_MODE_INHERIT );
BIND_CONSTANT( PAUSE_MODE_STOP );
@@ -2506,7 +2963,6 @@ void Node::_bind_methods() {
//ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "process/input" ), _SCS("set_process_input"),_SCS("is_processing_input" ) );
//ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "process/unhandled_input" ), _SCS("set_process_unhandled_input"),_SCS("is_processing_unhandled_input" ) );
ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "process/pause_mode",PROPERTY_HINT_ENUM,"Inherit,Stop,Process" ), _SCS("set_pause_mode"),_SCS("get_pause_mode" ) );
- ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "process/network_mode",PROPERTY_HINT_ENUM,"Inherit,Master,Slave" ), _SCS("set_network_mode"),_SCS("get_network_mode" ) );
ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "editor/display_folded",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR ), _SCS("set_display_folded"),_SCS("is_displayed_folded" ) );
BIND_VMETHOD( MethodInfo("_process",PropertyInfo(Variant::REAL,"delta")) );
diff --git a/scene/main/node.h b/scene/main/node.h
index 761725286e..3568da2ab0 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -60,6 +60,15 @@ public:
NETWORK_MODE_SLAVE
};
+ enum RPCMode {
+
+ RPC_MODE_DISABLED, //no rpc for this method, calls to this will be blocked (default)
+ RPC_MODE_REMOTE, // using rpc() on it will call method / set property in all other peers
+ RPC_MODE_SYNC, // using rpc() on it will call method / set property in all other peers and locally
+ RPC_MODE_MASTER, // usinc rpc() on it will call method on wherever the master is, be it local or remote
+ RPC_MODE_SLAVE, // usinc rpc() on it will call method for all slaves, be it local or remote
+ };
+
struct Comparator {
bool operator()(const Node* p_a, const Node* p_b) const { return p_b->is_greater_than(p_a); }
@@ -75,6 +84,7 @@ private:
};
+
struct Data {
String filename;
@@ -108,8 +118,8 @@ private:
NetworkMode network_mode;
Node *network_owner;
- Set<StringName> allowed_remote_calls;
- Set<StringName> allowed_remote_set;
+ Map<StringName,RPCMode> rpc_methods;
+ Map<StringName,RPCMode> rpc_properties;
// variables used to properly sort the node when processing, ignored otherwise
@@ -160,8 +170,10 @@ private:
Array _get_children() const;
Array _get_groups() const;
- Variant _remote_call_reliable_bind(const Variant** p_args, int p_argcount, Variant::CallError& r_error);
- Variant _remote_call_unreliable_bind(const Variant** p_args, int p_argcount, Variant::CallError& r_error);
+ Variant _rpc_bind(const Variant** p_args, int p_argcount, Variant::CallError& r_error);
+ Variant _rpc_unreliable_bind(const Variant** p_args, int p_argcount, Variant::CallError& r_error);
+ Variant _rpc_id_bind(const Variant** p_args, int p_argcount, Variant::CallError& r_error);
+ Variant _rpc_unreliable_id_bind(const Variant** p_args, int p_argcount, Variant::CallError& r_error);
friend class SceneTree;
@@ -358,20 +370,25 @@ public:
NetworkMode get_network_mode() const;
bool is_network_master() const;
- void allow_remote_call(const StringName& p_method);
- void disallow_remote_call(const StringName& p_method);
+ void rpc_config(const StringName& p_method,RPCMode p_mode); // config a local method for RPC
+ void rset_config(const StringName& p_property,RPCMode p_mode); // config a local property for RPC
+
+ void rpc(const StringName& p_method,VARIANT_ARG_LIST); //rpc call, honors RPCMode
+ void rpc_unreliable(const StringName& p_method,VARIANT_ARG_LIST); //rpc call, honors RPCMode
+ void rpc_id(int p_peer_id,const StringName& p_method,VARIANT_ARG_LIST); //rpc call, honors RPCMode
+ void rpc_unreliable_id(int p_peer_id,const StringName& p_method,VARIANT_ARG_LIST); //rpc call, honors RPCMode
- void allow_remote_set(const StringName& p_property);
- void disallow_remote_set(const StringName& p_property);
+ void rpcp(int p_peer_id,bool p_unreliable,const StringName& p_method,const Variant** p_arg,int p_argcount);
- void remote_call_reliable(const StringName& p_method,VARIANT_ARG_DECLARE);
- void remote_call_reliablep(const StringName& p_method,const Variant** p_arg,int p_argcount);
+ void rset(const StringName& p_property, const Variant& p_value); //remote set call, honors RPCMode
+ void rset_unreliable(const StringName& p_property,const Variant& p_value); //remote set call, honors RPCMode
+ void rset_id(int p_peer_id,const StringName& p_property,const Variant& p_value); //remote set call, honors RPCMode
+ void rset_unreliable_id(int p_peer_id,const StringName& p_property,const Variant& p_value); //remote set call, honors RPCMode
- void remote_call_unreliable(const StringName& p_method,VARIANT_ARG_DECLARE);
- void remote_call_unreliablep(const StringName& p_method,const Variant** p_arg,int p_argcount);
+ void rsetp(int p_peer_id,bool p_unreliable,const StringName& p_property,const Variant& p_value);
- void remote_set_reliable(const StringName& p_property,const Variant& p_value);
- void remote_set_unreliable(const StringName& p_property,const Variant& p_value);
+ bool can_call_rpc(const StringName& p_method) const;
+ bool can_call_rset(const StringName& p_property) const;
Node();
diff --git a/scene/main/scene_main_loop.cpp b/scene/main/scene_main_loop.cpp
index 6af2b9b169..4c7b7c1399 100644
--- a/scene/main/scene_main_loop.cpp
+++ b/scene/main/scene_main_loop.cpp
@@ -44,7 +44,7 @@
#include "scene/resources/packed_scene.h"
#include "scene/resources/material.h"
#include "scene/resources/mesh.h"
-
+#include "io/marshalls.h"
void SceneTreeTimer::_bind_methods() {
@@ -1657,25 +1657,45 @@ Ref<SceneTreeTimer> SceneTree::create_timer(float p_delay_sec) {
return stt;
}
-void SceneTree::_network_peer_connected(const StringName& p_id) {
+void SceneTree::_network_peer_connected(int p_id) {
connected_peers.insert(p_id);
path_get_cache.insert(p_id,PathGetCache());
+
+
emit_signal("network_peer_connected",p_id);
}
-void SceneTree::_network_peer_disconnected(const StringName& p_id) {
+void SceneTree::_network_peer_disconnected(int p_id) {
connected_peers.erase(p_id);
path_get_cache.erase(p_id); //I no longer need your cache, sorry
emit_signal("network_peer_disconnected",p_id);
}
+void SceneTree::_connected_to_server() {
+
+ emit_signal("connected_to_server");
+}
+
+void SceneTree::_connection_failed() {
+
+ emit_signal("connection_failed");
+}
+
+void SceneTree::_server_disconnected() {
+
+ emit_signal("server_disconnected");
+}
+
void SceneTree::set_network_peer(const Ref<NetworkedMultiplayerPeer>& p_network_peer) {
if (network_peer.is_valid()) {
network_peer->disconnect("peer_connected",this,"_network_peer_connected");
network_peer->disconnect("peer_disconnected",this,"_network_peer_disconnected");
+ network_peer->disconnect("connection_succeeded",this,"_connected_to_server");
+ network_peer->disconnect("connection_failed",this,"_connection_failed");
+ network_peer->disconnect("server_disconnected",this,"_server_disconnected");
connected_peers.clear();
path_get_cache.clear();
path_send_cache.clear();
@@ -1690,6 +1710,9 @@ void SceneTree::set_network_peer(const Ref<NetworkedMultiplayerPeer>& p_network_
if (network_peer.is_valid()) {
network_peer->connect("peer_connected",this,"_network_peer_connected");
network_peer->connect("peer_disconnected",this,"_network_peer_disconnected");
+ network_peer->connect("connection_succeeded",this,"_connected_to_server");
+ network_peer->connect("connection_failed",this,"_connection_failed");
+ network_peer->connect("server_disconnected",this,"_server_disconnected");
}
}
@@ -1700,7 +1723,27 @@ bool SceneTree::is_network_server() const {
}
-void SceneTree::_remote_call(Node* p_from, bool p_reliable, bool p_set, const StringName& p_name, const Variant** p_arg, int p_argcount) {
+int SceneTree::get_network_unique_id() const {
+
+ ERR_FAIL_COND_V(!network_peer.is_valid(),0);
+ return network_peer->get_unique_id();
+}
+
+void SceneTree::set_refuse_new_network_connections(bool p_refuse) {
+ ERR_FAIL_COND(!network_peer.is_valid());
+ network_peer->set_refuse_new_connections(p_refuse);
+}
+
+bool SceneTree::is_refusing_new_network_connections() const {
+
+ ERR_FAIL_COND_V(!network_peer.is_valid(),false);
+
+ return network_peer->is_refusing_new_connections();
+
+}
+
+
+void SceneTree::_rpc(Node* p_from,int p_to,bool p_unreliable,bool p_set,const StringName& p_name,const Variant** p_arg,int p_argcount) {
if (network_peer.is_null()) {
ERR_EXPLAIN("Attempt to remote call/set when networking is not active in SceneTree.");
@@ -1717,28 +1760,26 @@ void SceneTree::_remote_call(Node* p_from, bool p_reliable, bool p_set, const St
ERR_FAIL();
}
- NodePath from_path = p_from->get_path();
- ERR_FAIL_COND(from_path.is_empty());
+ if (p_argcount>255) {
+ ERR_EXPLAIN("Too many arguments >255.");
+ ERR_FAIL();
+ }
- //create base packet
- Array message;
+ if (p_to!=0 && !connected_peers.has(ABS(p_to))) {
+ if (p_to==get_network_unique_id()) {
+ ERR_EXPLAIN("Attempt to remote call/set yourself! unique ID: "+itos(get_network_unique_id()));
+ } else {
+ ERR_EXPLAIN("Attempt to remote call unexisting ID: "+itos(p_to));
- message.resize(3+p_argcount); //alloc size for args
+ }
- //set message type
- if (p_set) {
- message[0]=NETWORK_COMMAND_REMOTE_SET;
- } else {
- message[0]=NETWORK_COMMAND_REMOTE_CALL;
+ ERR_FAIL();
}
- //set message name
- message[2]=p_name;
+ NodePath from_path = p_from->get_path();
+ ERR_FAIL_COND(from_path.is_empty());
+
- //set message args
- for(int i=0;i<p_argcount;i++) {
- message[3+i]=*p_arg[i];
- }
//see if the path is cached
PathSentCache *psc = path_send_cache.getptr(from_path);
@@ -1750,14 +1791,67 @@ void SceneTree::_remote_call(Node* p_from, bool p_reliable, bool p_set, const St
}
+
+ //create base packet, lots of harcode because it must be tight
+
+ int ofs=0;
+
+#define MAKE_ROOM(m_amount) if (packet_cache.size() < m_amount) packet_cache.resize(m_amount);
+
+ //encode type
+ MAKE_ROOM(1);
+ packet_cache[0]=p_set ? NETWORK_COMMAND_REMOTE_SET : NETWORK_COMMAND_REMOTE_CALL;
+ ofs+=1;
+
+ //encode ID
+ MAKE_ROOM(ofs+4);
+ encode_uint32(psc->id,&packet_cache[ofs]);
+ ofs+=4;
+
+ //encode function name
+ CharString name = String(p_name).utf8();
+ int len = encode_cstring(name.get_data(),NULL);
+ MAKE_ROOM(ofs+len);
+ encode_cstring(name.get_data(),&packet_cache[ofs]);
+ ofs+=len;
+
+ if (p_set) {
+ //set argument
+ Error err = encode_variant(*p_arg[0],NULL,len);
+ ERR_FAIL_COND(err!=OK);
+ MAKE_ROOM(ofs+len);
+ encode_variant(*p_arg[0],&packet_cache[ofs],len);
+ ofs+=len;
+
+ } else {
+ //call arguments
+ MAKE_ROOM(ofs+1);
+ packet_cache[ofs]=p_argcount;
+ ofs+=1;
+ for(int i=0;i<p_argcount;i++) {
+ Error err = encode_variant(*p_arg[i],NULL,len);
+ ERR_FAIL_COND(err!=OK);
+ MAKE_ROOM(ofs+len);
+ encode_variant(*p_arg[i],&packet_cache[ofs],len);
+ ofs+=len;
+ }
+
+ }
+
//see if all peers have cached path (is so, call can be fast)
bool has_all_peers=true;
- List<StringName> peers_to_add; //if one is missing, take note to add it
+ List<int> peers_to_add; //if one is missing, take note to add it
+
+ for (Set<int>::Element *E=connected_peers.front();E;E=E->next()) {
- for (Set<StringName>::Element *E=connected_peers.front();E;E=E->next()) {
+ if (p_to<0 && E->get()==-p_to)
+ continue; //continue, excluded
- Map<StringName,bool>::Element *F = psc->confirmed_peers.find(E->get());
+ if (p_to>0 && E->get()!=p_to)
+ continue; //continue, not for this peer
+
+ Map<int,bool>::Element *F = psc->confirmed_peers.find(E->get());
if (!F || F->get()==false) {
//path was not cached, or was cached but is unconfirmed
@@ -1767,87 +1861,114 @@ void SceneTree::_remote_call(Node* p_from, bool p_reliable, bool p_set, const St
}
has_all_peers=false;
- break;
}
}
//those that need to be added, send a message for this
- for (List<StringName>::Element *E=peers_to_add.front();E;E=E->next()) {
+ for (List<int>::Element *E=peers_to_add.front();E;E=E->next()) {
- Array add_path_message;
- add_path_message.resize(3);
- add_path_message[0]=NETWORK_COMMAND_SIMPLIFY_PATH;
- add_path_message[1]=from_path;
- add_path_message[2]=psc->id;
+ //encode function name
+ CharString pname = String(from_path).utf8();
+ int len = encode_cstring(pname.get_data(),NULL);
+
+ Vector<uint8_t> packet;
+
+ packet.resize(1+4+len);
+ packet[0]=NETWORK_COMMAND_SIMPLIFY_PATH;
+ encode_uint32(psc->id,&packet[1]);
+ encode_cstring(pname.get_data(),&packet[5]);
network_peer->set_target_peer(E->get()); //to all of you
- network_peer->set_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_ORDERED);
- network_peer->put_var(add_path_message); //a message with love
+ network_peer->set_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE);
+ network_peer->put_packet(packet.ptr(),packet.size());
psc->confirmed_peers.insert(E->get(),false); //insert into confirmed, but as false since it was not confirmed
}
//take chance and set transfer mode, since all send methods will use it
- network_peer->set_transfer_mode(p_reliable ? NetworkedMultiplayerPeer::TRANSFER_MODE_ORDERED : NetworkedMultiplayerPeer::TRANSFER_MODE_UNRELIABLE);
+ network_peer->set_transfer_mode(p_unreliable ? NetworkedMultiplayerPeer::TRANSFER_MODE_UNRELIABLE : NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE);
if (has_all_peers) {
//they all have verified paths, so send fast
- message[1]=psc->id;
-
- network_peer->set_target_peer(StringName()); //to all of you
- network_peer->put_var(message); //a message with love
+ network_peer->set_target_peer(p_to); //to all of you
+ network_peer->put_packet(packet_cache.ptr(),ofs); //a message with love
} else {
//not all verified path, so send one by one
- for (Set<StringName>::Element *E=connected_peers.front();E;E=E->next()) {
- Map<StringName,bool>::Element *F = psc->confirmed_peers.find(E->get());
+ //apend path at the end, since we will need it for some packets
+ CharString pname = String(from_path).utf8();
+ int path_len = encode_cstring(pname.get_data(),NULL);
+ MAKE_ROOM(ofs+path_len);
+ encode_cstring(pname.get_data(),&packet_cache[ofs]);
+
+
+ for (Set<int>::Element *E=connected_peers.front();E;E=E->next()) {
+
+ if (p_to<0 && E->get()==-p_to)
+ continue; //continue, excluded
+
+ if (p_to>0 && E->get()!=p_to)
+ continue; //continue, not for this peer
+
+ Map<int,bool>::Element *F = psc->confirmed_peers.find(E->get());
ERR_CONTINUE(!F);//should never happen
network_peer->set_target_peer(E->get()); //to this one specifically
if (F->get()==true) {
//this one confirmed path, so use id
- message[1]=psc->id;
+ encode_uint32(psc->id,&packet_cache[1]);
+ network_peer->put_packet(packet_cache.ptr(),ofs);
} else {
//this one did not confirm path yet, so use entire path (sorry!)
- message[1]=from_path;
+ encode_uint32(0x80000000|ofs,&packet_cache[1]); //offset to path and flag
+ network_peer->put_packet(packet_cache.ptr(),ofs+path_len);
}
- network_peer->put_var(message);
}
}
}
-void SceneTree::_network_process_packet(const StringName& p_from,const Array& p_packet) {
+void SceneTree::_network_process_packet(int p_from, const uint8_t* p_packet, int p_packet_len) {
- ERR_FAIL_COND(p_packet.empty());
+ ERR_FAIL_COND(p_packet_len<5);
- int packet_type = p_packet[0];
+ uint8_t packet_type = p_packet[0];
switch(packet_type) {
case NETWORK_COMMAND_REMOTE_CALL:
case NETWORK_COMMAND_REMOTE_SET: {
- ERR_FAIL_COND(p_packet.size()<3);
- Variant target = p_packet[1];
- Node* node=NULL;
+ ERR_FAIL_COND(p_packet_len<5);
+ uint32_t target = decode_uint32(&p_packet[1]);
+
+
+ Node *node=NULL;
+
+ if (target&0x80000000) {
+
+ int ofs = target&0x7FFFFFFF;
+ ERR_FAIL_COND(ofs>=p_packet_len);
+
+ String paths;
+ paths.parse_utf8((const char*)&p_packet[ofs],p_packet_len-ofs);
+
+ NodePath np = paths;
- if (target.get_type()==Variant::NODE_PATH) {
- NodePath np = target;
node = get_root()->get_node(np);
if (node==NULL) {
ERR_EXPLAIN("Failed to get path from RPC: "+String(np));
ERR_FAIL_COND(node==NULL);
}
- } else if (target.get_type()==Variant::INT) {
+ } else {
int id = target;
- Map<StringName,PathGetCache>::Element *E=path_get_cache.find(p_from);
+ Map<int,PathGetCache>::Element *E=path_get_cache.find(p_from);
ERR_FAIL_COND(!E);
Map<int,PathGetCache::NodeInfo>::Element *F=E->get().nodes.find(id);
@@ -1863,23 +1984,51 @@ void SceneTree::_network_process_packet(const StringName& p_from,const Array& p_
}
- } else {
- ERR_FAIL();
}
- StringName name = p_packet[2];
+ ERR_FAIL_COND(p_packet_len<6);
+
+ //detect cstring end
+ int len_end=5;
+ for(;len_end<p_packet_len;len_end++) {
+ if (p_packet[len_end]==0) {
+ break;
+ }
+ }
+
+ ERR_FAIL_COND(len_end>=p_packet_len);
+
+ StringName name = String::utf8((const char*)&p_packet[5]);
+
+
+
if (packet_type==NETWORK_COMMAND_REMOTE_CALL) {
- int argc = p_packet.size()-3;
+ if (!node->can_call_rpc(name))
+ return;
+
+ int ofs = len_end+1;
+
+ ERR_FAIL_COND(ofs>=p_packet_len);
+
+ int argc = p_packet[ofs];
Vector<Variant> args;
Vector<const Variant*> argp;
args.resize(argc);
argp.resize(argc);
+ ofs++;
+
for(int i=0;i<argc;i++) {
- args[i]=p_packet[3+i];
- argp[i]=&args[i];
+
+ ERR_FAIL_COND(ofs>=p_packet_len);
+ int vlen;
+ Error err = decode_variant(args[i],&p_packet[ofs],p_packet_len-ofs,&vlen);
+ ERR_FAIL_COND(err!=OK);
+ //args[i]=p_packet[3+i];
+ argp[i]=&args[i];
+ ofs+=vlen;
}
Variant::CallError ce;
@@ -1887,14 +2036,22 @@ void SceneTree::_network_process_packet(const StringName& p_from,const Array& p_
node->call(name,argp.ptr(),argc,ce);
if (ce.error!=Variant::CallError::CALL_OK) {
String error = Variant::get_call_error_text(node,name,argp.ptr(),argc,ce);
+ error="RPC - "+error;
ERR_PRINTS(error);
}
} else {
+ if (!node->can_call_rset(name))
+ return;
+
+ int ofs = len_end+1;
+
+ ERR_FAIL_COND(ofs>=p_packet_len);
+
+ Variant value;
+ decode_variant(value,&p_packet[ofs],p_packet_len-ofs);
- ERR_FAIL_COND(p_packet.size()!=4);
- Variant value = p_packet[3];
bool valid;
node->set(name,value,&valid);
@@ -1907,9 +2064,13 @@ void SceneTree::_network_process_packet(const StringName& p_from,const Array& p_
} break;
case NETWORK_COMMAND_SIMPLIFY_PATH: {
- ERR_FAIL_COND(p_packet.size()!=3);
- NodePath path = p_packet[1];
- int id = p_packet[2];
+ ERR_FAIL_COND(p_packet_len<5);
+ int id = decode_uint32(&p_packet[1]);
+
+ String paths;
+ paths.parse_utf8((const char*)&p_packet[5],p_packet_len-5);
+
+ NodePath path = paths;
if (!path_get_cache.has(p_from)) {
path_get_cache[p_from]=PathGetCache();
@@ -1921,24 +2082,36 @@ void SceneTree::_network_process_packet(const StringName& p_from,const Array& p_
path_get_cache[p_from].nodes[id]=ni;
- network_peer->set_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_ORDERED);
- network_peer->set_target_peer(p_from);
- Array message;
- message.resize(2);
- message[0]=NETWORK_COMMAND_CONFIRM_PATH;
- message[1]=path;
+ {
+ //send ack
+
+ //encode path
+ CharString pname = String(path).utf8();
+ int len = encode_cstring(pname.get_data(),NULL);
+
+ Vector<uint8_t> packet;
- network_peer->put_var(message);
+ packet.resize(1+len);
+ packet[0]=NETWORK_COMMAND_CONFIRM_PATH;
+ encode_cstring(pname.get_data(),&packet[1]);
+
+ network_peer->set_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE);
+ network_peer->set_target_peer(p_from);
+ network_peer->put_packet(packet.ptr(),packet.size());
+ }
} break;
case NETWORK_COMMAND_CONFIRM_PATH: {
- ERR_FAIL_COND(p_packet.size()!=2);
- NodePath path = p_packet[1];
+
+ String paths;
+ paths.parse_utf8((const char*)&p_packet[1],p_packet_len-1);
+
+ NodePath path = paths;
PathSentCache *psc = path_send_cache.getptr(path);
ERR_FAIL_COND(!psc);
- Map<StringName,bool>::Element *E=psc->confirmed_peers.find(p_from);
+ Map<int,bool>::Element *E=psc->confirmed_peers.find(p_from);
ERR_FAIL_COND(!E);
E->get()=true;
} break;
@@ -1948,25 +2121,30 @@ void SceneTree::_network_process_packet(const StringName& p_from,const Array& p_
void SceneTree::_network_poll() {
- if (!network_peer.is_valid())
+ if (!network_peer.is_valid() || network_peer->get_connection_status()==NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED)
return;
network_peer->poll();
+ if (!network_peer.is_valid()) //it's possible that polling might have resulted in a disconnection, so check here
+ return;
+
while(network_peer->get_available_packet_count()) {
- StringName sender = network_peer->get_packet_peer();
- Variant packet;
- Error err = network_peer->get_var(packet);
+ int sender = network_peer->get_packet_peer();
+ const uint8_t *packet;
+ int len;
+
+ Error err = network_peer->get_packet(&packet,len);
if (err!=OK) {
ERR_PRINT("Error getting packet!");
}
- if (packet.get_type()!=Variant::ARRAY) {
- ERR_PRINT("Error getting packet! (not an array)");
- }
+ _network_process_packet(sender,packet,len);
- _network_process_packet(sender,packet);
+ if (!network_peer.is_valid()) {
+ break; //it's also possible that a packet or RPC caused a disconnection, so also check here
+ }
}
@@ -2042,9 +2220,15 @@ void SceneTree::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_network_peer","peer:NetworkedMultiplayerPeer"),&SceneTree::set_network_peer);
- ObjectTypeDB::bind_method(_MD("is_network_server","is_network_server"),&SceneTree::is_network_server);
+ ObjectTypeDB::bind_method(_MD("is_network_server"),&SceneTree::is_network_server);
+ ObjectTypeDB::bind_method(_MD("get_network_unique_id"),&SceneTree::get_network_unique_id);
+ ObjectTypeDB::bind_method(_MD("set_refuse_new_network_connections","refuse"),&SceneTree::set_refuse_new_network_connections);
+ ObjectTypeDB::bind_method(_MD("is_refusing_new_network_connections"),&SceneTree::is_refusing_new_network_connections);
ObjectTypeDB::bind_method(_MD("_network_peer_connected"),&SceneTree::_network_peer_connected);
ObjectTypeDB::bind_method(_MD("_network_peer_disconnected"),&SceneTree::_network_peer_disconnected);
+ ObjectTypeDB::bind_method(_MD("_connected_to_server"),&SceneTree::_connected_to_server);
+ ObjectTypeDB::bind_method(_MD("_connection_failed"),&SceneTree::_connection_failed);
+ ObjectTypeDB::bind_method(_MD("_server_disconnected"),&SceneTree::_server_disconnected);
ADD_SIGNAL( MethodInfo("tree_changed") );
ADD_SIGNAL( MethodInfo("node_removed",PropertyInfo( Variant::OBJECT, "node") ) );
@@ -2055,8 +2239,11 @@ void SceneTree::_bind_methods() {
ADD_SIGNAL( MethodInfo("fixed_frame"));
ADD_SIGNAL( MethodInfo("files_dropped",PropertyInfo(Variant::STRING_ARRAY,"files"),PropertyInfo(Variant::INT,"screen")) );
- ADD_SIGNAL( MethodInfo("network_peer_connected",PropertyInfo(Variant::STRING,"id")));
- ADD_SIGNAL( MethodInfo("network_peer_disconnected",PropertyInfo(Variant::STRING,"id")));
+ ADD_SIGNAL( MethodInfo("network_peer_connected",PropertyInfo(Variant::INT,"id")));
+ ADD_SIGNAL( MethodInfo("network_peer_disconnected",PropertyInfo(Variant::INT,"id")));
+ ADD_SIGNAL( MethodInfo("connected_to_server"));
+ ADD_SIGNAL( MethodInfo("connection_failed"));
+ ADD_SIGNAL( MethodInfo("server_disconnected"));
BIND_CONSTANT( GROUP_CALL_DEFAULT );
BIND_CONSTANT( GROUP_CALL_REVERSE );
diff --git a/scene/main/scene_main_loop.h b/scene/main/scene_main_loop.h
index f67dae01be..1c0f88862c 100644
--- a/scene/main/scene_main_loop.h
+++ b/scene/main/scene_main_loop.h
@@ -188,13 +188,17 @@ private:
Ref<NetworkedMultiplayerPeer> network_peer;
- Set<StringName> connected_peers;
- void _network_peer_connected(const StringName& p_id);
- void _network_peer_disconnected(const StringName& p_id);
+ Set<int> connected_peers;
+ void _network_peer_connected(int p_id);
+ void _network_peer_disconnected(int p_id);
+
+ void _connected_to_server();
+ void _connection_failed();
+ void _server_disconnected();
//path sent caches
struct PathSentCache {
- Map<StringName,bool> confirmed_peers;
+ Map<int,bool> confirmed_peers;
int id;
};
@@ -211,9 +215,11 @@ private:
Map<int,NodeInfo> nodes;
};
- Map<StringName,PathGetCache> path_get_cache;
+ Map<int,PathGetCache> path_get_cache;
+
+ Vector<uint8_t> packet_cache;
- void _network_process_packet(const StringName &p_from, const Array& p_packet);
+ void _network_process_packet(int p_from, const uint8_t *p_packet, int p_packet_len);
void _network_poll();
static SceneTree *singleton;
@@ -221,7 +227,8 @@ friend class Node;
- void _remote_call(Node* p_from,bool p_reliable,bool p_set,const StringName& p_name,const Variant** p_arg,int p_argcount);
+
+ void _rpc(Node* p_from,int p_to,bool p_unreliable,bool p_set,const StringName& p_name,const Variant** p_arg,int p_argcount);
void tree_changed();
void node_removed(Node *p_node);
@@ -418,6 +425,10 @@ public:
void set_network_peer(const Ref<NetworkedMultiplayerPeer>& p_network_peer);
bool is_network_server() const;
+ int get_network_unique_id() const;
+
+ void set_refuse_new_network_connections(bool p_refuse);
+ bool is_refusing_new_network_connections() const;
SceneTree();
~SceneTree();
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index 2033599307..8c1233b634 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -627,6 +627,7 @@ void fill_default_theme(Ref<Theme>& t,const Ref<Font> & default_font,const Ref<F
// GraphNode
Ref<StyleBoxTexture> graphsb = make_stylebox(graph_node_png,6,24,6,5,16,24,16,5);
+ Ref<StyleBoxTexture> graphsbcomment = make_stylebox(graph_node_comment_png,6,24,6,5,16,24,16,5);
Ref<StyleBoxTexture> graphsbselected = make_stylebox(graph_node_selected_png,6,24,6,5,16,24,16,5);
Ref<StyleBoxTexture> graphsbdefault = make_stylebox(graph_node_default_png,4,4,4,4,6,4,4,4);
Ref<StyleBoxTexture> graphsbdeffocus = make_stylebox(graph_node_default_focus_png,4,4,4,4,6,4,4,4);
@@ -639,11 +640,13 @@ void fill_default_theme(Ref<Theme>& t,const Ref<Font> & default_font,const Ref<F
t->set_stylebox("selectedframe","GraphNode", graphsbselected );
t->set_stylebox("defaultframe", "GraphNode", graphsbdefault );
t->set_stylebox("defaultfocus", "GraphNode", graphsbdeffocus );
+ t->set_stylebox("comment", "GraphNode", graphsbcomment );
t->set_stylebox("breakpoint", "GraphNode", graph_bpoint );
t->set_stylebox("position", "GraphNode", graph_position );
t->set_constant("separation","GraphNode", 1 *scale);
t->set_icon("port","GraphNode", make_icon( graph_port_png ) );
t->set_icon("close","GraphNode", make_icon( graph_node_close_png ) );
+ t->set_icon("resizer","GraphNode", make_icon( window_resizer_png ) );
t->set_font("title_font","GraphNode", default_font );
t->set_color("title_color","GraphNode", Color(0,0,0,1));
t->set_constant("title_offset","GraphNode", 20 *scale);
@@ -930,6 +933,8 @@ void fill_default_theme(Ref<Theme>& t,const Ref<Font> & default_font,const Ref<F
t->set_stylebox("bg","GraphEdit", make_stylebox( tree_bg_png,4,4,4,5) );
t->set_color("grid_minor","GraphEdit", Color(1,1,1,0.05) );
t->set_color("grid_major","GraphEdit", Color(1,1,1,0.2) );
+ t->set_constant("bezier_len_pos","GraphEdit", 80*scale );
+ t->set_constant("bezier_len_neg","GraphEdit", 160*scale );
diff --git a/scene/resources/default_theme/graph_node.png b/scene/resources/default_theme/graph_node.png
index ed0b6a6cd2..d4b4dd3c1f 100644
--- a/scene/resources/default_theme/graph_node.png
+++ b/scene/resources/default_theme/graph_node.png
Binary files differ
diff --git a/scene/resources/default_theme/graph_node_comment.png b/scene/resources/default_theme/graph_node_comment.png
new file mode 100644
index 0000000000..f2d6daa259
--- /dev/null
+++ b/scene/resources/default_theme/graph_node_comment.png
Binary files differ
diff --git a/scene/resources/default_theme/graph_node_selected.png b/scene/resources/default_theme/graph_node_selected.png
index 33c4d06128..f76c9703dd 100644
--- a/scene/resources/default_theme/graph_node_selected.png
+++ b/scene/resources/default_theme/graph_node_selected.png
Binary files differ
diff --git a/scene/resources/default_theme/theme_data.h b/scene/resources/default_theme/theme_data.h
index d62ca07c38..ea68901196 100644
--- a/scene/resources/default_theme/theme_data.h
+++ b/scene/resources/default_theme/theme_data.h
@@ -100,7 +100,7 @@ static const unsigned char full_panel_bg_png[]={
static const unsigned char graph_node_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x40,0x8,0x6,0x0,0x0,0x0,0x13,0x7d,0xf7,0x96,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x7,0x1d,0x1,0x8,0x10,0x1e,0x6f,0x12,0x2b,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x2,0x6a,0x49,0x44,0x41,0x54,0x58,0xc3,0xed,0x97,0xbb,0x6e,0x13,0x51,0x10,0x86,0xbf,0xf1,0x2e,0xb1,0x83,0x85,0x63,0x5,0x10,0xe2,0x22,0xa5,0x0,0x1a,0x24,0x90,0x22,0x9e,0x81,0x2,0xd1,0x53,0xf1,0x2,0x20,0xa,0x1a,0xa,0xa0,0x44,0xd0,0xd0,0x20,0x81,0xe0,0x5,0xa8,0xe8,0x11,0x5,0xcf,0x80,0x22,0x81,0x42,0x3,0x14,0x91,0xb8,0x4,0x85,0x58,0x8e,0x21,0x78,0xd7,0xd9,0x73,0x86,0xe2,0x9c,0xdd,0xec,0xae,0xd7,0xce,0x85,0xe,0xed,0x34,0xbb,0x3a,0x3e,0xf3,0xcd,0xcc,0x3f,0x63,0x69,0x47,0xd8,0x36,0x1,0x1a,0x40,0xe0,0x9f,0x42,0xd1,0x14,0xb0,0x80,0xf1,0x4f,0x25,0x77,0xa9,0x1,0x1c,0x4,0xe6,0x81,0xa3,0x40,0x7,0x38,0x50,0x2,0x6c,0x1,0x3,0x60,0xd,0xe8,0x1,0x7f,0x0,0x9b,0x46,0x6d,0x3,0x67,0xe6,0xe,0x75,0xaf,0xb7,0x9a,0xad,0xcb,0x33,0x33,0xcd,0x53,0x54,0xd8,0x68,0x14,0x7f,0x89,0xe2,0xe8,0xf5,0xc6,0xaf,0xfe,0x73,0xe0,0x13,0xb0,0x29,0x3e,0xd2,0xc2,0x7c,0xf7,0xf0,0xe3,0xd3,0xb,0x67,0xaf,0x3c,0xb8,0xfb,0x88,0xd9,0x4e,0xab,0xca,0x9f,0xe1,0x20,0xe2,0xde,0xc3,0xdb,0x7c,0x5e,0xf9,0xf8,0xaa,0xd7,0x5f,0xbf,0x5,0xac,0x8,0xd0,0x2,0x16,0x8f,0x1f,0x3b,0xf9,0xe6,0xc5,0xb3,0x97,0xed,0x24,0xb1,0x24,0xa3,0xa4,0x12,0x10,0xce,0x84,0x84,0x61,0x83,0x6b,0x37,0xae,0x6e,0x7e,0xff,0xf1,0xf5,0x12,0xb0,0x14,0x7a,0x1d,0xda,0x61,0x10,0xb6,0x87,0xbf,0x63,0x10,0x75,0x47,0xa,0x2a,0x79,0x85,0x95,0x51,0xbc,0xc5,0x28,0x86,0x30,0x8,0xdb,0xbe,0x6c,0x49,0x1,0x1,0x80,0x51,0xeb,0xfc,0x9d,0xc0,0x4e,0x6b,0xf,0xd1,0xfc,0xb9,0xb3,0x20,0x5,0x68,0xfa,0x8b,0x5a,0x8b,0xaa,0x80,0x28,0x82,0xa0,0x28,0xa2,0x92,0x73,0xd3,0xb1,0xde,0x86,0x85,0x46,0x5b,0x45,0x51,0x50,0x45,0xc4,0x95,0x61,0x53,0x27,0x71,0x61,0x74,0x1a,0xc0,0xaa,0xcd,0x6e,0xa8,0x64,0x2f,0xee,0x5d,0x29,0x8a,0x32,0x39,0x3,0x5f,0xb6,0x2f,0x4c,0x45,0x73,0x5a,0xd8,0x31,0x48,0x1,0x60,0xac,0x2d,0xf1,0x5,0x51,0x75,0x45,0x68,0x5a,0xbf,0x4e,0xcf,0x60,0xfb,0x82,0x2b,0x5a,0x73,0x4e,0xb6,0xe2,0xf,0x52,0x2,0xd8,0x82,0xe2,0x14,0x50,0x54,0xc4,0x2f,0x8b,0x68,0xad,0x1f,0x99,0x54,0x79,0x41,0xdd,0x0,0xf8,0xb6,0x82,0x88,0x4e,0xeb,0x82,0x66,0x89,0xaa,0x3b,0xc8,0x52,0x48,0x41,0x56,0x76,0xcc,0x60,0x7b,0x74,0x75,0xac,0x1a,0x49,0x47,0x72,0x72,0x6,0xe2,0xe7,0x56,0x45,0xfd,0x5d,0xc9,0x44,0x28,0x40,0x2b,0x45,0x34,0xea,0x7,0xa8,0x14,0xc9,0x92,0x75,0x64,0x7,0x11,0x8d,0x8f,0x98,0x9b,0x87,0xf2,0xf4,0x4d,0xd5,0x40,0xd5,0xc9,0x97,0xf,0xa3,0x5a,0x74,0x9c,0x36,0x89,0xf7,0x9f,0xdc,0x61,0xaf,0x96,0x1,0x92,0x2d,0xc3,0xe2,0xf9,0x8b,0xbb,0x72,0x5a,0x7a,0xff,0xb6,0x3a,0x83,0x8d,0x41,0x7f,0xcf,0x19,0x34,0xf8,0x47,0xab,0x1,0x35,0xa0,0x6,0xd4,0x80,0x1a,0x50,0x3,0x6a,0xc0,0x7f,0x9,0x90,0x8a,0x4f,0xe0,0x3d,0x67,0x60,0xf7,0xe1,0x6b,0x53,0x80,0x5,0x22,0x63,0x4c,0x6c,0x93,0x5d,0x78,0x25,0x60,0x8c,0x89,0x81,0x8,0xb0,0xd,0xbf,0xca,0xae,0x47,0xf1,0x70,0x79,0xad,0xb7,0xca,0x34,0x88,0x4d,0x60,0xad,0xb7,0x4a,0x14,0xf,0x97,0x81,0x75,0xc0,0xa4,0x9b,0xeb,0x1c,0x70,0xa1,0xd3,0xee,0x3e,0x6d,0x35,0x67,0xcf,0x5,0x41,0x50,0x29,0xae,0x31,0xc6,0x46,0xf1,0xf0,0xc3,0x60,0xb3,0x7f,0x13,0x78,0x7,0x6c,0x48,0x6e,0x85,0xeb,0x0,0x27,0x80,0x23,0x40,0x73,0xc2,0xf2,0x1d,0x3,0x3f,0x81,0x6f,0x7e,0x8f,0x36,0x52,0x12,0x34,0x4c,0xf7,0xc1,0x9,0x55,0xa8,0x2f,0x39,0xd9,0xa7,0xf0,0xe3,0xf6,0x17,0x4c,0x97,0x1d,0x24,0x5b,0x8,0x8b,0x95,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x40,0x8,0x6,0x0,0x0,0x0,0x13,0x7d,0xf7,0x96,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x8,0x17,0xd,0x5,0x12,0xa1,0x38,0x83,0x9b,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x2,0x74,0x49,0x44,0x41,0x54,0x58,0xc3,0xed,0x97,0x3d,0x6f,0xd3,0x60,0x10,0xc7,0x7f,0x17,0x9b,0x26,0x25,0x22,0xad,0xa,0x8,0xf1,0x52,0x75,0x0,0x16,0x24,0x90,0x2a,0x96,0x7c,0x1,0x6,0xc4,0xce,0xc4,0x17,0x0,0x31,0xb0,0x30,0x0,0x23,0x82,0x85,0x5,0x9,0x4,0x5f,0x80,0x89,0x1d,0x31,0xf0,0x5,0x58,0x50,0x25,0x50,0x59,0x80,0xa1,0xe2,0xad,0x28,0x34,0x4a,0x3,0x25,0x76,0xea,0xe7,0x39,0x6,0x3f,0x76,0x6d,0xc7,0x49,0x5f,0xd8,0x90,0x6f,0xb1,0xf5,0xe4,0xb9,0xdf,0xdd,0xfd,0xef,0x22,0xf9,0x84,0x2d,0x13,0xa0,0x6,0x78,0xee,0x29,0xe4,0x4d,0x1,0xb,0x18,0xf7,0x54,0x32,0x97,0x6a,0xc0,0x7e,0x60,0xe,0x38,0xc,0xb4,0x80,0x7d,0x5,0xc0,0x26,0xd0,0x7,0x3a,0x40,0x17,0xf8,0x3,0xd8,0x24,0x6a,0x13,0x38,0x35,0x73,0x60,0xf6,0x6a,0xa3,0xde,0xb8,0x38,0x35,0x55,0x3f,0x41,0x89,0xd,0x87,0xe1,0x97,0x20,0xc,0x5e,0xae,0xff,0xea,0x3d,0x5,0x3e,0x2,0x1b,0xe2,0x22,0x2d,0xcc,0xcd,0x1e,0x7c,0x78,0x72,0xe1,0xf4,0xa5,0x7b,0xb7,0x1f,0x7c,0x9e,0x6e,0x35,0xca,0xfc,0x19,0xf4,0x3,0xee,0xdc,0xbf,0x39,0xff,0x69,0xe5,0xc3,0x8b,0x6e,0x6f,0xed,0x6,0xb0,0x22,0x40,0x3,0x58,0x3c,0x7a,0xe4,0xf8,0xab,0x67,0x4f,0x9e,0x77,0xa3,0xc8,0x12,0xd,0xa3,0x52,0x80,0x3f,0xe5,0xe3,0xfb,0x35,0xae,0x5c,0xbb,0x3c,0xf7,0xfd,0xc7,0xd7,0xb,0xc0,0x92,0xef,0x74,0x68,0xfa,0x9e,0xdf,0x1c,0xfc,0xe,0xbb,0x88,0xc6,0x47,0xa,0x2a,0x59,0x85,0x95,0x61,0xb8,0xc9,0x30,0x4,0xdf,0xf3,0x9b,0xae,0x6c,0x49,0x0,0x1e,0x80,0x51,0x1b,0xfb,0xc7,0x2,0xc7,0x5a,0x3b,0x88,0x66,0xcf,0x63,0xf3,0x12,0x80,0x26,0xbf,0xa8,0xb5,0xa8,0xa,0x88,0x22,0x8,0x8a,0x22,0x2a,0x19,0x37,0x1d,0xe9,0xad,0x9f,0x6b,0xb4,0x55,0x14,0x5,0x55,0x44,0xe2,0x32,0x6c,0xe2,0x24,0x71,0x18,0x9d,0x4,0xb0,0x6a,0xd3,0x1b,0x2a,0xe9,0x4b,0xfc,0xae,0xe4,0x45,0x19,0x9f,0x81,0x2b,0xdb,0x15,0xa6,0xa2,0x19,0x2d,0xec,0x8,0x24,0x7,0x30,0xd6,0x16,0xf8,0x82,0xa8,0xc6,0x45,0x68,0x52,0xbf,0x4e,0xce,0x60,0xeb,0x42,0x5c,0xb4,0x66,0x9c,0x6c,0xc9,0x1f,0xa4,0x0,0xb0,0x39,0xc5,0xc9,0xa1,0x28,0x89,0x5f,0x14,0xd1,0x5a,0x37,0x32,0x89,0xf2,0x82,0xc6,0x3,0xe0,0xda,0xa,0x22,0x3a,0xa9,0xb,0x9a,0x26,0xaa,0xf1,0x41,0x9a,0x42,0x2,0xb2,0xb2,0x6d,0x6,0x5b,0xa3,0xab,0x23,0xd5,0x48,0x32,0x92,0xe3,0x33,0x10,0x37,0xb7,0x2a,0xea,0xee,0x4a,0x2a,0x42,0xe,0x5a,0x2a,0xa2,0x51,0x37,0x40,0x85,0x48,0x96,0xb4,0x23,0xdb,0x88,0x68,0x5c,0xc4,0xcc,0x3c,0x14,0xa7,0x6f,0xa2,0x6,0xaa,0xb1,0x7c,0xd9,0x30,0xaa,0x79,0xc7,0x49,0x93,0x78,0xf7,0xd1,0xad,0x79,0x76,0x69,0x29,0x20,0xda,0x34,0x2c,0x9e,0x3d,0xff,0x7a,0x27,0x4e,0x4b,0xef,0xde,0xb4,0x4b,0x33,0x58,0xef,0xf7,0x76,0x9b,0x0,0x35,0xfe,0xd1,0x2a,0x40,0x5,0xa8,0x0,0x15,0xa0,0x2,0x54,0x80,0xa,0xf0,0x5f,0x2,0xa4,0xe4,0x13,0x78,0xd7,0x19,0xd8,0x3d,0xf8,0xda,0x4,0x60,0x81,0xc0,0x18,0x13,0xda,0x68,0x7,0x5e,0x11,0x18,0x63,0x42,0x20,0x0,0x6c,0xcd,0xad,0xb2,0x6b,0x41,0x38,0x58,0xee,0x74,0x57,0xdb,0x93,0x20,0x36,0x82,0x4e,0x77,0xb5,0x1d,0x84,0x83,0x65,0x60,0xd,0x30,0xc9,0xe6,0x3a,0x3,0x9c,0x6b,0x35,0x67,0x1f,0x37,0xea,0xd3,0x67,0x3c,0xcf,0x2b,0x15,0xd7,0x18,0x63,0x83,0x70,0xf0,0xbe,0xbf,0xd1,0xbb,0xe,0xbc,0x5,0xd6,0x25,0xb3,0xc2,0xb5,0x80,0x63,0xc0,0x21,0xa0,0x3e,0x66,0xf9,0xe,0x81,0x9f,0xc0,0x37,0xb7,0x47,0x1b,0x29,0x8,0xea,0x27,0xfb,0xe0,0x98,0x2a,0xd4,0x95,0x1c,0xed,0x51,0xf8,0x51,0xfb,0xb,0x1,0xbe,0x20,0x9f,0x90,0x81,0x17,0xaa,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
@@ -114,6 +114,11 @@ static const unsigned char graph_node_close_png[]={
};
+static const unsigned char graph_node_comment_png[]={
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x40,0x8,0x6,0x0,0x0,0x0,0x13,0x7d,0xf7,0x96,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x8,0x19,0x11,0x2a,0x1d,0xd6,0x78,0x8b,0x40,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x1,0x74,0x49,0x44,0x41,0x54,0x58,0xc3,0xed,0x97,0xbf,0x4e,0xc2,0x50,0x14,0xc6,0x7f,0x6d,0x91,0x56,0x1b,0x90,0x80,0x2c,0x44,0xc2,0xa0,0x2e,0xe,0x3e,0x3,0x89,0x93,0xf1,0x1d,0x4c,0x18,0x4d,0x1c,0x7c,0xb,0x57,0x7,0x13,0x47,0x13,0x77,0x46,0xe3,0xc4,0x4b,0x98,0x60,0x4c,0xd4,0x81,0x60,0x58,0x94,0xff,0x22,0x2d,0xd0,0xd6,0xe5,0xde,0x88,0x8,0x2,0x35,0x6e,0xf7,0x5b,0x6e,0x9a,0x9c,0xef,0x77,0xee,0x39,0x37,0x1d,0x3e,0x8d,0x2f,0x69,0x80,0xe,0x18,0xe2,0xd4,0xf8,0xae,0x0,0xf0,0x1,0x4f,0x9c,0x1,0x63,0x45,0x3a,0xb0,0x6,0x24,0x81,0x34,0x10,0x7,0x56,0x26,0x0,0x43,0xa0,0x3,0xbc,0x2,0xd,0xe0,0x3,0xf0,0x65,0x57,0x1b,0xd8,0x5e,0x8f,0x25,0x8e,0x2d,0xd3,0x3a,0x88,0x46,0xcd,0x4d,0xa6,0x68,0x30,0x70,0x5f,0x1c,0xd7,0xb9,0x6d,0x77,0x5b,0x97,0xc0,0x13,0xd0,0xd3,0x44,0xa7,0x5c,0x32,0x91,0x3a,0xdf,0xca,0xed,0x1c,0x16,0x52,0xdd,0x2a,0xbf,0xe8,0xaa,0x1e,0xcb,0x3e,0x57,0x1e,0x6f,0x1a,0xad,0xfa,0x29,0x50,0x91,0x33,0xa7,0x4d,0xd3,0xca,0xcf,0x33,0x3,0x14,0x52,0xdd,0xaa,0x69,0x5a,0x79,0x31,0xaa,0x21,0x97,0x65,0x47,0x8c,0x88,0xcd,0x82,0x12,0xb5,0x36,0xa0,0x49,0x80,0xc1,0xf2,0x32,0x24,0x20,0x90,0x4f,0x12,0x46,0x3a,0x7f,0x94,0x2,0x28,0x80,0x2,0x88,0x5f,0x7b,0xfc,0xe3,0xec,0xe1,0x3d,0x1b,0x1a,0x30,0x1a,0x7a,0x1c,0x65,0xd8,0x5f,0xc4,0x74,0x5d,0xa3,0xa4,0x5e,0x41,0x1,0x14,0x40,0x1,0x14,0x40,0x1,0x14,0x40,0x1,0xfe,0x15,0xa0,0x4d,0xc9,0x88,0x4b,0xdf,0xc0,0xf,0xe1,0xf5,0x25,0xc0,0x7,0x1c,0xcf,0xf3,0xdc,0x45,0x9d,0xa2,0xd6,0x1,0x7c,0x5d,0x44,0xd9,0xba,0xe3,0xf6,0xcb,0xc5,0xa6,0x5d,0x9a,0x67,0x2e,0x36,0xed,0x92,0xe3,0xf6,0xcb,0x40,0x1d,0xf0,0x64,0x72,0x5d,0x7,0xf6,0xe2,0x76,0xe2,0xc2,0x32,0x57,0x77,0xd,0xc3,0xd0,0x67,0x74,0xf6,0x1d,0xb7,0x7f,0xdf,0xe9,0xb5,0x4e,0x80,0x3b,0xa0,0xad,0x8d,0x45,0xb8,0x38,0x90,0x1,0x36,0x0,0x73,0x46,0xf8,0x76,0x81,0x37,0xa0,0x26,0x72,0xb4,0xa7,0x4d,0x2c,0x34,0x22,0xf3,0xe0,0x8c,0x9,0x2,0x31,0xf2,0x28,0xe4,0xe2,0x7f,0xea,0x13,0x64,0x47,0x6c,0x83,0x36,0x6d,0xd2,0x40,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+};
+
+
static const unsigned char graph_node_default_png[]={
0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x3,0x0,0x0,0x0,0x28,0x2d,0xf,0x53,0x0,0x0,0x0,0x4,0x67,0x41,0x4d,0x41,0x0,0x0,0xb1,0x8f,0xb,0xfc,0x61,0x5,0x0,0x0,0x0,0x20,0x63,0x48,0x52,0x4d,0x0,0x0,0x7a,0x26,0x0,0x0,0x80,0x84,0x0,0x0,0xfa,0x0,0x0,0x0,0x80,0xe8,0x0,0x0,0x75,0x30,0x0,0x0,0xea,0x60,0x0,0x0,0x3a,0x98,0x0,0x0,0x17,0x70,0x9c,0xba,0x51,0x3c,0x0,0x0,0x0,0x39,0x50,0x4c,0x54,0x45,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x16,0x12,0x19,0xe,0xb,0x10,0xe,0xb,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x16,0x12,0x19,0x0,0x0,0x0,0x19,0x15,0x1c,0x24,0x1e,0x27,0x16,0x12,0x19,0xff,0xff,0xff,0x2b,0x4d,0xfd,0x66,0x0,0x0,0x0,0xf,0x74,0x52,0x4e,0x53,0x0,0x46,0x47,0x3f,0x2b,0x11,0x3,0xfd,0xd3,0xcd,0x2a,0x73,0x45,0xf8,0x3d,0x3f,0x57,0xda,0x84,0x0,0x0,0x0,0x1,0x62,0x4b,0x47,0x44,0x12,0x7b,0xbc,0x6c,0x0,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x6,0x16,0x12,0x2b,0x4,0x4e,0x1d,0x2,0xaf,0x0,0x0,0x0,0x38,0x49,0x44,0x41,0x54,0x18,0xd3,0x63,0x60,0x64,0x2,0x2,0x46,0x8,0xc9,0xcc,0xc2,0xca,0xc6,0xc0,0x8f,0x4,0xd8,0x39,0x98,0x59,0x19,0x50,0x80,0x0,0x27,0x17,0xaa,0x0,0x83,0x20,0x37,0x9a,0x0,0x3f,0xd3,0xc0,0x8,0xf0,0xa0,0x9,0xf0,0xf2,0x61,0x3a,0x1d,0xc3,0x73,0xe8,0xde,0x7,0x0,0x89,0x4d,0x2,0xf2,0x16,0xd3,0x74,0x45,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x63,0x72,0x65,0x61,0x74,0x65,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x39,0x3a,0x32,0x36,0x2b,0x30,0x32,0x3a,0x30,0x30,0xc9,0xad,0xc8,0x52,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x6d,0x6f,0x64,0x69,0x66,0x79,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x39,0x3a,0x32,0x36,0x2b,0x30,0x32,0x3a,0x30,0x30,0xb8,0xf0,0x70,0xee,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
@@ -130,7 +135,7 @@ static const unsigned char graph_node_position_png[]={
static const unsigned char graph_node_selected_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x40,0x8,0x6,0x0,0x0,0x0,0x13,0x7d,0xf7,0x96,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x8,0x6,0xc,0x29,0x12,0x71,0x6e,0xb2,0xf8,0x0,0x0,0x3,0x37,0x49,0x44,0x41,0x54,0x58,0xc3,0xed,0x97,0x4f,0x88,0xdc,0x74,0x14,0xc7,0xbf,0xef,0x97,0x7f,0x9b,0xcc,0xee,0xec,0x64,0x64,0x76,0x5,0xd1,0xd5,0xc2,0x6e,0x41,0x8f,0xbd,0xef,0x49,0x7a,0x10,0xa,0xeb,0x61,0xa1,0xb5,0x16,0xc4,0xa3,0x87,0xbd,0xb9,0x17,0x8f,0x5e,0xa4,0xc7,0x16,0xbc,0x8,0xa2,0xdb,0x16,0xf,0x7b,0xb0,0x50,0x28,0x54,0x7a,0xea,0xdd,0xa3,0x82,0x16,0x14,0x5,0xc1,0xd9,0xe9,0x4e,0x32,0x3b,0xc9,0x64,0x26,0xbf,0xe4,0xf7,0x3c,0x24,0xd9,0x26,0x99,0x35,0x73,0xf0,0x26,0xf3,0x60,0x66,0x12,0xe6,0xbd,0xcf,0xf7,0xbd,0xef,0xef,0x17,0xc8,0x8f,0x98,0x99,0x0,0x88,0x47,0x8f,0x7e,0xb4,0x92,0xa1,0x67,0xf,0xcf,0x6,0x96,0x62,0x25,0xa4,0x8c,0x9,0xa5,0x30,0xc,0x93,0x5,0x9,0xd5,0x6d,0xf7,0x66,0x7a,0xd7,0x8d,0xae,0x5d,0xbb,0x32,0x3,0xa0,0x88,0x99,0xb5,0x87,0xdf,0x3c,0x5c,0x1b,0x85,0x93,0xd7,0x86,0xbe,0x7f,0x69,0x34,0xf2,0x36,0x83,0x30,0x70,0xe2,0x38,0xd6,0xcb,0x0,0xd3,0x34,0x93,0xd5,0xd6,0xea,0x64,0x7d,0xdd,0xed,0x77,0x3b,0x9d,0xdf,0xd6,0x5b,0xce,0x5f,0x7b,0x1f,0xed,0x8d,0xe9,0xe8,0xe8,0x49,0x2b,0x1e,0xf6,0xdf,0xf2,0x46,0xc3,0xdd,0xf7,0x6f,0xec,0xde,0x31,0x2d,0x5d,0x43,0x43,0xc4,0xb3,0x24,0xfd,0xfe,0xbb,0x67,0x7,0xee,0x7a,0xf7,0x99,0xd9,0xdd,0xfc,0x5d,0x48,0xcf,0x77,0xfa,0x2f,0x4e,0x76,0xf6,0xae,0xef,0xde,0x65,0x66,0x6d,0x7a,0xda,0x46,0x12,0xb8,0x48,0xc3,0x6e,0xe5,0x93,0x4,0x2e,0xa6,0xa7,0x6d,0x30,0xb3,0xb6,0x77,0x7d,0xf7,0x6e,0xff,0xc5,0xc9,0x8e,0xf4,0x7c,0x47,0x8f,0x93,0xc8,0xc,0x83,0xf1,0x86,0xb5,0xa2,0x8b,0x99,0xb7,0x6,0x12,0x84,0x44,0x2a,0x50,0x4d,0x99,0x1,0x90,0x20,0x20,0xea,0xc2,0x72,0xc7,0x22,0xc,0xc6,0x1b,0xb1,0x1b,0x99,0x42,0xb1,0x12,0x93,0x68,0x62,0x3,0x40,0x2a,0x19,0xcc,0x79,0xb1,0xaa,0x56,0x13,0x18,0xcc,0x8c,0x34,0x61,0x0,0xc0,0x24,0x9a,0xd8,0x8a,0x95,0x10,0x52,0x4a,0x4a,0x91,0x12,0x0,0x30,0x65,0xba,0xcc,0xc,0x88,0x5c,0x16,0x0,0x8,0x60,0x5,0x80,0x19,0xe0,0x2c,0x27,0x45,0x4a,0x52,0x4a,0xd2,0xd,0xc3,0x60,0xa4,0x79,0xa2,0x62,0x30,0x8,0x20,0xc6,0xf9,0xc,0x39,0x84,0x99,0x2b,0xbf,0x45,0x4d,0x65,0xa9,0x98,0x19,0x20,0x2,0xc0,0x28,0xf2,0xea,0xc1,0xb5,0x3f,0xf4,0xda,0xbf,0x60,0x95,0x27,0x10,0x97,0xdc,0x2b,0x75,0xd3,0x4,0xe0,0x4c,0xbb,0x7c,0x93,0x15,0xab,0x97,0x90,0x7a,0x67,0x15,0x80,0x52,0xa5,0xd9,0x73,0xf7,0x88,0x73,0x5f,0x98,0x41,0x8b,0x47,0x28,0x4b,0x50,0xa9,0x9f,0xec,0x5b,0x2d,0xea,0x0,0xac,0xc0,0xaa,0x66,0xff,0xbc,0x8b,0xd,0x1e,0xe4,0x73,0xe7,0x4d,0x23,0xdf,0x3e,0xc5,0x30,0xd9,0x55,0x53,0x7,0x19,0x40,0xe5,0x85,0x25,0x35,0x7a,0x39,0xbb,0x6a,0x6,0xa8,0xac,0xbe,0xa2,0x5d,0x56,0xa5,0xc5,0xcb,0x48,0xc5,0x7e,0xa0,0x62,0x33,0x51,0xe1,0x67,0xfe,0x3c,0x34,0x75,0xa0,0xb2,0xc2,0x39,0x25,0x85,0xf3,0x15,0xa9,0x5b,0x3b,0xbf,0x95,0xb9,0xfe,0x28,0x36,0xc7,0xbc,0x89,0x75,0x8d,0x92,0x91,0xb5,0x8b,0x79,0xc0,0x67,0x9f,0x7f,0x8a,0x9f,0x7f,0xfd,0xa9,0x51,0xf1,0xed,0x9d,0x77,0xf0,0xd5,0xb7,0x5f,0x5c,0xc,0xb8,0xb4,0xb5,0xd,0x4d,0x18,0x8d,0x80,0xad,0xd7,0xdf,0xfc,0xf7,0xe,0xc2,0x30,0xc0,0xe8,0xcc,0x6f,0x4,0x84,0x61,0x50,0xb9,0x17,0xf8,0x8f,0xb1,0x4,0x2c,0x1,0x4b,0xc0,0x12,0xb0,0x4,0x2c,0x1,0x4b,0xc0,0xff,0xf,0x20,0xa5,0x24,0x68,0x17,0xbe,0xfe,0x5c,0x1c,0x45,0x8e,0x56,0xea,0x40,0x83,0xc6,0x0,0x60,0xe8,0xfa,0xc2,0xfa,0x22,0xa7,0xa8,0x11,0x96,0x69,0xa5,0x96,0x69,0xc6,0x0,0xe0,0xd8,0xab,0xb,0x1,0x45,0x8e,0x65,0x9a,0xb1,0x65,0x5a,0xa9,0x6e,0xea,0x76,0xbc,0x62,0x3b,0x83,0xd9,0x54,0xf2,0xc1,0xe1,0x7,0x74,0xe7,0x36,0x61,0x12,0x8d,0x21,0x93,0xa4,0x72,0xe8,0x32,0x74,0x1d,0x8e,0xbd,0x86,0x83,0xc3,0x1b,0x98,0x4d,0x25,0xaf,0xd8,0xce,0xc0,0xd4,0xed,0x98,0x8e,0x8e,0x9e,0xb4,0x4e,0xff,0x7c,0xbe,0xed,0x9f,0x79,0xef,0x7e,0xf8,0xf1,0x7b,0xb7,0x2d,0xdb,0x68,0x74,0x62,0x16,0x49,0xbe,0xff,0xf5,0xe3,0xc3,0x4e,0xdb,0x7d,0xfa,0xca,0x1b,0xdb,0xcf,0x89,0x99,0xb5,0x7,0x5f,0x3e,0x68,0xf,0x3c,0x7f,0xcb,0xf3,0xfd,0xcb,0x93,0x28,0xdc,0x90,0x52,0x1a,0x4a,0x55,0xdf,0x56,0x85,0x10,0x30,0xc,0x43,0x3a,0x76,0xeb,0xc4,0xed,0x74,0x7e,0xe9,0xb9,0x9d,0x3f,0x6e,0x7e,0x72,0xf3,0x8c,0x8a,0xd3,0xfb,0xbd,0x7b,0x3f,0xac,0x4,0x7f,0xf7,0x5b,0x52,0xcd,0x4c,0x66,0x75,0xe1,0xf2,0x12,0x9,0x65,0x8,0x2b,0x5e,0x7d,0x75,0x33,0xbc,0x75,0xeb,0xea,0x14,0xc0,0xf9,0xf1,0x4,0xcc,0x4c,0xc7,0xc7,0xc7,0xa2,0xd7,0xeb,0x35,0x8e,0x30,0x18,0xc,0x78,0x7f,0x7f,0x5f,0x11,0x65,0xc7,0xba,0x7f,0x0,0xff,0xc4,0xaa,0x19,0xfd,0xaf,0x1e,0xb7,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x40,0x8,0x6,0x0,0x0,0x0,0x13,0x7d,0xf7,0x96,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x8,0x17,0xd,0x4,0x3b,0xfa,0x91,0x2a,0xb6,0x0,0x0,0x3,0x44,0x49,0x44,0x41,0x54,0x58,0xc3,0xed,0x97,0x3f,0x68,0xdc,0x76,0x14,0xc7,0xbf,0xef,0xa7,0x9f,0x7e,0x3a,0xdd,0x39,0xf6,0xdd,0x95,0xb3,0x3,0xc1,0x75,0x1b,0x70,0xa,0xe9,0x98,0x25,0x93,0x87,0x52,0x3a,0x4,0x2,0xce,0xe0,0xd2,0x34,0x35,0x94,0x8e,0x1d,0xbc,0xd5,0x4b,0xc7,0x2e,0x25,0x63,0x2,0x5d,0xa,0xa5,0xb1,0x1b,0x2,0xf5,0xd0,0x40,0xa0,0x90,0x10,0x3a,0x64,0xca,0x92,0x31,0x81,0x24,0xd0,0xd2,0x9a,0x40,0x2f,0x17,0xdf,0x1f,0xfb,0x74,0xf2,0xe9,0x27,0xfd,0x5e,0x7,0x49,0xb6,0x4e,0xe7,0xea,0x86,0x6e,0xe5,0x1e,0xdc,0x49,0x42,0xef,0x7d,0xde,0xf7,0x7d,0xf5,0x13,0xe8,0x47,0xcc,0x4c,0x0,0xc4,0xbd,0x7b,0x4f,0x9c,0xb0,0xdd,0x71,0xdb,0xfb,0x2d,0xc7,0xb0,0x11,0x5a,0x7,0x84,0x4c,0xd8,0xb6,0x62,0x41,0xc2,0xd4,0x67,0x1b,0x43,0x59,0xaf,0xf9,0x97,0x2f,0x5f,0x18,0x2,0x30,0xc4,0xcc,0xd6,0xdd,0x1f,0xef,0x9e,0xea,0x79,0x83,0x33,0xed,0x6e,0xf7,0x6c,0xaf,0xd7,0x59,0xe8,0x7b,0xfd,0x72,0x10,0x4,0x32,0xb,0x50,0x4a,0x85,0x33,0x95,0x99,0xc1,0xdc,0x5c,0xad,0x59,0xaf,0x56,0x7f,0x9f,0xab,0x94,0x5f,0xad,0x7e,0xbe,0x7a,0x40,0x5b,0x5b,0xf7,0x2b,0x41,0xbb,0xf9,0x6e,0xa7,0xd7,0x5e,0xb9,0x72,0x75,0xe5,0x86,0x72,0xa4,0x85,0x82,0x8,0x86,0x61,0xf4,0xcb,0x9d,0x47,0x1b,0xb5,0xb9,0xfa,0x23,0x55,0x5f,0xf8,0x43,0xea,0x4e,0xb7,0xdc,0x7c,0xf3,0xfa,0xdc,0xc7,0xeb,0x1f,0xdc,0x64,0x66,0x71,0xb8,0x37,0xbb,0x2b,0x1d,0xb,0x44,0x23,0x13,0x80,0x99,0x11,0xe,0x23,0x50,0x65,0x6f,0x71,0xf5,0x93,0x95,0x9b,0x3f,0x6f,0xff,0xb6,0x76,0x9a,0x9c,0xa6,0x8,0x42,0x5f,0x79,0xfd,0x83,0x79,0xa7,0x24,0x5,0xfc,0xfa,0x2e,0x9,0x42,0xa8,0xd,0xc2,0x20,0x1a,0xfd,0x69,0x3,0x12,0x4,0xf8,0xf5,0x5d,0xa7,0x24,0x85,0xd7,0x3f,0x98,0xf,0x42,0x5f,0x9,0xc3,0x46,0xc,0xfc,0x81,0xb,0x0,0x91,0x66,0x30,0x1b,0x10,0x0,0x98,0x6c,0x7b,0x80,0xc0,0x60,0x66,0x44,0x21,0x3,0x0,0x6,0xfe,0xc0,0x35,0x6c,0x84,0xd0,0x5a,0x53,0x84,0x88,0x0,0x80,0x13,0xd9,0xcc,0xc,0x88,0xb8,0x10,0x0,0x40,0x0,0x1b,0x0,0xcc,0x0,0xc7,0x39,0x11,0x22,0xd2,0x5a,0x93,0xb4,0x6d,0x9b,0x11,0x25,0x89,0x86,0xc1,0x20,0x80,0x18,0xa0,0xe3,0xee,0x47,0xd0,0xcc,0x31,0xad,0x91,0x79,0xa3,0x40,0x4,0x80,0x91,0xe6,0xe5,0x83,0x73,0x37,0x64,0xee,0x2e,0xd8,0x24,0x9,0xc4,0xc7,0xa,0xb2,0x6a,0x8a,0x0,0x1c,0xf7,0xce,0x5e,0xc4,0xc5,0xe6,0x18,0x92,0x57,0x36,0x2,0x30,0x26,0x33,0x7b,0xe2,0x1e,0x71,0xe2,0xb,0x33,0x68,0xf2,0x8,0xd9,0x16,0x94,0xd1,0x13,0xff,0x9b,0x49,0xa,0xc0,0x6,0x6c,0x72,0xf6,0x8f,0xbb,0x58,0xe0,0x41,0x32,0x77,0x22,0x1a,0xc9,0xf2,0x49,0x87,0x89,0xcf,0x8a,0x14,0xc4,0x0,0x93,0x14,0x66,0xba,0xd1,0xf1,0xec,0xa6,0x18,0x60,0xe2,0xfa,0x91,0xde,0xd9,0xae,0x34,0xf9,0x31,0x52,0xba,0x1e,0x28,0x5d,0x4c,0x94,0xfa,0x99,0xbc,0xf,0x45,0xa,0x4c,0x5c,0x38,0xd6,0xc9,0xe0,0xe8,0x89,0xe4,0xad,0x1d,0x5f,0xca,0x9c,0x7f,0x15,0x8b,0x63,0xdc,0xc4,0x7c,0x8f,0x8c,0x91,0xb9,0x93,0x71,0xc0,0xd7,0xdf,0x7c,0xf5,0xea,0xd9,0x8b,0xa7,0x85,0x1d,0xcf,0x9f,0x7b,0x1f,0xdf,0xdf,0xfa,0x76,0xf1,0x44,0xc0,0xd9,0xa5,0x65,0x58,0xc2,0x2e,0x4,0x2c,0x2d,0xbe,0xf3,0xef,0xa,0x3c,0xaf,0x8f,0xde,0x7e,0xb7,0x10,0xe0,0x79,0xfd,0x91,0x6b,0x81,0xff,0x18,0x53,0xc0,0x14,0x30,0x5,0x4c,0x1,0x53,0xc0,0x14,0x30,0x5,0xfc,0xff,0x0,0x5a,0x6b,0x82,0x75,0xe2,0xe7,0xcf,0xc9,0x91,0xe6,0x58,0x19,0x5,0x16,0x2c,0x6,0x0,0x5b,0xca,0x89,0xf5,0x69,0x4e,0x5a,0x23,0x1c,0xe5,0x44,0x8e,0x52,0x1,0x0,0x94,0xdd,0x99,0x89,0x80,0x34,0xc7,0x51,0x2a,0x70,0x94,0x13,0x49,0x25,0xdd,0xa0,0xe4,0x96,0x5b,0xc3,0x43,0xcd,0x1b,0x9b,0x9f,0x5e,0xbc,0x71,0x9d,0x1e,0xf,0xfc,0x3,0xe8,0x30,0x1c,0xd9,0x74,0xd9,0x52,0xa2,0xec,0x9e,0xc2,0xc6,0xe6,0xd5,0x8b,0xc3,0x43,0xcd,0x25,0xb7,0xdc,0x52,0xd2,0xd,0x68,0x6b,0xeb,0x7e,0x65,0xef,0xaf,0x97,0xcb,0xdd,0xfd,0xce,0x87,0x9f,0x7d,0x71,0xe9,0xba,0xe3,0xda,0x85,0x4e,0xc,0x7d,0xcd,0x3f,0xfd,0xf0,0xeb,0x66,0x75,0xb6,0xf6,0xf0,0xad,0xb7,0x97,0x5f,0x12,0x33,0x5b,0xb7,0xbf,0xbb,0x3d,0xdb,0xea,0x74,0x97,0x3a,0xdd,0xee,0x7b,0x3,0xdf,0x9b,0xd7,0x5a,0xdb,0xc6,0x8c,0x7e,0xad,0xa,0x21,0x60,0xdb,0xb6,0x2e,0xbb,0x95,0xd7,0xb5,0x6a,0xf5,0x79,0xa3,0x56,0xfd,0xf3,0xda,0x97,0xd7,0xf6,0x29,0xdd,0xbd,0x6f,0x6f,0x3f,0x28,0xf5,0xff,0x6e,0x56,0xb4,0x19,0x2a,0x66,0x73,0xe2,0xe3,0x25,0x12,0xc6,0x16,0x4e,0x30,0x73,0x7a,0xc1,0x5b,0x5f,0xff,0xe8,0x10,0xc0,0xd1,0xf6,0x4,0xcc,0x4c,0x3b,0x3b,0x3b,0xa2,0xd1,0x68,0x14,0x8e,0xd0,0x6a,0xb5,0x78,0x6d,0x6d,0xcd,0x10,0xc5,0xdb,0xba,0x7f,0x0,0xb2,0x1f,0xaf,0x82,0x62,0x7a,0x69,0xbb,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
@@ -544,6 +549,11 @@ static const unsigned char vsplitter_png[]={
};
+static const unsigned char window_resizer_png[]={
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x8,0x19,0x11,0x33,0x13,0xaa,0xc0,0xf,0x5f,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0x2f,0x49,0x44,0x41,0x54,0x38,0xcb,0x63,0x60,0x18,0x5,0x24,0x81,0x17,0x2f,0x5e,0xf4,0xa3,0x8b,0x31,0x91,0xa2,0xb9,0xb9,0xb9,0x99,0x7c,0x9b,0xb3,0xb3,0xb3,0xfb,0x87,0x81,0x66,0x6c,0x81,0x48,0x92,0x66,0xa2,0x5c,0x43,0x91,0xe6,0x11,0xa,0x0,0x73,0x5b,0x34,0x19,0x10,0xa0,0xb6,0x7d,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+};
+
+
diff --git a/scene/resources/default_theme/window_resizer.png b/scene/resources/default_theme/window_resizer.png
new file mode 100644
index 0000000000..ed51968c4e
--- /dev/null
+++ b/scene/resources/default_theme/window_resizer.png
Binary files differ