String _Marshalls::variant_to_base64(const Variant& p_var) { int len; Error err = encode_variant(p_var,NULL,len); ERR_FAIL_COND_V( err != OK, "" ); DVector<uint8_t> buff; buff.resize(len); DVector<uint8_t>::Write w = buff.write(); err = encode_variant(p_var,&w[0],len); ERR_FAIL_COND_V( err != OK, "" ); int b64len = len / 3 * 4 + 4 + 1; DVector<uint8_t> b64buff; b64buff.resize(b64len); DVector<uint8_t>::Write w64 = b64buff.write(); int strlen = base64_encode((char*)(&w64[0]), (char*)(&w[0]), len); //OS::get_singleton()->print("len is %i, vector size is %i\n", b64len, strlen); w64[strlen] = 0; String ret = (char*)&w64[0]; return ret; };
void StreamPeer::put_var(const Variant &p_variant) { int len = 0; Vector<uint8_t> buf; encode_variant(p_variant, NULL, len); buf.resize(len); put_32(len); encode_variant(p_variant, buf.ptr(), len); put_data(buf.ptr(), buf.size()); }
Error PacketPeer::put_var(const Variant &p_packet) { int len; Error err = encode_variant(p_packet, NULL, len); // compute len first if (err) return err; if (len == 0) return OK; uint8_t *buf = (uint8_t *)alloca(len); ERR_FAIL_COND_V(!buf, ERR_OUT_OF_MEMORY); err = encode_variant(p_packet, buf, len); ERR_FAIL_COND_V(err, err); return put_packet(buf, len); }
void _File::store_var(const Variant& p_var) { ERR_FAIL_COND(!f); int len; Error err = encode_variant(p_var,NULL,len); ERR_FAIL_COND( err != OK ); DVector<uint8_t> buff; buff.resize(len); DVector<uint8_t>::Write w = buff.write(); err = encode_variant(p_var,&w[0],len); ERR_FAIL_COND( err != OK ); w=DVector<uint8_t>::Write(); store_32(len); store_buffer(buff); }
void ScriptDebuggerRemote::_send_object_id(ObjectID p_id) { Object *obj = ObjectDB::get_instance(p_id); if (!obj) return; List<PropertyInfo> pinfo; obj->get_property_list(&pinfo, true); int props_to_send = 0; for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { if (E->get().usage & (PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CATEGORY)) { props_to_send++; } } packet_peer_stream->put_var("message:inspect_object"); packet_peer_stream->put_var(props_to_send * 5 + 4); packet_peer_stream->put_var(p_id); packet_peer_stream->put_var(obj->get_class()); if (obj->is_class("Resource") || obj->is_class("Node")) packet_peer_stream->put_var(obj->call("get_path")); else packet_peer_stream->put_var(""); packet_peer_stream->put_var(props_to_send); for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { if (E->get().usage & (PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CATEGORY)) { if (E->get().usage & PROPERTY_USAGE_CATEGORY) { packet_peer_stream->put_var("*" + E->get().name); } else { packet_peer_stream->put_var(E->get().name); } Variant var = obj->get(E->get().name); packet_peer_stream->put_var(E->get().type); //only send information that can be sent.. int len = 0; //test how big is this to encode encode_variant(var, NULL, len); if (len > packet_peer_stream->get_output_buffer_max_size()) { //limit to max size packet_peer_stream->put_var(PROPERTY_HINT_OBJECT_TOO_BIG); packet_peer_stream->put_var(""); packet_peer_stream->put_var(Variant()); } else { packet_peer_stream->put_var(E->get().hint); packet_peer_stream->put_var(E->get().hint_string); packet_peer_stream->put_var(var); } } } }
void ScriptDebuggerRemote::_put_variable(const String &p_name, const Variant &p_variable) { packet_peer_stream->put_var(p_name); int len = 0; Error err = encode_variant(p_variable, NULL, len); if (len > packet_peer_stream->get_output_buffer_max_size()) { //limit to max size packet_peer_stream->put_var(Variant()); } else { packet_peer_stream->put_var(p_variable); } }
void GDNetHost::broadcast_var(const Variant& var, int channel_id, int type) { ERR_FAIL_COND(_host == NULL); int len; Error err = encode_variant(var, NULL, len); ERR_FAIL_COND(err != OK || len == 0); GDNetMessage* message = memnew(GDNetMessage((GDNetMessage::Type)type)); message->set_broadcast(true); message->set_channel_id(channel_id); ByteArray packet; packet.resize(len); ByteArray::Write w = packet.write(); err = encode_variant(var, w.ptr(), len); ERR_FAIL_COND(err != OK); message->set_packet(packet); _message_queue.push(message); }
void ScriptDebuggerRemote::_put_variable(const String &p_name, const Variant &p_variable) { packet_peer_stream->put_var(p_name); Variant var = p_variable; if (p_variable.get_type() == Variant::OBJECT && !ObjectDB::instance_validate(p_variable)) { var = Variant(); } int len = 0; Error err = encode_variant(var, NULL, len, true); if (err != OK) ERR_PRINT("Failed to encode variant"); if (len > packet_peer_stream->get_output_buffer_max_size()) { //limit to max size packet_peer_stream->put_var(Variant()); } else { packet_peer_stream->put_var(var); } }
void ScriptDebuggerRemote::_send_object_id(ObjectID p_id) { Object *obj = ObjectDB::get_instance(p_id); if (!obj) return; typedef Pair<PropertyInfo, Variant> PropertyDesc; List<PropertyDesc> properties; if (ScriptInstance *si = obj->get_script_instance()) { if (!si->get_script().is_null()) { typedef Map<const Script *, Set<StringName> > ScriptMemberMap; typedef Map<const Script *, Map<StringName, Variant> > ScriptConstantsMap; ScriptMemberMap members; members[si->get_script().ptr()] = Set<StringName>(); si->get_script()->get_members(&(members[si->get_script().ptr()])); ScriptConstantsMap constants; constants[si->get_script().ptr()] = Map<StringName, Variant>(); si->get_script()->get_constants(&(constants[si->get_script().ptr()])); Ref<Script> base = si->get_script()->get_base_script(); while (base.is_valid()) { members[base.ptr()] = Set<StringName>(); base->get_members(&(members[base.ptr()])); constants[base.ptr()] = Map<StringName, Variant>(); base->get_constants(&(constants[base.ptr()])); base = base->get_base_script(); } for (ScriptMemberMap::Element *sm = members.front(); sm; sm = sm->next()) { for (Set<StringName>::Element *E = sm->get().front(); E; E = E->next()) { Variant m; if (si->get(E->get(), m)) { String script_path = sm->key() == si->get_script().ptr() ? "" : sm->key()->get_path().get_file() + "/"; PropertyInfo pi(m.get_type(), "Members/" + script_path + E->get()); properties.push_back(PropertyDesc(pi, m)); } } } for (ScriptConstantsMap::Element *sc = constants.front(); sc; sc = sc->next()) { for (Map<StringName, Variant>::Element *E = sc->get().front(); E; E = E->next()) { String script_path = sc->key() == si->get_script().ptr() ? "" : sc->key()->get_path().get_file() + "/"; if (E->value().get_type() == Variant::OBJECT) { Variant id = ((Object *)E->value())->get_instance_id(); PropertyInfo pi(id.get_type(), "Constants/" + E->key(), PROPERTY_HINT_OBJECT_ID, "Object"); properties.push_back(PropertyDesc(pi, id)); } else { PropertyInfo pi(E->value().get_type(), "Constants/" + script_path + E->key()); properties.push_back(PropertyDesc(pi, E->value())); } } } } } if (Node *node = Object::cast_to<Node>(obj)) { PropertyInfo pi(Variant::NODE_PATH, String("Node/path")); properties.push_front(PropertyDesc(pi, node->get_path())); } else if (Resource *res = Object::cast_to<Resource>(obj)) { if (Script *s = Object::cast_to<Script>(res)) { Map<StringName, Variant> constants; s->get_constants(&constants); for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) { if (E->value().get_type() == Variant::OBJECT) { Variant id = ((Object *)E->value())->get_instance_id(); PropertyInfo pi(id.get_type(), "Constants/" + E->key(), PROPERTY_HINT_OBJECT_ID, "Object"); properties.push_front(PropertyDesc(pi, E->value())); } else { PropertyInfo pi(E->value().get_type(), String("Constants/") + E->key()); properties.push_front(PropertyDesc(pi, E->value())); } } } } List<PropertyInfo> pinfo; obj->get_property_list(&pinfo, true); for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { if (E->get().usage & (PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CATEGORY)) { properties.push_back(PropertyDesc(E->get(), obj->get(E->get().name))); } } Array send_props; for (int i = 0; i < properties.size(); i++) { const PropertyInfo &pi = properties[i].first; Variant &var = properties[i].second; WeakRef *ref = Object::cast_to<WeakRef>(var); if (ref) { var = ref->get_ref(); } RES res = var; Array prop; prop.push_back(pi.name); prop.push_back(pi.type); //only send information that can be sent.. int len = 0; //test how big is this to encode encode_variant(var, NULL, len); if (len > packet_peer_stream->get_output_buffer_max_size()) { //limit to max size prop.push_back(PROPERTY_HINT_OBJECT_TOO_BIG); prop.push_back(""); prop.push_back(pi.usage); prop.push_back(Variant()); } else { prop.push_back(pi.hint); prop.push_back(pi.hint_string); prop.push_back(pi.usage); if (!res.is_null()) { var = res->get_path(); } prop.push_back(var); } send_props.push_back(prop); } packet_peer_stream->put_var("message:inspect_object"); packet_peer_stream->put_var(3); packet_peer_stream->put_var(p_id); packet_peer_stream->put_var(obj->get_class()); packet_peer_stream->put_var(send_props); }
void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Variant &r_ret,Variant::CallError &r_error) { r_error.error=Variant::CallError::CALL_OK; #ifdef DEBUG_ENABLED #define VALIDATE_ARG_COUNT(m_count) \ if (p_arg_count<m_count) {\ r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;\ r_error.argument=m_count;\ r_ret=Variant();\ return;\ }\ if (p_arg_count>m_count) {\ r_error.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;\ r_error.argument=m_count;\ r_ret=Variant();\ return;\ } #define VALIDATE_ARG_NUM(m_arg) \ if (!p_args[m_arg]->is_num()) {\ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;\ r_error.argument=m_arg;\ r_error.expected=Variant::REAL;\ r_ret=Variant();\ return;\ } #else #define VALIDATE_ARG_COUNT(m_count) #define VALIDATE_ARG_NUM(m_arg) #endif //using a switch, so the compiler generates a jumptable switch(p_func) { case MATH_SIN: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::sin((double)*p_args[0]); } break; case MATH_COS: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::cos((double)*p_args[0]); } break; case MATH_TAN: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::tan((double)*p_args[0]); } break; case MATH_SINH: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::sinh((double)*p_args[0]); } break; case MATH_COSH: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::cosh((double)*p_args[0]); } break; case MATH_TANH: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::tanh((double)*p_args[0]); } break; case MATH_ASIN: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::asin((double)*p_args[0]); } break; case MATH_ACOS: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::acos((double)*p_args[0]); } break; case MATH_ATAN: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::atan((double)*p_args[0]); } break; case MATH_ATAN2: { VALIDATE_ARG_COUNT(2); VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); r_ret=Math::atan2((double)*p_args[0],(double)*p_args[1]); } break; case MATH_SQRT: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::sqrt((double)*p_args[0]); } break; case MATH_FMOD: { VALIDATE_ARG_COUNT(2); VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); r_ret=Math::fmod((double)*p_args[0],(double)*p_args[1]); } break; case MATH_FPOSMOD: { VALIDATE_ARG_COUNT(2); VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); r_ret=Math::fposmod((double)*p_args[0],(double)*p_args[1]); } break; case MATH_FLOOR: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::floor((double)*p_args[0]); } break; case MATH_CEIL: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::ceil((double)*p_args[0]); } break; case MATH_ROUND: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::round((double)*p_args[0]); } break; case MATH_ABS: { VALIDATE_ARG_COUNT(1); if (p_args[0]->get_type()==Variant::INT) { int64_t i = *p_args[0]; r_ret=ABS(i); } else if (p_args[0]->get_type()==Variant::REAL) { double r = *p_args[0]; r_ret=Math::abs(r); } else { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::REAL; r_ret=Variant(); } } break; case MATH_SIGN: { VALIDATE_ARG_COUNT(1); if (p_args[0]->get_type()==Variant::INT) { int64_t i = *p_args[0]; r_ret= i < 0 ? -1 : ( i > 0 ? +1 : 0); } else if (p_args[0]->get_type()==Variant::REAL) { real_t r = *p_args[0]; r_ret= r < 0.0 ? -1.0 : ( r > 0.0 ? +1.0 : 0.0); } else { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::REAL; r_ret=Variant(); } } break; case MATH_POW: { VALIDATE_ARG_COUNT(2); VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); r_ret=Math::pow((double)*p_args[0],(double)*p_args[1]); } break; case MATH_LOG: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::log((double)*p_args[0]); } break; case MATH_EXP: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::exp((double)*p_args[0]); } break; case MATH_ISNAN: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::is_nan((double)*p_args[0]); } break; case MATH_ISINF: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::is_inf((double)*p_args[0]); } break; case MATH_EASE: { VALIDATE_ARG_COUNT(2); VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); r_ret=Math::ease((double)*p_args[0],(double)*p_args[1]); } break; case MATH_DECIMALS: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::step_decimals((double)*p_args[0]); } break; case MATH_STEPIFY: { VALIDATE_ARG_COUNT(2); VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); r_ret=Math::stepify((double)*p_args[0],(double)*p_args[1]); } break; case MATH_LERP: { VALIDATE_ARG_COUNT(3); VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); VALIDATE_ARG_NUM(2); r_ret=Math::lerp((double)*p_args[0],(double)*p_args[1],(double)*p_args[2]); } break; case MATH_DECTIME: { VALIDATE_ARG_COUNT(3); VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); VALIDATE_ARG_NUM(2); r_ret=Math::dectime((double)*p_args[0],(double)*p_args[1],(double)*p_args[2]); } break; case MATH_RANDOMIZE: { Math::randomize(); r_ret=Variant(); } break; case MATH_RAND: { r_ret=Math::rand(); } break; case MATH_RANDF: { r_ret=Math::randf(); } break; case MATH_RANDOM: { VALIDATE_ARG_COUNT(2); VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); r_ret=Math::random((double)*p_args[0],(double)*p_args[1]); } break; case MATH_SEED: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); uint64_t seed=*p_args[0]; Math::seed(seed); r_ret=Variant(); } break; case MATH_RANDSEED: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); uint64_t seed=*p_args[0]; int ret = Math::rand_from_seed(&seed); Array reta; reta.push_back(ret); reta.push_back(seed); r_ret=reta; } break; case MATH_DEG2RAD: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::deg2rad((double)*p_args[0]); } break; case MATH_RAD2DEG: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::rad2deg((double)*p_args[0]); } break; case MATH_LINEAR2DB: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::linear2db((double)*p_args[0]); } break; case MATH_DB2LINEAR: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); r_ret=Math::db2linear((double)*p_args[0]); } break; case LOGIC_MAX: { VALIDATE_ARG_COUNT(2); if (p_args[0]->get_type()==Variant::INT && p_args[1]->get_type()==Variant::INT) { int64_t a = *p_args[0]; int64_t b = *p_args[1]; r_ret=MAX(a,b); } else { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); real_t a = *p_args[0]; real_t b = *p_args[1]; r_ret=MAX(a,b); } } break; case LOGIC_MIN: { VALIDATE_ARG_COUNT(2); if (p_args[0]->get_type()==Variant::INT && p_args[1]->get_type()==Variant::INT) { int64_t a = *p_args[0]; int64_t b = *p_args[1]; r_ret=MIN(a,b); } else { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); real_t a = *p_args[0]; real_t b = *p_args[1]; r_ret=MIN(a,b); } } break; case LOGIC_CLAMP: { VALIDATE_ARG_COUNT(3); if (p_args[0]->get_type()==Variant::INT && p_args[1]->get_type()==Variant::INT && p_args[2]->get_type()==Variant::INT) { int64_t a = *p_args[0]; int64_t b = *p_args[1]; int64_t c = *p_args[2]; r_ret=CLAMP(a,b,c); } else { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); VALIDATE_ARG_NUM(2); real_t a = *p_args[0]; real_t b = *p_args[1]; real_t c = *p_args[2]; r_ret=CLAMP(a,b,c); } } break; case LOGIC_NEAREST_PO2: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); int64_t num = *p_args[0]; r_ret = nearest_power_of_2(num); } break; case OBJ_WEAKREF: { VALIDATE_ARG_COUNT(1); if (p_args[0]->get_type()!=Variant::OBJECT) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::OBJECT; r_ret=Variant(); return; } if (p_args[0]->is_ref()) { REF r = *p_args[0]; if (!r.is_valid()) { r_ret=Variant(); return; } Ref<WeakRef> wref = memnew( WeakRef ); wref->set_ref(r); r_ret=wref; } else { Object *obj = *p_args[0]; if (!obj) { r_ret=Variant(); return; } Ref<WeakRef> wref = memnew( WeakRef ); wref->set_obj(obj); r_ret=wref; } } break; case FUNC_FUNCREF: { VALIDATE_ARG_COUNT(2); if (p_args[0]->get_type()!=Variant::OBJECT) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::OBJECT; r_ret=Variant(); return; } if (p_args[1]->get_type()!=Variant::STRING && p_args[1]->get_type()!=Variant::NODE_PATH) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=1; r_error.expected=Variant::STRING; r_ret=Variant(); return; } Ref<FuncRef> fr = memnew( FuncRef); fr->set_instance(*p_args[0]); fr->set_function(*p_args[1]); r_ret=fr; } break; case TYPE_CONVERT: { VALIDATE_ARG_COUNT(2); VALIDATE_ARG_NUM(1); int type=*p_args[1]; if (type<0 || type>=Variant::VARIANT_MAX) { r_ret=RTR("Invalid type argument to convert(), use TYPE_* constants."); r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::INT; return; } else { r_ret=Variant::construct(Variant::Type(type),p_args,1,r_error); } } break; case TYPE_OF: { VALIDATE_ARG_COUNT(1); r_ret = p_args[0]->get_type(); } break; case TYPE_EXISTS: { VALIDATE_ARG_COUNT(1); r_ret = ClassDB::class_exists(*p_args[0]); } break; case TEXT_CHAR: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); CharType result[2] = {*p_args[0], 0}; r_ret=String(result); } break; case TEXT_STR: { String str; for(int i=0;i<p_arg_count;i++) { String os = p_args[i]->operator String(); if (i==0) str=os; else str+=os; } r_ret=str; } break; case TEXT_PRINT: { String str; for(int i=0;i<p_arg_count;i++) { str+=p_args[i]->operator String(); } //str+="\n"; print_line(str); r_ret=Variant(); } break; case TEXT_PRINT_TABBED: { String str; for(int i=0;i<p_arg_count;i++) { if (i) str+="\t"; str+=p_args[i]->operator String(); } //str+="\n"; print_line(str); r_ret=Variant(); } break; case TEXT_PRINT_SPACED: { String str; for(int i=0;i<p_arg_count;i++) { if (i) str+=" "; str+=p_args[i]->operator String(); } //str+="\n"; print_line(str); r_ret=Variant(); } break; case TEXT_PRINTERR: { String str; for(int i=0;i<p_arg_count;i++) { str+=p_args[i]->operator String(); } //str+="\n"; OS::get_singleton()->printerr("%s\n",str.utf8().get_data()); r_ret=Variant(); } break; case TEXT_PRINTRAW: { String str; for(int i=0;i<p_arg_count;i++) { str+=p_args[i]->operator String(); } //str+="\n"; OS::get_singleton()->print("%s",str.utf8().get_data()); r_ret=Variant(); } break; case VAR_TO_STR: { VALIDATE_ARG_COUNT(1); String vars; VariantWriter::write_to_string(*p_args[0],vars); r_ret=vars; } break; case STR_TO_VAR: { VALIDATE_ARG_COUNT(1); 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; r_ret=Variant(); return; } VariantParser::StreamString ss; ss.s=*p_args[0]; String errs; int line; Error err = VariantParser::parse(&ss,r_ret,errs,line); if (err!=OK) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::STRING; r_ret="Parse error at line "+itos(line)+": "+errs; return; } } break; case VAR_TO_BYTES: { VALIDATE_ARG_COUNT(1); PoolByteArray barr; int len; Error err = encode_variant(*p_args[0],NULL,len); if (err) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::NIL; r_ret="Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID)."; return; } barr.resize(len); { PoolByteArray::Write w = barr.write(); encode_variant(*p_args[0],w.ptr(),len); } r_ret=barr; } break; case BYTES_TO_VAR: { VALIDATE_ARG_COUNT(1); if (p_args[0]->get_type()!=Variant::POOL_BYTE_ARRAY) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::POOL_BYTE_ARRAY; r_ret=Variant(); return; } PoolByteArray varr=*p_args[0]; Variant ret; { PoolByteArray::Read r=varr.read(); Error err = decode_variant(ret,r.ptr(),varr.size(),NULL); if (err!=OK) { r_ret=RTR("Not enough bytes for decoding bytes, or invalid format."); r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::POOL_BYTE_ARRAY; return; } } r_ret=ret; } break; case GEN_RANGE: { switch(p_arg_count) { case 0: { r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; r_error.argument=1; r_ret=Variant(); } break; case 1: { VALIDATE_ARG_NUM(0); int count=*p_args[0]; Array arr; if (count<=0) { r_ret=arr; return; } Error err = arr.resize(count); if (err!=OK) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; r_ret=Variant(); return; } for(int i=0;i<count;i++) { arr[i]=i; } r_ret=arr; } break; case 2: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); int from=*p_args[0]; int to=*p_args[1]; Array arr; if (from>=to) { r_ret=arr; return; } Error err = arr.resize(to-from); if (err!=OK) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; r_ret=Variant(); return; } for(int i=from;i<to;i++) arr[i-from]=i; r_ret=arr; } break; case 3: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); VALIDATE_ARG_NUM(2); int from=*p_args[0]; int to=*p_args[1]; int incr=*p_args[2]; if (incr==0) { r_ret=RTR("step argument is zero!"); r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; return; } Array arr; if (from>=to && incr>0) { r_ret=arr; return; } if (from<=to && incr<0) { r_ret=arr; return; } //calculate how many int count=0; if (incr>0) { count=((to-from-1)/incr)+1; } else { count=((from-to-1)/-incr)+1; } Error err = arr.resize(count); if (err!=OK) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; r_ret=Variant(); return; } if (incr>0) { int idx=0; for(int i=from;i<to;i+=incr) { arr[idx++]=i; } } else { int idx=0; for(int i=from;i>to;i+=incr) { arr[idx++]=i; } } r_ret=arr; } break; default: { r_error.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; r_error.argument=3; r_ret=Variant(); } break; } } break; case RESOURCE_LOAD: { VALIDATE_ARG_COUNT(1); 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; r_ret=Variant(); } else { r_ret=ResourceLoader::load(*p_args[0]); } } break; case INST2DICT: { VALIDATE_ARG_COUNT(1); if (p_args[0]->get_type()==Variant::NIL) { r_ret=Variant(); } else if (p_args[0]->get_type()!=Variant::OBJECT) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_ret=Variant(); } else { Object *obj = *p_args[0]; if (!obj) { r_ret=Variant(); } else if (!obj->get_script_instance() || obj->get_script_instance()->get_language()!=GDScriptLanguage::get_singleton()) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::DICTIONARY; r_ret=RTR("Not a script with an instance"); return; } else { GDInstance *ins = static_cast<GDInstance*>(obj->get_script_instance()); Ref<GDScript> base = ins->get_script(); if (base.is_null()) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::DICTIONARY; r_ret=RTR("Not based on a script"); return; } GDScript *p = base.ptr(); Vector<StringName> sname; while(p->_owner) { sname.push_back(p->name); p=p->_owner; } sname.invert(); if (!p->path.is_resource_file()) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::DICTIONARY; r_ret=Variant(); r_ret=RTR("Not based on a resource file"); return; } NodePath cp(sname,Vector<StringName>(),false); Dictionary d; d["@subpath"]=cp; d["@path"]=p->path; p = base.ptr(); while(p) { for(Set<StringName>::Element *E=p->members.front();E;E=E->next()) { Variant value; if (ins->get(E->get(),value)) { String k = E->get(); if (!d.has(k)) { d[k]=value; } } } p=p->_base; } r_ret=d; } } } break; case DICT2INST: { VALIDATE_ARG_COUNT(1); if (p_args[0]->get_type()!=Variant::DICTIONARY) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::DICTIONARY; r_ret=Variant(); return; } Dictionary d = *p_args[0]; if (!d.has("@path")) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::OBJECT; r_ret=RTR("Invalid instance dictionary format (missing @path)"); return; } Ref<Script> scr = ResourceLoader::load(d["@path"]); if (!scr.is_valid()) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::OBJECT; r_ret=RTR("Invalid instance dictionary format (can't load script at @path)"); return; } Ref<GDScript> gdscr = scr; if (!gdscr.is_valid()) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::OBJECT; r_ret=Variant(); r_ret=RTR("Invalid instance dictionary format (invalid script at @path)"); return; } NodePath sub; if (d.has("@subpath")) { sub=d["@subpath"]; } for(int i=0;i<sub.get_name_count();i++) { gdscr = gdscr->subclasses[ sub.get_name(i)]; if (!gdscr.is_valid()) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::OBJECT; r_ret=Variant(); r_ret=RTR("Invalid instance dictionary (invalid subclasses)"); return; } } r_ret = gdscr->_new(NULL,0,r_error); GDInstance *ins = static_cast<GDInstance*>(static_cast<Object*>(r_ret)->get_script_instance()); Ref<GDScript> gd_ref = ins->get_script(); for(Map<StringName,GDScript::MemberInfo>::Element *E = gd_ref->member_indices.front(); E; E = E->next()) { if(d.has(E->key())) { ins->members[E->get().index] = d[E->key()]; } } } break; case VALIDATE_JSON: { VALIDATE_ARG_COUNT(1); 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; r_ret=Variant(); return; } String errs; int errl; Error err = JSON::parse(*p_args[0],r_ret,errs,errl); if (err!=OK) { r_ret=itos(errl)+":"+errs; } else { r_ret=""; } } break; case PARSE_JSON: { VALIDATE_ARG_COUNT(1); 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; r_ret=Variant(); return; } String errs; int errl; Error err = JSON::parse(*p_args[0],r_ret,errs,errl); if (err!=OK) { r_ret=Variant(); } } break; case TO_JSON: { VALIDATE_ARG_COUNT(1); r_ret = JSON::print(*p_args[0]); } break; case HASH: { VALIDATE_ARG_COUNT(1); r_ret=p_args[0]->hash(); } break; case COLOR8: { if (p_arg_count<3) { r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; r_error.argument=3; r_ret=Variant(); return; } if (p_arg_count>4) { r_error.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; r_error.argument=4; r_ret=Variant(); return; } VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); VALIDATE_ARG_NUM(2); Color color((float)*p_args[0]/255.0f,(float)*p_args[1]/255.0f,(float)*p_args[2]/255.0f); if (p_arg_count==4) { VALIDATE_ARG_NUM(3); color.a=(float)*p_args[3]/255.0f; } r_ret=color; } break; case COLORN: { if (p_arg_count<1) { r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; r_error.argument=1; r_ret=Variant(); return; } if (p_arg_count>2) { r_error.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; r_error.argument=2; r_ret=Variant(); return; } if (p_args[0]->get_type()!=Variant::STRING) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_ret=Variant(); } else { Color color = Color::named(*p_args[0]); if (p_arg_count==2) { VALIDATE_ARG_NUM(1); color.a=*p_args[1]; } r_ret=color; } } break; case PRINT_STACK: { ScriptLanguage* script = GDScriptLanguage::get_singleton(); for (int i=0; i < script->debug_get_stack_level_count(); i++) { print_line("Frame "+itos(i)+" - "+script->debug_get_stack_level_source(i)+":"+itos(script->debug_get_stack_level_line(i))+" in function '"+script->debug_get_stack_level_function(i)+"'"); }; } break; case INSTANCE_FROM_ID: { VALIDATE_ARG_COUNT(1); if (p_args[0]->get_type()!=Variant::INT && p_args[0]->get_type()!=Variant::REAL) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::INT; r_ret=Variant(); break; } uint32_t id=*p_args[0]; r_ret=ObjectDB::get_instance(id); } break; case FUNC_MAX: { ERR_FAIL(); } break; } }
Vector<uint8_t> GDTokenizerBuffer::parse_code_string(const String& p_code) { Vector<uint8_t> buf; Map<StringName,int> identifier_map; HashMap<Variant,int,VariantHasher> constant_map; Map<uint32_t,int> line_map; Vector<uint32_t> token_array; GDTokenizerText tt; tt.set_code(p_code); int line=-1; int col=0; while(true) { if (tt.get_token_line()!=line) { line=tt.get_token_line(); line_map[line]=token_array.size(); } uint32_t token=tt.get_token(); switch(tt.get_token()) { case TK_IDENTIFIER: { StringName id = tt.get_token_identifier(); if (!identifier_map.has(id)) { int idx = identifier_map.size(); identifier_map[id]=idx; } token|=identifier_map[id]<<TOKEN_BITS; } break; case TK_CONSTANT: { Variant c = tt.get_token_constant(); if (!constant_map.has(c)) { int idx = constant_map.size(); constant_map[c]=idx; } token|=constant_map[c]<<TOKEN_BITS; } break; case TK_BUILT_IN_TYPE: { token|=tt.get_token_type()<<TOKEN_BITS; } break; case TK_BUILT_IN_FUNC: { token|=tt.get_token_built_in_func()<<TOKEN_BITS; } break; case TK_NEWLINE: { token|=tt.get_token_line_indent()<<TOKEN_BITS; } break; case TK_ERROR: { ERR_FAIL_V(Vector<uint8_t>()); } break; default: {} }; token_array.push_back(token); if (tt.get_token()==TK_EOF) break; tt.advance(); } //reverse maps Map<int,StringName> rev_identifier_map; for(Map<StringName,int>::Element *E=identifier_map.front();E;E=E->next()) { rev_identifier_map[E->get()]=E->key(); } Map<int,Variant> rev_constant_map; const Variant *K =NULL; while((K=constant_map.next(K))) { rev_constant_map[constant_map[*K]]=*K; } Map<int,uint32_t> rev_line_map; for(Map<uint32_t,int>::Element *E=line_map.front();E;E=E->next()) { rev_line_map[E->get()]=E->key(); } //save header buf.resize(24); buf[0]='G'; buf[1]='D'; buf[2]='S'; buf[3]='C'; encode_uint32(BYTECODE_VERSION,&buf[4]); encode_uint32(identifier_map.size(),&buf[8]); encode_uint32(constant_map.size(),&buf[12]); encode_uint32(line_map.size(),&buf[16]); encode_uint32(token_array.size(),&buf[20]); //save identifiers for(Map<int,StringName>::Element *E=rev_identifier_map.front();E;E=E->next()) { CharString cs = String(E->get()).utf8(); int len = cs.length()+1; int extra = 4-(len%4); if (extra==4) extra=0; uint8_t ibuf[4]; encode_uint32(len+extra,ibuf); for(int i=0;i<4;i++) { buf.push_back(ibuf[i]); } for(int i=0;i<len;i++) { buf.push_back(cs[i]^0xb6); } for(int i=0;i<extra;i++) { buf.push_back(0^0xb6); } } for(Map<int,Variant>::Element *E=rev_constant_map.front();E;E=E->next()) { int len; Error err = encode_variant(E->get(),NULL,len); ERR_FAIL_COND_V(err!=OK,Vector<uint8_t>()); int pos=buf.size(); buf.resize(pos+len); encode_variant(E->get(),&buf[pos],len); } for(Map<int,uint32_t>::Element *E=rev_line_map.front();E;E=E->next()) { uint8_t ibuf[8]; encode_uint32(E->key(),&ibuf[0]); encode_uint32(E->get(),&ibuf[4]); for(int i=0;i<8;i++) buf.push_back(ibuf[i]); } for(int i=0;i<token_array.size();i++) { uint32_t token = token_array[i]; if (token&~TOKEN_MASK) { uint8_t buf4[4]; encode_uint32(token_array[i]|TOKEN_BYTE_MASK,&buf4[0]); for(int j=0;j<4;j++) { buf.push_back(buf4[j]); } } else { buf.push_back(token); } } return buf; }
void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant *r_return, Variant::CallError &r_error, String &r_error_str) { switch (p_func) { case VisualScriptBuiltinFunc::MATH_SIN: { VALIDATE_ARG_NUM(0); *r_return = Math::sin((double)*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_COS: { VALIDATE_ARG_NUM(0); *r_return = Math::cos((double)*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_TAN: { VALIDATE_ARG_NUM(0); *r_return = Math::tan((double)*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_SINH: { VALIDATE_ARG_NUM(0); *r_return = Math::sinh((double)*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_COSH: { VALIDATE_ARG_NUM(0); *r_return = Math::cosh((double)*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_TANH: { VALIDATE_ARG_NUM(0); *r_return = Math::tanh((double)*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_ASIN: { VALIDATE_ARG_NUM(0); *r_return = Math::asin((double)*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_ACOS: { VALIDATE_ARG_NUM(0); *r_return = Math::acos((double)*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_ATAN: { VALIDATE_ARG_NUM(0); *r_return = Math::atan((double)*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_ATAN2: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); *r_return = Math::atan2((double)*p_inputs[0], (double)*p_inputs[1]); } break; case VisualScriptBuiltinFunc::MATH_SQRT: { VALIDATE_ARG_NUM(0); *r_return = Math::sqrt((double)*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_FMOD: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); *r_return = Math::fmod((double)*p_inputs[0], (double)*p_inputs[1]); } break; case VisualScriptBuiltinFunc::MATH_FPOSMOD: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); *r_return = Math::fposmod((double)*p_inputs[0], (double)*p_inputs[1]); } break; case VisualScriptBuiltinFunc::MATH_FLOOR: { VALIDATE_ARG_NUM(0); *r_return = Math::floor((double)*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_CEIL: { VALIDATE_ARG_NUM(0); *r_return = Math::ceil((double)*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_ROUND: { VALIDATE_ARG_NUM(0); *r_return = Math::round((double)*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_ABS: { if (p_inputs[0]->get_type() == Variant::INT) { int64_t i = *p_inputs[0]; *r_return = ABS(i); } else if (p_inputs[0]->get_type() == Variant::REAL) { real_t r = *p_inputs[0]; *r_return = Math::abs(r); } else { r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::REAL; } } break; case VisualScriptBuiltinFunc::MATH_SIGN: { if (p_inputs[0]->get_type() == Variant::INT) { int64_t i = *p_inputs[0]; *r_return = i < 0 ? -1 : (i > 0 ? +1 : 0); } else if (p_inputs[0]->get_type() == Variant::REAL) { real_t r = *p_inputs[0]; *r_return = r < 0.0 ? -1.0 : (r > 0.0 ? +1.0 : 0.0); } else { r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::REAL; } } break; case VisualScriptBuiltinFunc::MATH_POW: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); *r_return = Math::pow((double)*p_inputs[0], (double)*p_inputs[1]); } break; case VisualScriptBuiltinFunc::MATH_LOG: { VALIDATE_ARG_NUM(0); *r_return = Math::log((double)*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_EXP: { VALIDATE_ARG_NUM(0); *r_return = Math::exp((double)*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_ISNAN: { VALIDATE_ARG_NUM(0); *r_return = Math::is_nan((double)*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_ISINF: { VALIDATE_ARG_NUM(0); *r_return = Math::is_inf((double)*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_EASE: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); *r_return = Math::ease((double)*p_inputs[0], (double)*p_inputs[1]); } break; case VisualScriptBuiltinFunc::MATH_DECIMALS: { VALIDATE_ARG_NUM(0); *r_return = Math::step_decimals((double)*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_STEPIFY: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); *r_return = Math::stepify((double)*p_inputs[0], (double)*p_inputs[1]); } break; case VisualScriptBuiltinFunc::MATH_LERP: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); VALIDATE_ARG_NUM(2); *r_return = Math::lerp((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]); } break; case VisualScriptBuiltinFunc::MATH_INVERSE_LERP: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); VALIDATE_ARG_NUM(2); *r_return = Math::inverse_lerp((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]); } break; case VisualScriptBuiltinFunc::MATH_RANGE_LERP: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); VALIDATE_ARG_NUM(2); VALIDATE_ARG_NUM(3); VALIDATE_ARG_NUM(4); *r_return = Math::range_lerp((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2], (double)*p_inputs[3], (double)*p_inputs[4]); } break; case VisualScriptBuiltinFunc::MATH_SMOOTHSTEP: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); VALIDATE_ARG_NUM(2); *r_return = Math::smoothstep((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]); } break; case VisualScriptBuiltinFunc::MATH_DECTIME: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); VALIDATE_ARG_NUM(2); *r_return = Math::dectime((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]); } break; case VisualScriptBuiltinFunc::MATH_RANDOMIZE: { Math::randomize(); } break; case VisualScriptBuiltinFunc::MATH_RAND: { *r_return = Math::rand(); } break; case VisualScriptBuiltinFunc::MATH_RANDF: { *r_return = Math::randf(); } break; case VisualScriptBuiltinFunc::MATH_RANDOM: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); *r_return = Math::random((double)*p_inputs[0], (double)*p_inputs[1]); } break; case VisualScriptBuiltinFunc::MATH_SEED: { VALIDATE_ARG_NUM(0); uint64_t seed = *p_inputs[0]; Math::seed(seed); } break; case VisualScriptBuiltinFunc::MATH_RANDSEED: { VALIDATE_ARG_NUM(0); uint64_t seed = *p_inputs[0]; int ret = Math::rand_from_seed(&seed); Array reta; reta.push_back(ret); reta.push_back(seed); *r_return = reta; } break; case VisualScriptBuiltinFunc::MATH_DEG2RAD: { VALIDATE_ARG_NUM(0); *r_return = Math::deg2rad((double)*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_RAD2DEG: { VALIDATE_ARG_NUM(0); *r_return = Math::rad2deg((double)*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_LINEAR2DB: { VALIDATE_ARG_NUM(0); *r_return = Math::linear2db((double)*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_DB2LINEAR: { VALIDATE_ARG_NUM(0); *r_return = Math::db2linear((double)*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_POLAR2CARTESIAN: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); double r = *p_inputs[0]; double th = *p_inputs[1]; *r_return = Vector2(r * Math::cos(th), r * Math::sin(th)); } break; case VisualScriptBuiltinFunc::MATH_CARTESIAN2POLAR: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); double x = *p_inputs[0]; double y = *p_inputs[1]; *r_return = Vector2(Math::sqrt(x * x + y * y), Math::atan2(y, x)); } break; case VisualScriptBuiltinFunc::MATH_WRAP: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); VALIDATE_ARG_NUM(2); *r_return = Math::wrapi((int64_t)*p_inputs[0], (int64_t)*p_inputs[1], (int64_t)*p_inputs[2]); } break; case VisualScriptBuiltinFunc::MATH_WRAPF: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); VALIDATE_ARG_NUM(2); *r_return = Math::wrapf((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]); } break; case VisualScriptBuiltinFunc::LOGIC_MAX: { if (p_inputs[0]->get_type() == Variant::INT && p_inputs[1]->get_type() == Variant::INT) { int64_t a = *p_inputs[0]; int64_t b = *p_inputs[1]; *r_return = MAX(a, b); } else { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); real_t a = *p_inputs[0]; real_t b = *p_inputs[1]; *r_return = MAX(a, b); } } break; case VisualScriptBuiltinFunc::LOGIC_MIN: { if (p_inputs[0]->get_type() == Variant::INT && p_inputs[1]->get_type() == Variant::INT) { int64_t a = *p_inputs[0]; int64_t b = *p_inputs[1]; *r_return = MIN(a, b); } else { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); real_t a = *p_inputs[0]; real_t b = *p_inputs[1]; *r_return = MIN(a, b); } } break; case VisualScriptBuiltinFunc::LOGIC_CLAMP: { if (p_inputs[0]->get_type() == Variant::INT && p_inputs[1]->get_type() == Variant::INT && p_inputs[2]->get_type() == Variant::INT) { int64_t a = *p_inputs[0]; int64_t b = *p_inputs[1]; int64_t c = *p_inputs[2]; *r_return = CLAMP(a, b, c); } else { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); VALIDATE_ARG_NUM(2); real_t a = *p_inputs[0]; real_t b = *p_inputs[1]; real_t c = *p_inputs[2]; *r_return = CLAMP(a, b, c); } } break; case VisualScriptBuiltinFunc::LOGIC_NEAREST_PO2: { VALIDATE_ARG_NUM(0); int64_t num = *p_inputs[0]; *r_return = next_power_of_2(num); } break; case VisualScriptBuiltinFunc::OBJ_WEAKREF: { if (p_inputs[0]->get_type() != Variant::OBJECT) { r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::OBJECT; return; } if (p_inputs[0]->is_ref()) { REF r = *p_inputs[0]; if (!r.is_valid()) { return; } Ref<WeakRef> wref = memnew(WeakRef); wref->set_ref(r); *r_return = wref; } else { Object *obj = *p_inputs[0]; if (!obj) { return; } Ref<WeakRef> wref = memnew(WeakRef); wref->set_obj(obj); *r_return = wref; } } break; case VisualScriptBuiltinFunc::FUNC_FUNCREF: { if (p_inputs[0]->get_type() != Variant::OBJECT) { r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::OBJECT; return; } if (p_inputs[1]->get_type() != Variant::STRING && p_inputs[1]->get_type() != Variant::NODE_PATH) { r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 1; r_error.expected = Variant::STRING; return; } Ref<FuncRef> fr = memnew(FuncRef); fr->set_instance(*p_inputs[0]); fr->set_function(*p_inputs[1]); *r_return = fr; } break; case VisualScriptBuiltinFunc::TYPE_CONVERT: { VALIDATE_ARG_NUM(1); int type = *p_inputs[1]; if (type < 0 || type >= Variant::VARIANT_MAX) { r_error_str = RTR("Invalid type argument to convert(), use TYPE_* constants."); r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::INT; return; } else { *r_return = Variant::construct(Variant::Type(type), p_inputs, 1, r_error); } } break; case VisualScriptBuiltinFunc::TYPE_OF: { *r_return = p_inputs[0]->get_type(); } break; case VisualScriptBuiltinFunc::TYPE_EXISTS: { *r_return = ClassDB::class_exists(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::TEXT_CHAR: { CharType result[2] = { *p_inputs[0], 0 }; *r_return = String(result); } break; case VisualScriptBuiltinFunc::TEXT_STR: { String str = *p_inputs[0]; *r_return = str; } break; case VisualScriptBuiltinFunc::TEXT_PRINT: { String str = *p_inputs[0]; print_line(str); } break; case VisualScriptBuiltinFunc::TEXT_PRINTERR: { String str = *p_inputs[0]; print_error(str); } break; case VisualScriptBuiltinFunc::TEXT_PRINTRAW: { String str = *p_inputs[0]; OS::get_singleton()->print("%s", str.utf8().get_data()); } break; case VisualScriptBuiltinFunc::VAR_TO_STR: { String vars; VariantWriter::write_to_string(*p_inputs[0], vars); *r_return = vars; } break; case VisualScriptBuiltinFunc::STR_TO_VAR: { if (p_inputs[0]->get_type() != Variant::STRING) { r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::STRING; return; } VariantParser::StreamString ss; ss.s = *p_inputs[0]; String errs; int line; Error err = VariantParser::parse(&ss, *r_return, errs, line); if (err != OK) { r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::STRING; *r_return = "Parse error at line " + itos(line) + ": " + errs; return; } } break; case VisualScriptBuiltinFunc::VAR_TO_BYTES: { if (p_inputs[1]->get_type() != Variant::BOOL) { r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 1; r_error.expected = Variant::BOOL; return; } PoolByteArray barr; int len; bool full_objects = *p_inputs[1]; Error err = encode_variant(*p_inputs[0], NULL, len, full_objects); if (err) { r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::NIL; r_error_str = "Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID)."; return; } barr.resize(len); { PoolByteArray::Write w = barr.write(); encode_variant(*p_inputs[0], w.ptr(), len, full_objects); } *r_return = barr; } break; case VisualScriptBuiltinFunc::BYTES_TO_VAR: { if (p_inputs[0]->get_type() != Variant::POOL_BYTE_ARRAY) { r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::POOL_BYTE_ARRAY; return; } if (p_inputs[1]->get_type() != Variant::BOOL) { r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 1; r_error.expected = Variant::BOOL; return; } PoolByteArray varr = *p_inputs[0]; bool allow_objects = *p_inputs[1]; Variant ret; { PoolByteArray::Read r = varr.read(); Error err = decode_variant(ret, r.ptr(), varr.size(), NULL, allow_objects); if (err != OK) { r_error_str = RTR("Not enough bytes for decoding bytes, or invalid format."); r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::POOL_BYTE_ARRAY; return; } } *r_return = ret; } break; case VisualScriptBuiltinFunc::COLORN: { VALIDATE_ARG_NUM(1); Color color = Color::named(*p_inputs[0]); color.a = *p_inputs[1]; *r_return = String(color); } break; default: { } } }
void MultiplayerAPI::_send_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."); ERR_FAIL(); } if (network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_CONNECTING) { ERR_EXPLAIN("Attempt to remote call/set when networking is not connected yet in SceneTree."); ERR_FAIL(); } if (network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED) { ERR_EXPLAIN("Attempt to remote call/set when networking is disconnected."); ERR_FAIL(); } if (p_argcount > 255) { ERR_EXPLAIN("Too many arguments >255."); ERR_FAIL(); } if (p_to != 0 && !connected_peers.has(ABS(p_to))) { if (p_to == network_peer->get_unique_id()) { ERR_EXPLAIN("Attempt to remote call/set yourself! unique ID: " + itos(network_peer->get_unique_id())); } else { ERR_EXPLAIN("Attempt to remote call unexisting ID: " + itos(p_to)); } ERR_FAIL(); } NodePath from_path = (root_node->get_path()).rel_path_to(p_from->get_path()); ERR_EXPLAIN("Unable to send RPC. Relative path is empty. THIS IS LIKELY A BUG IN THE ENGINE!"); ERR_FAIL_COND(from_path.is_empty()); // See if the path is cached. PathSentCache *psc = path_send_cache.getptr(from_path); if (!psc) { // Path is not cached, create. path_send_cache[from_path] = PathSentCache(); psc = path_send_cache.getptr(from_path); psc->id = last_send_cache_id++; } // Create base packet, lots of hardcode 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.write[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.write[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.write[ofs])); ofs += len; if (p_set) { // Set argument. Error err = encode_variant(*p_arg[0], NULL, len, allow_object_decoding || network_peer->is_object_decoding_allowed()); ERR_EXPLAIN("Unable to encode RSET value. THIS IS LIKELY A BUG IN THE ENGINE!"); ERR_FAIL_COND(err != OK); MAKE_ROOM(ofs + len); encode_variant(*p_arg[0], &(packet_cache.write[ofs]), len, allow_object_decoding || network_peer->is_object_decoding_allowed()); ofs += len; } else { // Call arguments. MAKE_ROOM(ofs + 1); packet_cache.write[ofs] = p_argcount; ofs += 1; for (int i = 0; i < p_argcount; i++) { Error err = encode_variant(*p_arg[i], NULL, len, allow_object_decoding || network_peer->is_object_decoding_allowed()); ERR_EXPLAIN("Unable to encode RPC argument. THIS IS LIKELY A BUG IN THE ENGINE!"); ERR_FAIL_COND(err != OK); MAKE_ROOM(ofs + len); encode_variant(*p_arg[i], &(packet_cache.write[ofs]), len, allow_object_decoding || network_peer->is_object_decoding_allowed()); ofs += len; } } // See if all peers have cached path (is so, call can be fast). bool has_all_peers = _send_confirm_path(from_path, psc, p_to); // Take chance and set transfer mode, since all send methods will use it. 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. 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. // Append 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.write[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()) { // This one confirmed path, so use id. encode_uint32(psc->id, &(packet_cache.write[1])); network_peer->put_packet(packet_cache.ptr(), ofs); } else { // This one did not confirm path yet, so use entire path (sorry!). encode_uint32(0x80000000 | ofs, &(packet_cache.write[1])); // Offset to path and flag. network_peer->put_packet(packet_cache.ptr(), ofs + path_len); } } } }
void ScriptDebuggerRemote::_send_object_id(ObjectID p_id) { Object *obj = ObjectDB::get_instance(p_id); if (!obj) return; typedef Pair<PropertyInfo, Variant> PropertyDesc; List<PropertyDesc> properties; if (ScriptInstance *si = obj->get_script_instance()) { if (!si->get_script().is_null()) { Set<StringName> members; si->get_script()->get_members(&members); for (Set<StringName>::Element *E = members.front(); E; E = E->next()) { Variant m; if (si->get(E->get(), m)) { PropertyInfo pi(m.get_type(), String("Members/") + E->get()); properties.push_back(PropertyDesc(pi, m)); } } Map<StringName, Variant> constants; si->get_script()->get_constants(&constants); for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) { PropertyInfo pi(E->value().get_type(), (String("Constants/") + E->key())); properties.push_back(PropertyDesc(pi, E->value())); } } } if (Node *node = Object::cast_to<Node>(obj)) { PropertyInfo pi(Variant::NODE_PATH, String("Node/path")); properties.push_front(PropertyDesc(pi, node->get_path())); } else if (Resource *res = Object::cast_to<Resource>(obj)) { if (Script *s = Object::cast_to<Script>(res)) { Map<StringName, Variant> constants; s->get_constants(&constants); for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) { PropertyInfo pi(E->value().get_type(), String("Constants/") + E->key()); properties.push_front(PropertyDesc(pi, E->value())); } } } List<PropertyInfo> pinfo; obj->get_property_list(&pinfo, true); for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { if (E->get().usage & (PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CATEGORY)) { properties.push_back(PropertyDesc(E->get(), obj->get(E->get().name))); } } Array send_props; for (int i = 0; i < properties.size(); i++) { const PropertyInfo &pi = properties[i].first; Variant &var = properties[i].second; WeakRef *ref = Object::cast_to<WeakRef>(var); if (ref) { var = ref->get_ref(); } RES res = var; Array prop; prop.push_back(pi.name); prop.push_back(pi.type); //only send information that can be sent.. int len = 0; //test how big is this to encode encode_variant(var, NULL, len); if (len > packet_peer_stream->get_output_buffer_max_size()) { //limit to max size prop.push_back(PROPERTY_HINT_OBJECT_TOO_BIG); prop.push_back(""); prop.push_back(pi.usage); prop.push_back(Variant()); } else { prop.push_back(pi.hint); if (res.is_null()) prop.push_back(pi.hint_string); else prop.push_back(String("RES:") + res->get_path()); prop.push_back(pi.usage); prop.push_back(var); } send_props.push_back(prop); } packet_peer_stream->put_var("message:inspect_object"); packet_peer_stream->put_var(3); packet_peer_stream->put_var(p_id); packet_peer_stream->put_var(obj->get_class()); packet_peer_stream->put_var(send_props); }
Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len) { uint8_t *buf = r_buffer; r_len = 0; uint32_t flags = 0; switch (p_variant.get_type()) { case Variant::INT: { int64_t val = p_variant; if (val > 0x7FFFFFFF || val < -0x80000000) { flags |= ENCODE_FLAG_64; } } break; case Variant::REAL: { double d = p_variant; float f = d; if (double(f) != d) { flags |= ENCODE_FLAG_64; //always encode real as double } } break; } if (buf) { encode_uint32(p_variant.get_type() | flags, buf); buf += 4; } r_len += 4; switch (p_variant.get_type()) { case Variant::NIL: { //nothing to do } break; case Variant::BOOL: { if (buf) { encode_uint32(p_variant.operator bool(), buf); } r_len += 4; } break; case Variant::INT: { int64_t val = p_variant; if (val > 0x7FFFFFFF || val < -0x80000000) { //64 bits if (buf) { encode_uint64(val, buf); } r_len += 8; } else { if (buf) { encode_uint32(int32_t(val), buf); } r_len += 4; } } break; case Variant::REAL: { double d = p_variant; float f = d; if (double(f) != d) { if (buf) { encode_double(p_variant.operator double(), buf); } r_len += 8; } else { if (buf) { encode_float(p_variant.operator float(), buf); } r_len += 4; } } break; case Variant::NODE_PATH: { NodePath np = p_variant; if (buf) { encode_uint32(uint32_t(np.get_name_count()) | 0x80000000, buf); //for compatibility with the old format encode_uint32(np.get_subname_count(), buf + 4); uint32_t flags = 0; if (np.is_absolute()) flags |= 1; if (np.get_property() != StringName()) flags |= 2; encode_uint32(flags, buf + 8); buf += 12; } r_len += 12; int total = np.get_name_count() + np.get_subname_count(); if (np.get_property() != StringName()) total++; for (int i = 0; i < total; i++) { String str; if (i < np.get_name_count()) str = np.get_name(i); else if (i < np.get_name_count() + np.get_subname_count()) str = np.get_subname(i - np.get_subname_count()); else str = np.get_property(); CharString utf8 = str.utf8(); int pad = 0; if (utf8.length() % 4) pad = 4 - utf8.length() % 4; if (buf) { encode_uint32(utf8.length(), buf); buf += 4; copymem(buf, utf8.get_data(), utf8.length()); buf += pad + utf8.length(); } r_len += 4 + utf8.length() + pad; } } break; case Variant::STRING: { CharString utf8 = p_variant.operator String().utf8(); if (buf) { encode_uint32(utf8.length(), buf); buf += 4; copymem(buf, utf8.get_data(), utf8.length()); } r_len += 4 + utf8.length(); while (r_len % 4) r_len++; //pad } break; // math types case Variant::VECTOR2: { if (buf) { Vector2 v2 = p_variant; encode_float(v2.x, &buf[0]); encode_float(v2.y, &buf[4]); } r_len += 2 * 4; } break; // 5 case Variant::RECT2: { if (buf) { Rect2 r2 = p_variant; encode_float(r2.position.x, &buf[0]); encode_float(r2.position.y, &buf[4]); encode_float(r2.size.x, &buf[8]); encode_float(r2.size.y, &buf[12]); } r_len += 4 * 4; } break; case Variant::VECTOR3: { if (buf) { Vector3 v3 = p_variant; encode_float(v3.x, &buf[0]); encode_float(v3.y, &buf[4]); encode_float(v3.z, &buf[8]); } r_len += 3 * 4; } break; case Variant::TRANSFORM2D: { if (buf) { Transform2D val = p_variant; for (int i = 0; i < 3; i++) { for (int j = 0; j < 2; j++) { copymem(&buf[(i * 2 + j) * 4], &val.elements[i][j], sizeof(float)); } } } r_len += 6 * 4; } break; case Variant::PLANE: { if (buf) { Plane p = p_variant; encode_float(p.normal.x, &buf[0]); encode_float(p.normal.y, &buf[4]); encode_float(p.normal.z, &buf[8]); encode_float(p.d, &buf[12]); } r_len += 4 * 4; } break; case Variant::QUAT: { if (buf) { Quat q = p_variant; encode_float(q.x, &buf[0]); encode_float(q.y, &buf[4]); encode_float(q.z, &buf[8]); encode_float(q.w, &buf[12]); } r_len += 4 * 4; } break; case Variant::RECT3: { if (buf) { Rect3 aabb = p_variant; encode_float(aabb.position.x, &buf[0]); encode_float(aabb.position.y, &buf[4]); encode_float(aabb.position.z, &buf[8]); encode_float(aabb.size.x, &buf[12]); encode_float(aabb.size.y, &buf[16]); encode_float(aabb.size.z, &buf[20]); } r_len += 6 * 4; } break; case Variant::BASIS: { if (buf) { Basis val = p_variant; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { copymem(&buf[(i * 3 + j) * 4], &val.elements[i][j], sizeof(float)); } } } r_len += 9 * 4; } break; case Variant::TRANSFORM: { if (buf) { Transform val = p_variant; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { copymem(&buf[(i * 3 + j) * 4], &val.basis.elements[i][j], sizeof(float)); } } encode_float(val.origin.x, &buf[36]); encode_float(val.origin.y, &buf[40]); encode_float(val.origin.z, &buf[44]); } r_len += 12 * 4; } break; // misc types case Variant::COLOR: { if (buf) { Color c = p_variant; encode_float(c.r, &buf[0]); encode_float(c.g, &buf[4]); encode_float(c.b, &buf[8]); encode_float(c.a, &buf[12]); } r_len += 4 * 4; } break; /*case Variant::RESOURCE: { ERR_EXPLAIN("Can't marshallize resources"); ERR_FAIL_V(ERR_INVALID_DATA); //no, i'm sorry, no go } break;*/ case Variant::_RID: case Variant::OBJECT: { } break; case Variant::DICTIONARY: { Dictionary d = p_variant; if (buf) { encode_uint32(uint32_t(d.size()), buf); buf += 4; } r_len += 4; List<Variant> keys; d.get_key_list(&keys); for (List<Variant>::Element *E = keys.front(); E; E = E->next()) { /* CharString utf8 = E->->utf8(); if (buf) { encode_uint32(utf8.length()+1,buf); buf+=4; copymem(buf,utf8.get_data(),utf8.length()+1); } r_len+=4+utf8.length()+1; while (r_len%4) r_len++; //pad */ int len; encode_variant(E->get(), buf, len); ERR_FAIL_COND_V(len % 4, ERR_BUG); r_len += len; if (buf) buf += len; encode_variant(d[E->get()], buf, len); ERR_FAIL_COND_V(len % 4, ERR_BUG); r_len += len; if (buf) buf += len; } } break; case Variant::ARRAY: { Array v = p_variant; if (buf) { encode_uint32(uint32_t(v.size()), buf); buf += 4; } r_len += 4; for (int i = 0; i < v.size(); i++) { int len; encode_variant(v.get(i), buf, len); ERR_FAIL_COND_V(len % 4, ERR_BUG); r_len += len; if (buf) buf += len; } } break; // arrays case Variant::POOL_BYTE_ARRAY: { PoolVector<uint8_t> data = p_variant; int datalen = data.size(); int datasize = sizeof(uint8_t); if (buf) { encode_uint32(datalen, buf); buf += 4; PoolVector<uint8_t>::Read r = data.read(); copymem(buf, &r[0], datalen * datasize); } r_len += 4 + datalen * datasize; while (r_len % 4) r_len++; } break; case Variant::POOL_INT_ARRAY: { PoolVector<int> data = p_variant; int datalen = data.size(); int datasize = sizeof(int32_t); if (buf) { encode_uint32(datalen, buf); buf += 4; PoolVector<int>::Read r = data.read(); for (int i = 0; i < datalen; i++) encode_uint32(r[i], &buf[i * datasize]); } r_len += 4 + datalen * datasize; } break; case Variant::POOL_REAL_ARRAY: { PoolVector<real_t> data = p_variant; int datalen = data.size(); int datasize = sizeof(real_t); if (buf) { encode_uint32(datalen, buf); buf += 4; PoolVector<real_t>::Read r = data.read(); for (int i = 0; i < datalen; i++) encode_float(r[i], &buf[i * datasize]); } r_len += 4 + datalen * datasize; } break; case Variant::POOL_STRING_ARRAY: { PoolVector<String> data = p_variant; int len = data.size(); if (buf) { encode_uint32(len, buf); buf += 4; } r_len += 4; for (int i = 0; i < len; i++) { CharString utf8 = data.get(i).utf8(); if (buf) { encode_uint32(utf8.length() + 1, buf); buf += 4; copymem(buf, utf8.get_data(), utf8.length() + 1); buf += utf8.length() + 1; } r_len += 4 + utf8.length() + 1; while (r_len % 4) { r_len++; //pad if (buf) buf++; } } } break; case Variant::POOL_VECTOR2_ARRAY: { PoolVector<Vector2> data = p_variant; int len = data.size(); if (buf) { encode_uint32(len, buf); buf += 4; } r_len += 4; if (buf) { for (int i = 0; i < len; i++) { Vector2 v = data.get(i); encode_float(v.x, &buf[0]); encode_float(v.y, &buf[4]); buf += 4 * 2; } } r_len += 4 * 2 * len; } break; case Variant::POOL_VECTOR3_ARRAY: { PoolVector<Vector3> data = p_variant; int len = data.size(); if (buf) { encode_uint32(len, buf); buf += 4; } r_len += 4; if (buf) { for (int i = 0; i < len; i++) { Vector3 v = data.get(i); encode_float(v.x, &buf[0]); encode_float(v.y, &buf[4]); encode_float(v.z, &buf[8]); buf += 4 * 3; } } r_len += 4 * 3 * len; } break; case Variant::POOL_COLOR_ARRAY: { PoolVector<Color> data = p_variant; int len = data.size(); if (buf) { encode_uint32(len, buf); buf += 4; } r_len += 4; if (buf) { for (int i = 0; i < len; i++) { Color c = data.get(i); encode_float(c.r, &buf[0]); encode_float(c.g, &buf[4]); encode_float(c.b, &buf[8]); encode_float(c.a, &buf[12]); buf += 4 * 4; } } r_len += 4 * 4 * len; } break; default: { ERR_FAIL_V(ERR_BUG); } } return OK; }
virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { switch(func) { case VisualScriptBuiltinFunc::MATH_SIN: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::sin(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_COS: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::cos(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_TAN: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::tan(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_SINH: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::sinh(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_COSH: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::cosh(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_TANH: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::tanh(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_ASIN: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::asin(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_ACOS: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::acos(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_ATAN: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::atan(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_ATAN2: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); *p_outputs[0]=Math::atan2(*p_inputs[0],*p_inputs[1]); } break; case VisualScriptBuiltinFunc::MATH_SQRT: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::sqrt(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_FMOD: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); *p_outputs[0]=Math::fmod(*p_inputs[0],*p_inputs[1]); } break; case VisualScriptBuiltinFunc::MATH_FPOSMOD: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); *p_outputs[0]=Math::fposmod(*p_inputs[0],*p_inputs[1]); } break; case VisualScriptBuiltinFunc::MATH_FLOOR: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::floor(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_CEIL: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::ceil(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_ROUND: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::round(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_ABS: { if (p_inputs[0]->get_type()==Variant::INT) { int64_t i = *p_inputs[0]; *p_outputs[0]=ABS(i); } else if (p_inputs[0]->get_type()==Variant::REAL) { real_t r = *p_inputs[0]; *p_outputs[0]=Math::abs(r); } else { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::REAL; } } break; case VisualScriptBuiltinFunc::MATH_SIGN: { if (p_inputs[0]->get_type()==Variant::INT) { int64_t i = *p_inputs[0]; *p_outputs[0]= i < 0 ? -1 : ( i > 0 ? +1 : 0); } else if (p_inputs[0]->get_type()==Variant::REAL) { real_t r = *p_inputs[0]; *p_outputs[0]= r < 0.0 ? -1.0 : ( r > 0.0 ? +1.0 : 0.0); } else { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::REAL; } } break; case VisualScriptBuiltinFunc::MATH_POW: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); *p_outputs[0]=Math::pow(*p_inputs[0],*p_inputs[1]); } break; case VisualScriptBuiltinFunc::MATH_LOG: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::log(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_EXP: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::exp(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_ISNAN: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::is_nan(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_ISINF: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::is_inf(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_EASE: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); *p_outputs[0]=Math::ease(*p_inputs[0],*p_inputs[1]); } break; case VisualScriptBuiltinFunc::MATH_DECIMALS: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::step_decimals(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_STEPIFY: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); *p_outputs[0]=Math::stepify(*p_inputs[0],*p_inputs[1]); } break; case VisualScriptBuiltinFunc::MATH_LERP: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); VALIDATE_ARG_NUM(2); *p_outputs[0]=Math::lerp(*p_inputs[0],*p_inputs[1],*p_inputs[2]); } break; case VisualScriptBuiltinFunc::MATH_DECTIME: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); VALIDATE_ARG_NUM(2); *p_outputs[0]=Math::dectime(*p_inputs[0],*p_inputs[1],*p_inputs[2]); } break; case VisualScriptBuiltinFunc::MATH_RANDOMIZE: { Math::randomize(); } break; case VisualScriptBuiltinFunc::MATH_RAND: { *p_outputs[0]=Math::rand(); } break; case VisualScriptBuiltinFunc::MATH_RANDF: { *p_outputs[0]=Math::randf(); } break; case VisualScriptBuiltinFunc::MATH_RANDOM: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); *p_outputs[0]=Math::random(*p_inputs[0],*p_inputs[1]); } break; case VisualScriptBuiltinFunc::MATH_SEED: { VALIDATE_ARG_NUM(0); uint32_t seed=*p_inputs[0]; Math::seed(seed); } break; case VisualScriptBuiltinFunc::MATH_RANDSEED: { VALIDATE_ARG_NUM(0); uint32_t seed=*p_inputs[0]; int ret = Math::rand_from_seed(&seed); Array reta; reta.push_back(ret); reta.push_back(seed); *p_outputs[0]=reta; } break; case VisualScriptBuiltinFunc::MATH_DEG2RAD: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::deg2rad(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_RAD2DEG: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::rad2deg(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_LINEAR2DB: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::linear2db(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::MATH_DB2LINEAR: { VALIDATE_ARG_NUM(0); *p_outputs[0]=Math::db2linear(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::LOGIC_MAX: { if (p_inputs[0]->get_type()==Variant::INT && p_inputs[1]->get_type()==Variant::INT) { int64_t a = *p_inputs[0]; int64_t b = *p_inputs[1]; *p_outputs[0]=MAX(a,b); } else { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); real_t a = *p_inputs[0]; real_t b = *p_inputs[1]; *p_outputs[0]=MAX(a,b); } } break; case VisualScriptBuiltinFunc::LOGIC_MIN: { if (p_inputs[0]->get_type()==Variant::INT && p_inputs[1]->get_type()==Variant::INT) { int64_t a = *p_inputs[0]; int64_t b = *p_inputs[1]; *p_outputs[0]=MIN(a,b); } else { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); real_t a = *p_inputs[0]; real_t b = *p_inputs[1]; *p_outputs[0]=MIN(a,b); } } break; case VisualScriptBuiltinFunc::LOGIC_CLAMP: { if (p_inputs[0]->get_type()==Variant::INT && p_inputs[1]->get_type()==Variant::INT && p_inputs[2]->get_type()==Variant::INT) { int64_t a = *p_inputs[0]; int64_t b = *p_inputs[1]; int64_t c = *p_inputs[2]; *p_outputs[0]=CLAMP(a,b,c); } else { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); VALIDATE_ARG_NUM(2); real_t a = *p_inputs[0]; real_t b = *p_inputs[1]; real_t c = *p_inputs[2]; *p_outputs[0]=CLAMP(a,b,c); } } break; case VisualScriptBuiltinFunc::LOGIC_NEAREST_PO2: { VALIDATE_ARG_NUM(0); int64_t num = *p_inputs[0]; *p_outputs[0] = nearest_power_of_2(num); } break; case VisualScriptBuiltinFunc::OBJ_WEAKREF: { if (p_inputs[0]->get_type()!=Variant::OBJECT) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::OBJECT; return 0; } if (p_inputs[0]->is_ref()) { REF r = *p_inputs[0]; if (!r.is_valid()) { return 0; } Ref<WeakRef> wref = memnew( WeakRef ); wref->set_ref(r); *p_outputs[0]=wref; } else { Object *obj = *p_inputs[0]; if (!obj) { return 0; } Ref<WeakRef> wref = memnew( WeakRef ); wref->set_obj(obj); *p_outputs[0]=wref; } } break; case VisualScriptBuiltinFunc::FUNC_FUNCREF: { if (p_inputs[0]->get_type()!=Variant::OBJECT) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::OBJECT; return 0; } if (p_inputs[1]->get_type()!=Variant::STRING && p_inputs[1]->get_type()!=Variant::NODE_PATH) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=1; r_error.expected=Variant::STRING; return 0; } Ref<FuncRef> fr = memnew( FuncRef); fr->set_instance(*p_inputs[0]); fr->set_function(*p_inputs[1]); *p_outputs[0]=fr; } break; case VisualScriptBuiltinFunc::TYPE_CONVERT: { VALIDATE_ARG_NUM(1); int type=*p_inputs[1]; if (type<0 || type>=Variant::VARIANT_MAX) { *p_outputs[0]=RTR("Invalid type argument to convert(), use TYPE_* constants."); r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::INT; return 0; } else { *p_outputs[0]=Variant::construct(Variant::Type(type),p_inputs,1,r_error); } } break; case VisualScriptBuiltinFunc::TYPE_OF: { *p_outputs[0] = p_inputs[0]->get_type(); } break; case VisualScriptBuiltinFunc::TYPE_EXISTS: { *p_outputs[0] = ObjectTypeDB::type_exists(*p_inputs[0]); } break; case VisualScriptBuiltinFunc::TEXT_STR: { String str = *p_inputs[0]; *p_outputs[0]=str; } break; case VisualScriptBuiltinFunc::TEXT_PRINT: { String str = *p_inputs[0]; print_line(str); } break; case VisualScriptBuiltinFunc::TEXT_PRINTERR: { String str = *p_inputs[0]; //str+="\n"; OS::get_singleton()->printerr("%s\n",str.utf8().get_data()); } break; case VisualScriptBuiltinFunc::TEXT_PRINTRAW: { String str = *p_inputs[0]; //str+="\n"; OS::get_singleton()->print("%s",str.utf8().get_data()); } break; case VisualScriptBuiltinFunc::VAR_TO_STR: { String vars; VariantWriter::write_to_string(*p_inputs[0],vars); *p_outputs[0]=vars; } break; case VisualScriptBuiltinFunc::STR_TO_VAR: { if (p_inputs[0]->get_type()!=Variant::STRING) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::STRING; return 0; } VariantParser::StreamString ss; ss.s=*p_inputs[0]; String errs; int line; Error err = VariantParser::parse(&ss,*p_outputs[0],errs,line); if (err!=OK) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::STRING; *p_outputs[0]="Parse error at line "+itos(line)+": "+errs; return 0; } } break; case VisualScriptBuiltinFunc::VAR_TO_BYTES: { ByteArray barr; int len; Error err = encode_variant(*p_inputs[0],NULL,len); if (err) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::NIL; *p_outputs[0]="Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID)."; return 0; } barr.resize(len); { ByteArray::Write w = barr.write(); encode_variant(*p_inputs[0],w.ptr(),len); } *p_outputs[0]=barr; } break; case VisualScriptBuiltinFunc::BYTES_TO_VAR: { if (p_inputs[0]->get_type()!=Variant::RAW_ARRAY) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::RAW_ARRAY; return 0; } ByteArray varr=*p_inputs[0]; Variant ret; { ByteArray::Read r=varr.read(); Error err = decode_variant(ret,r.ptr(),varr.size(),NULL); if (err!=OK) { *p_outputs[0]=RTR("Not enough bytes for decoding bytes, or invalid format."); r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=0; r_error.expected=Variant::RAW_ARRAY; return 0; } } *p_outputs[0]=ret; } break; default: {} } return 0; }
uint32_t PackedDataContainer::_pack(const Variant &p_data, Vector<uint8_t> &tmpdata, Map<String, uint32_t> &string_cache) { switch (p_data.get_type()) { case Variant::STRING: { String s = p_data; if (string_cache.has(s)) { return string_cache[s]; } string_cache[s] = tmpdata.size(); }; //fallthrough case Variant::NIL: case Variant::BOOL: case Variant::INT: case Variant::REAL: case Variant::VECTOR2: case Variant::RECT2: case Variant::VECTOR3: case Variant::TRANSFORM2D: case Variant::PLANE: case Variant::QUAT: case Variant::AABB: case Variant::BASIS: case Variant::TRANSFORM: case Variant::POOL_BYTE_ARRAY: case Variant::POOL_INT_ARRAY: case Variant::POOL_REAL_ARRAY: case Variant::POOL_STRING_ARRAY: case Variant::POOL_VECTOR2_ARRAY: case Variant::POOL_VECTOR3_ARRAY: case Variant::POOL_COLOR_ARRAY: case Variant::NODE_PATH: { uint32_t pos = tmpdata.size(); int len; encode_variant(p_data, NULL, len); tmpdata.resize(tmpdata.size() + len); encode_variant(p_data, &tmpdata[pos], len); return pos; } break; // misc types case Variant::_RID: case Variant::OBJECT: { return _pack(Variant(), tmpdata, string_cache); } break; case Variant::DICTIONARY: { Dictionary d = p_data; //size is known, use sort uint32_t pos = tmpdata.size(); int len = d.size(); tmpdata.resize(tmpdata.size() + len * 12 + 8); encode_uint32(TYPE_DICT, &tmpdata[pos + 0]); encode_uint32(len, &tmpdata[pos + 4]); List<Variant> keys; d.get_key_list(&keys); List<DictKey> sortk; for (List<Variant>::Element *E = keys.front(); E; E = E->next()) { DictKey dk; dk.hash = E->get().hash(); dk.key = E->get(); sortk.push_back(dk); } sortk.sort(); int idx = 0; for (List<DictKey>::Element *E = sortk.front(); E; E = E->next()) { encode_uint32(E->get().hash, &tmpdata[pos + 8 + idx * 12 + 0]); uint32_t ofs = _pack(E->get().key, tmpdata, string_cache); encode_uint32(ofs, &tmpdata[pos + 8 + idx * 12 + 4]); ofs = _pack(d[E->get().key], tmpdata, string_cache); encode_uint32(ofs, &tmpdata[pos + 8 + idx * 12 + 8]); idx++; } return pos; } break; case Variant::ARRAY: { Array a = p_data; //size is known, use sort uint32_t pos = tmpdata.size(); int len = a.size(); tmpdata.resize(tmpdata.size() + len * 4 + 8); encode_uint32(TYPE_ARRAY, &tmpdata[pos + 0]); encode_uint32(len, &tmpdata[pos + 4]); for (int i = 0; i < len; i++) { uint32_t ofs = _pack(a[i], tmpdata, string_cache); encode_uint32(ofs, &tmpdata[pos + 8 + i * 4]); } return pos; } break; default: {} } return OK; }