aboutsummaryrefslogtreecommitdiff
path: root/modules/gdscript/gd_functions.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdscript/gd_functions.cpp')
-rw-r--r--modules/gdscript/gd_functions.cpp253
1 files changed, 211 insertions, 42 deletions
diff --git a/modules/gdscript/gd_functions.cpp b/modules/gdscript/gd_functions.cpp
index 1c05a71d0..1c41b2e73 100644
--- a/modules/gdscript/gd_functions.cpp
+++ b/modules/gdscript/gd_functions.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -35,6 +35,7 @@
#include "os/os.h"
#include "variant_parser.h"
#include "io/marshalls.h"
+#include "io/json.h"
const char *GDFunctions::get_func_name(Function p_func) {
@@ -87,6 +88,8 @@ const char *GDFunctions::get_func_name(Function p_func) {
"funcref",
"convert",
"typeof",
+ "type_exists",
+ "char",
"str",
"print",
"printt",
@@ -101,8 +104,12 @@ const char *GDFunctions::get_func_name(Function p_func) {
"load",
"inst2dict",
"dict2inst",
+ "validate_json",
+ "parse_json",
+ "to_json",
"hash",
"Color8",
+ "ColorN",
"print_stack",
"instance_from_id",
};
@@ -120,11 +127,13 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
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;\
}
@@ -133,6 +142,7 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;\
r_error.argument=m_arg;\
r_error.expected=Variant::REAL;\
+ r_ret=Variant();\
return;\
}
@@ -244,6 +254,7 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
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: {
@@ -261,6 +272,7 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
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: {
@@ -298,7 +310,7 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
case MATH_DECIMALS: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::decimals(*p_args[0]);
+ r_ret=Math::step_decimals(*p_args[0]);
} break;
case MATH_STEPIFY: {
VALIDATE_ARG_COUNT(2);
@@ -442,6 +454,7 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument=0;
r_error.expected=Variant::OBJECT;
+ r_ret=Variant();
return;
}
@@ -479,7 +492,7 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument=0;
r_error.expected=Variant::OBJECT;
- r_ret=Variant();
+ r_ret=Variant();
return;
}
@@ -495,7 +508,6 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
Ref<FuncRef> fr = memnew( FuncRef);
- Object *obj = *p_args[0];
fr->set_instance(*p_args[0]);
fr->set_function(*p_args[1]);
@@ -508,8 +520,11 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
int type=*p_args[1];
if (type<0 || type>=Variant::VARIANT_MAX) {
- ERR_PRINT("Invalid type argument to convert()");
- r_ret=Variant::NIL;
+ 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 {
@@ -523,6 +538,18 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
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;
@@ -638,27 +665,28 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument=0;
r_error.expected=Variant::STRING;
- r_ret=Variant();
+ r_ret="Parse error at line "+itos(line)+": "+errs;
+ return;
}
} break;
case VAR_TO_BYTES: {
VALIDATE_ARG_COUNT(1);
- ByteArray barr;
+ 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=Variant();
+ r_ret="Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID).";
return;
}
barr.resize(len);
{
- ByteArray::Write w = barr.write();
+ PoolByteArray::Write w = barr.write();
encode_variant(*p_args[0],w.ptr(),len);
}
@@ -666,25 +694,24 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
} break;
case BYTES_TO_VAR: {
VALIDATE_ARG_COUNT(1);
- if (p_args[0]->get_type()!=Variant::RAW_ARRAY) {
+ 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::RAW_ARRAY;
+ r_error.expected=Variant::POOL_BYTE_ARRAY;
r_ret=Variant();
return;
}
- ByteArray varr=*p_args[0];
+ PoolByteArray varr=*p_args[0];
Variant ret;
{
- ByteArray::Read r=varr.read();
+ PoolByteArray::Read r=varr.read();
Error err = decode_variant(ret,r.ptr(),varr.size(),NULL);
if (err!=OK) {
- ERR_PRINT("Not enough bytes for decoding..");
+ 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::RAW_ARRAY;
- r_ret=Variant();
+ r_error.expected=Variant::POOL_BYTE_ARRAY;
return;
}
@@ -701,13 +728,14 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
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(true);
+ Array arr;
if (count<=0) {
r_ret=arr;
return;
@@ -733,7 +761,7 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
int from=*p_args[0];
int to=*p_args[1];
- Array arr(true);
+ Array arr;
if (from>=to) {
r_ret=arr;
return;
@@ -759,12 +787,12 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
int incr=*p_args[2];
if (incr==0) {
- ERR_EXPLAIN("step argument is zero!");
+ r_ret=RTR("step argument is zero!");
r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
- ERR_FAIL();
+ return;
}
- Array arr(true);
+ Array arr;
if (from>=to && incr>0) {
r_ret=arr;
return;
@@ -812,6 +840,8 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
r_error.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.argument=3;
+ r_ret=Variant();
+
} break;
}
@@ -821,9 +851,11 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
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]);
}
- r_ret=ResourceLoader::load(*p_args[0]);
} break;
case INST2DICT: {
@@ -847,8 +879,8 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument=0;
r_error.expected=Variant::DICTIONARY;
- ERR_PRINT("Not a script with an instance");
-
+ r_ret=RTR("Not a script with an instance");
+ return;
} else {
GDInstance *ins = static_cast<GDInstance*>(obj->get_script_instance());
@@ -858,7 +890,7 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument=0;
r_error.expected=Variant::DICTIONARY;
- ERR_PRINT("Not based on a script");
+ r_ret=RTR("Not based on a script");
return;
}
@@ -879,15 +911,17 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument=0;
r_error.expected=Variant::DICTIONARY;
- print_line("PATH: "+p->path);
- ERR_PRINT("Not based on a resource file");
+ r_ret=Variant();
+
+
+ r_ret=RTR("Not based on a resource file");
return;
}
NodePath cp(sname,Vector<StringName>(),false);
- Dictionary d(true);
+ Dictionary d;
d["@subpath"]=cp;
d["@path"]=p->path;
@@ -926,6 +960,8 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument=0;
r_error.expected=Variant::DICTIONARY;
+ r_ret=Variant();
+
return;
}
@@ -936,6 +972,8 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
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;
}
@@ -945,6 +983,7 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
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;
}
@@ -955,6 +994,8 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
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;
}
@@ -971,22 +1012,75 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
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();
+ 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);
- 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()];
- }
- }
+ 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);
@@ -998,11 +1092,15 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
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;
}
@@ -1010,16 +1108,46 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
VALIDATE_ARG_NUM(1);
VALIDATE_ARG_NUM(2);
- Color color(*p_args[0],*p_args[1],*p_args[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=*p_args[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: {
@@ -1036,6 +1164,7 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
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;
}
@@ -1098,6 +1227,8 @@ bool GDFunctions::is_deterministic(Function p_func) {
case LOGIC_NEAREST_PO2:
case TYPE_CONVERT:
case TYPE_OF:
+ case TYPE_EXISTS:
+ case TEXT_CHAR:
case TEXT_STR:
case COLOR8:
// enable for debug only, otherwise not desirable - case GEN_RANGE:
@@ -1281,12 +1412,12 @@ MethodInfo GDFunctions::get_info(Function p_func) {
return mi;
} break;
case MATH_SEED: {
- MethodInfo mi("seed",PropertyInfo(Variant::REAL,"seed"));
+ MethodInfo mi("seed",PropertyInfo(Variant::INT,"seed"));
mi.return_val.type=Variant::NIL;
return mi;
} break;
case MATH_RANDSEED: {
- MethodInfo mi("rand_seed",PropertyInfo(Variant::REAL,"seed"));
+ MethodInfo mi("rand_seed",PropertyInfo(Variant::INT,"seed"));
mi.return_val.type=Variant::ARRAY;
return mi;
} break;
@@ -1361,6 +1492,20 @@ MethodInfo GDFunctions::get_info(Function p_func) {
return mi;
} break;
+ case TYPE_EXISTS: {
+
+ MethodInfo mi("type_exists",PropertyInfo(Variant::STRING,"type"));
+ mi.return_val.type=Variant::BOOL;
+ return mi;
+
+ } break;
+ case TEXT_CHAR: {
+
+ MethodInfo mi("char",PropertyInfo(Variant::INT,"ascii"));
+ mi.return_val.type=Variant::STRING;
+ return mi;
+
+ } break;
case TEXT_STR: {
MethodInfo mi("str",PropertyInfo(Variant::NIL,"what"),PropertyInfo(Variant::NIL,"..."));
@@ -1417,13 +1562,13 @@ MethodInfo GDFunctions::get_info(Function p_func) {
} break;
case VAR_TO_BYTES: {
MethodInfo mi("var2bytes",PropertyInfo(Variant::NIL,"var"));
- mi.return_val.type=Variant::RAW_ARRAY;
+ mi.return_val.type=Variant::POOL_BYTE_ARRAY;
return mi;
} break;
case BYTES_TO_VAR: {
- MethodInfo mi("bytes2var:Variant",PropertyInfo(Variant::RAW_ARRAY,"bytes"));
+ MethodInfo mi("bytes2var:Variant",PropertyInfo(Variant::POOL_BYTE_ARRAY,"bytes"));
mi.return_val.type=Variant::NIL;
return mi;
} break;
@@ -1452,6 +1597,24 @@ MethodInfo GDFunctions::get_info(Function p_func) {
mi.return_val.type=Variant::OBJECT;
return mi;
} break;
+ case VALIDATE_JSON: {
+
+ MethodInfo mi("validate_json:Variant",PropertyInfo(Variant::STRING,"json"));
+ mi.return_val.type=Variant::STRING;
+ return mi;
+ } break;
+ case PARSE_JSON: {
+
+ MethodInfo mi("parse_json:Variant",PropertyInfo(Variant::STRING,"json"));
+ mi.return_val.type=Variant::NIL;
+ return mi;
+ } break;
+ case TO_JSON: {
+
+ MethodInfo mi("to_json",PropertyInfo(Variant::NIL,"var:Variant"));
+ mi.return_val.type=Variant::STRING;
+ return mi;
+ } break;
case HASH: {
MethodInfo mi("hash",PropertyInfo(Variant::NIL,"var:Variant"));
@@ -1464,6 +1627,12 @@ MethodInfo GDFunctions::get_info(Function p_func) {
mi.return_val.type=Variant::COLOR;
return mi;
} break;
+ case COLORN: {
+
+ MethodInfo mi("ColorN",PropertyInfo(Variant::STRING,"name"),PropertyInfo(Variant::REAL,"alpha"));
+ mi.return_val.type=Variant::COLOR;
+ return mi;
+ } break;
case PRINT_STACK: {
MethodInfo mi("print_stack");