diff options
Diffstat (limited to 'modules/gdscript')
| -rw-r--r-- | modules/gdscript/config.py | 2 | ||||
| -rw-r--r-- | modules/gdscript/doc_classes/GDScript.xml | 2 | ||||
| -rw-r--r-- | modules/gdscript/editor/gdscript_highlighter.cpp | 20 | ||||
| -rw-r--r-- | modules/gdscript/gdscript.cpp | 58 | ||||
| -rw-r--r-- | modules/gdscript/gdscript.h | 11 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_compiler.cpp | 40 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_editor.cpp | 33 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_function.cpp | 22 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_function.h | 14 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_functions.cpp | 48 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_functions.h | 2 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_parser.cpp | 86 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_parser.h | 8 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_tokenizer.cpp | 13 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_tokenizer.h | 4 |
15 files changed, 300 insertions, 63 deletions
diff --git a/modules/gdscript/config.py b/modules/gdscript/config.py index 6496b59d75..95b40d90af 100644 --- a/modules/gdscript/config.py +++ b/modules/gdscript/config.py @@ -1,4 +1,4 @@ -def can_build(platform): +def can_build(env, platform): return True def configure(env): diff --git a/modules/gdscript/doc_classes/GDScript.xml b/modules/gdscript/doc_classes/GDScript.xml index 40a435f459..632970f8c0 100644 --- a/modules/gdscript/doc_classes/GDScript.xml +++ b/modules/gdscript/doc_classes/GDScript.xml @@ -8,7 +8,7 @@ [method new] creates a new instance of the script. [method Object.set_script] extends an existing object, if that object's class matches one of the script's base classes. </description> <tutorials> - http://docs.godotengine.org/en/3.0/getting_started/scripting/gdscript/index.html + <link>http://docs.godotengine.org/en/3.0/getting_started/scripting/gdscript/index.html</link> </tutorials> <demos> </demos> diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp index ea3efff9cf..fedc510f01 100644 --- a/modules/gdscript/editor/gdscript_highlighter.cpp +++ b/modules/gdscript/editor/gdscript_highlighter.cpp @@ -312,8 +312,24 @@ void GDScriptSyntaxHighlighter::_update_cache() { number_color = text_editor->get_color("number_color"); member_color = text_editor->get_color("member_variable_color"); - function_definition_color = EDITOR_DEF("text_editor/highlighting/gdscript/function_definition_color", Color::html("#01e1ff")); - node_path_color = EDITOR_DEF("text_editor/highlighting/gdscript/node_path_color", Color::html("#64c15a")); + EditorSettings *settings = EditorSettings::get_singleton(); + String text_editor_color_theme = settings->get("text_editor/theme/color_theme"); + + bool default_theme = text_editor_color_theme == "Default"; + bool dark_theme = settings->is_dark_theme(); + + function_definition_color = Color::html(default_theme ? "#01e1ff" : dark_theme ? "#01e1ff" : "#00a5ba"); + node_path_color = Color::html(default_theme ? "#64c15a" : dark_theme ? "64c15a" : "#518b4b"); + + EDITOR_DEF("text_editor/highlighting/gdscript/function_definition_color", function_definition_color); + EDITOR_DEF("text_editor/highlighting/gdscript/node_path_color", node_path_color); + if (text_editor_color_theme == "Adaptive" || default_theme) { + settings->set_initial_value("text_editor/highlighting/gdscript/function_definition_color", function_definition_color, true); + settings->set_initial_value("text_editor/highlighting/gdscript/node_path_color", node_path_color, true); + } + + function_definition_color = EDITOR_GET("text_editor/highlighting/gdscript/function_definition_color"); + node_path_color = EDITOR_GET("text_editor/highlighting/gdscript/node_path_color"); } SyntaxHighlighter *GDScriptSyntaxHighlighter::create() { diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 14bdce50ec..b3ebd4fe4b 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -1220,7 +1220,7 @@ ScriptLanguage *GDScriptInstance::get_language() { return GDScriptLanguage::get_singleton(); } -GDScriptInstance::RPCMode GDScriptInstance::get_rpc_mode(const StringName &p_method) const { +MultiplayerAPI::RPCMode GDScriptInstance::get_rpc_mode(const StringName &p_method) const { const GDScript *cscript = script.ptr(); @@ -1228,17 +1228,17 @@ GDScriptInstance::RPCMode GDScriptInstance::get_rpc_mode(const StringName &p_met const Map<StringName, GDScriptFunction *>::Element *E = cscript->member_functions.find(p_method); if (E) { - if (E->get()->get_rpc_mode() != RPC_MODE_DISABLED) { + if (E->get()->get_rpc_mode() != MultiplayerAPI::RPC_MODE_DISABLED) { return E->get()->get_rpc_mode(); } } cscript = cscript->_base; } - return RPC_MODE_DISABLED; + return MultiplayerAPI::RPC_MODE_DISABLED; } -GDScriptInstance::RPCMode GDScriptInstance::get_rset_mode(const StringName &p_variable) const { +MultiplayerAPI::RPCMode GDScriptInstance::get_rset_mode(const StringName &p_variable) const { const GDScript *cscript = script.ptr(); @@ -1253,7 +1253,7 @@ GDScriptInstance::RPCMode GDScriptInstance::get_rset_mode(const StringName &p_va cscript = cscript->_base; } - return RPC_MODE_DISABLED; + return MultiplayerAPI::RPC_MODE_DISABLED; } void GDScriptInstance::reload_members() { @@ -1739,6 +1739,7 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const { "assert", "breakpoint", "class", + "class_name", "extends", "is", "func", @@ -1769,6 +1770,9 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const { "sync", "master", "slave", + "remotesync", + "mastersync", + "slavesync", 0 }; @@ -1785,6 +1789,50 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const { } } +bool GDScriptLanguage::handles_global_class_type(const String &p_type) const { + + return p_type == "GDScript"; +} + +String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_base_type) const { + + PoolVector<uint8_t> sourcef; + Error err; + FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); + if (err) { + return String(); + } + + int len = f->get_len(); + sourcef.resize(len + 1); + PoolVector<uint8_t>::Write w = sourcef.write(); + int r = f->get_buffer(w.ptr(), len); + f->close(); + memdelete(f); + ERR_FAIL_COND_V(r != len, String()); + w[len] = 0; + + String s; + if (s.parse_utf8((const char *)w.ptr())) { + return String(); + } + + GDScriptParser parser; + + parser.parse(s, p_path.get_base_dir(), true, p_path); + + if (parser.get_parse_tree() && parser.get_parse_tree()->type == GDScriptParser::Node::TYPE_CLASS) { + + const GDScriptParser::ClassNode *c = static_cast<const GDScriptParser::ClassNode *>(parser.get_parse_tree()); + if (r_base_type && c->extends_used && c->extends_class.size() == 1) { + *r_base_type = c->extends_class[0]; //todo, should work much better + } + return c->name; + } + + return String(); +} + GDScriptLanguage::GDScriptLanguage() { calls = 0; diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 6885fbb7fe..d1c57a0330 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -63,7 +63,7 @@ class GDScript : public Script { int index; StringName setter; StringName getter; - ScriptInstance::RPCMode rpc_mode; + MultiplayerAPI::RPCMode rpc_mode; }; friend class GDScriptInstance; @@ -248,8 +248,8 @@ public: void reload_members(); - virtual RPCMode get_rpc_mode(const StringName &p_method) const; - virtual RPCMode get_rset_mode(const StringName &p_variable) const; + virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const; + virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const; GDScriptInstance(); ~GDScriptInstance(); @@ -439,6 +439,11 @@ public: virtual void get_recognized_extensions(List<String> *p_extensions) const; + /* GLOBAL CLASSES */ + + virtual bool handles_global_class_type(const String &p_type) const; + virtual String get_global_class_name(const String &p_path, String *r_base_type = NULL) const; + GDScriptLanguage(); ~GDScriptLanguage(); }; diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 9947512444..7ce19859ca 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -34,7 +34,7 @@ bool GDScriptCompiler::_is_class_member_property(CodeGen &codegen, const StringName &p_name) { - if (!codegen.function_node || codegen.function_node->_static) + if (codegen.function_node && codegen.function_node->_static) return false; if (codegen.stack_identifiers.has(p_name)) @@ -278,6 +278,41 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: return idx | (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS); //argument (stack root) } + /* TRY GLOBAL CLASSES */ + + if (ScriptServer::is_global_class(identifier)) { + + const GDScriptParser::ClassNode *class_node = codegen.class_node; + while (class_node->owner) { + class_node = class_node->owner; + } + + if (class_node->name == identifier) { + _set_error("Using own name in class file is not allowed (creates a cyclic reference)", p_expression); + return -1; + } + + RES res = ResourceLoader::load(ScriptServer::get_global_class_path(identifier)); + if (res.is_null()) { + _set_error("Can't load global class " + String(identifier) + ", cyclic reference?", p_expression); + return -1; + } + + Variant key = res; + int idx; + + if (!codegen.constant_map.has(key)) { + + idx = codegen.constant_map.size(); + codegen.constant_map[key] = idx; + + } else { + idx = codegen.constant_map[key]; + } + + return idx | (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS); //make it a local constant (faster access) + } + #ifdef TOOLS_ENABLED if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(identifier)) { @@ -738,6 +773,9 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: case GDScriptParser::OperatorNode::OP_NEG: { if (!_create_unary_operator(codegen, on, Variant::OP_NEGATE, p_stack_level)) return -1; } break; + case GDScriptParser::OperatorNode::OP_POS: { + if (!_create_unary_operator(codegen, on, Variant::OP_POSITIVE, p_stack_level)) return -1; + } break; case GDScriptParser::OperatorNode::OP_NOT: { if (!_create_unary_operator(codegen, on, Variant::OP_NOT, p_stack_level)) return -1; } break; diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 30ef167466..c0c3bd7b06 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -54,18 +54,18 @@ void GDScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const { } Ref<Script> GDScriptLanguage::get_template(const String &p_class_name, const String &p_base_class_name) const { - String _template = String() + - "extends %BASE%\n\n" + - "# class member variables go here, for example:\n" + - "# var a = 2\n" + - "# var b = \"textvar\"\n\n" + - "func _ready():\n" + - "%TS%# Called when the node is added to the scene for the first time.\n" + - "%TS%# Initialization here.\n" + - "%TS%pass\n\n" + - "#func _process(delta):\n" + - "#%TS%# Called every frame. Delta is time since last frame.\n" + - "#%TS%# Update game logic here.\n" + + String _template = "extends %BASE%\n" + "\n" + "# Declare member variables here. Examples:\n" + "# var a = 2\n" + "# var b = \"text\"\n" + "\n" + "# Called when the node enters the scene tree for the first time.\n" + "func _ready():\n" + "%TS%pass # Replace with function body.\n" + "\n" + "# Called every frame. 'delta' is the elapsed time since the previous frame.\n" + "#func _process(delta):\n" "#%TS%pass\n"; _template = _template.replace("%BASE%", p_base_class_name); @@ -118,6 +118,13 @@ bool GDScriptLanguage::validate(const String &p_script, int &r_line_error, int & funcs[cl->static_functions[i]->line] = cl->static_functions[i]->name; } + for (int i = 0; i < cl->subclasses.size(); i++) { + for (int j = 0; j < cl->subclasses[i]->functions.size(); j++) { + + funcs[cl->subclasses[i]->functions[j]->line] = String(cl->subclasses[i]->name) + "." + String(cl->subclasses[i]->functions[j]->name); + } + } + for (Map<int, String>::Element *E = funcs.front(); E; E = E->next()) { r_functions->push_back(E->get() + ":" + itos(E->key())); @@ -416,7 +423,7 @@ String GDScriptLanguage::make_function(const String &p_class, const String &p_na s += p_args[i].get_slice(":", 0); } } - s += "):\n" + _get_indentation() + "pass # replace with function body\n"; + s += "):\n" + _get_indentation() + "pass # Replace with function body.\n"; return s; } diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp index dac7da3a28..10599f0c38 100644 --- a/modules/gdscript/gdscript_function.cpp +++ b/modules/gdscript/gdscript_function.cpp @@ -1455,7 +1455,7 @@ GDScriptFunction::GDScriptFunction() : _stack_size = 0; _call_size = 0; - rpc_mode = ScriptInstance::RPC_MODE_DISABLED; + rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED; name = "<anonymous>"; #ifdef DEBUG_ENABLED _func_cname = NULL; @@ -1552,7 +1552,7 @@ Variant GDScriptFunctionState::_signal_callback(const Variant **p_args, int p_ar GDScriptFunctionState *gdfs = Object::cast_to<GDScriptFunctionState>(ret); if (gdfs && gdfs->function == function) { completed = false; - gdfs->previous_state = Ref<GDScriptFunctionState>(this); + gdfs->first_state = first_state.is_valid() ? first_state : Ref<GDScriptFunctionState>(this); } } @@ -1560,10 +1560,10 @@ Variant GDScriptFunctionState::_signal_callback(const Variant **p_args, int p_ar state.result = Variant(); if (completed) { - GDScriptFunctionState *state = this; - while (state != NULL) { - state->emit_signal("completed", ret); - state = *(state->previous_state); + if (first_state.is_valid()) { + first_state->emit_signal("completed", ret); + } else { + emit_signal("completed", ret); } } @@ -1614,7 +1614,7 @@ Variant GDScriptFunctionState::resume(const Variant &p_arg) { GDScriptFunctionState *gdfs = Object::cast_to<GDScriptFunctionState>(ret); if (gdfs && gdfs->function == function) { completed = false; - gdfs->previous_state = Ref<GDScriptFunctionState>(this); + gdfs->first_state = first_state.is_valid() ? first_state : Ref<GDScriptFunctionState>(this); } } @@ -1622,10 +1622,10 @@ Variant GDScriptFunctionState::resume(const Variant &p_arg) { state.result = Variant(); if (completed) { - GDScriptFunctionState *state = this; - while (state != NULL) { - state->emit_signal("completed", ret); - state = *(state->previous_state); + if (first_state.is_valid()) { + first_state->emit_signal("completed", ret); + } else { + emit_signal("completed", ret); } } diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h index ea009dcd96..770d5c8733 100644 --- a/modules/gdscript/gdscript_function.h +++ b/modules/gdscript/gdscript_function.h @@ -96,14 +96,6 @@ public: ADDR_TYPE_NIL = 9 }; - enum RPCMode { - RPC_DISABLED, - RPC_ENABLED, - RPC_SYNC, - RPC_SYNC_MASTER, - RPC_SYNC_SLAVE - }; - struct StackDebug { int line; @@ -135,7 +127,7 @@ private: int _call_size; int _initial_line; bool _static; - ScriptInstance::RPCMode rpc_mode; + MultiplayerAPI::RPCMode rpc_mode; GDScript *_script; @@ -230,7 +222,7 @@ public: Variant call(GDScriptInstance *p_instance, const Variant **p_args, int p_argcount, Variant::CallError &r_err, CallState *p_state = NULL); - _FORCE_INLINE_ ScriptInstance::RPCMode get_rpc_mode() const { return rpc_mode; } + _FORCE_INLINE_ MultiplayerAPI::RPCMode get_rpc_mode() const { return rpc_mode; } GDScriptFunction(); ~GDScriptFunction(); }; @@ -242,7 +234,7 @@ class GDScriptFunctionState : public Reference { GDScriptFunction *function; GDScriptFunction::CallState state; Variant _signal_callback(const Variant **p_args, int p_argcount, Variant::CallError &r_error); - Ref<GDScriptFunctionState> previous_state; + Ref<GDScriptFunctionState> first_state; protected: static void _bind_methods(); diff --git a/modules/gdscript/gdscript_functions.cpp b/modules/gdscript/gdscript_functions.cpp index a88ba477c6..ce91e7dff3 100644 --- a/modules/gdscript/gdscript_functions.cpp +++ b/modules/gdscript/gdscript_functions.cpp @@ -105,6 +105,7 @@ const char *GDScriptFunctions::get_func_name(Function p_func) { "prints", "printerr", "printraw", + "print_debug", "var2str", "str2var", "var2bytes", @@ -120,6 +121,7 @@ const char *GDScriptFunctions::get_func_name(Function p_func) { "Color8", "ColorN", "print_stack", + "get_stack", "instance_from_id", "len", "is_instance_valid", @@ -701,6 +703,23 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ r_ret = Variant(); } break; + case TEXT_PRINT_DEBUG: { + String str; + for (int i = 0; i < p_arg_count; i++) { + + str += p_args[i]->operator String(); + } + + ScriptLanguage *script = GDScriptLanguage::get_singleton(); + if (script->debug_get_stack_level_count() > 0) { + str += "\n\t"; + str += "At: " + script->debug_get_stack_level_source(0) + ":" + itos(script->debug_get_stack_level_line(0)); // + " in function '" + script->debug_get_stack_level_function(0) + "'"; + } + + //str+="\n"; + print_line(str); + r_ret = Variant(); + } break; case VAR_TO_STR: { VALIDATE_ARG_COUNT(1); String vars; @@ -1213,6 +1232,22 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ }; } break; + case GET_STACK: { + VALIDATE_ARG_COUNT(0); + + ScriptLanguage *script = GDScriptLanguage::get_singleton(); + Array ret; + for (int i = 0; i < script->debug_get_stack_level_count(); i++) { + + Dictionary frame; + frame["source"] = script->debug_get_stack_level_source(i); + frame["function"] = script->debug_get_stack_level_function(i); + frame["line"] = script->debug_get_stack_level_line(i); + ret.push_back(frame); + }; + r_ret = ret; + } break; + case INSTANCE_FROM_ID: { VALIDATE_ARG_COUNT(1); @@ -1716,6 +1751,14 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) { return mi; } break; + case TEXT_PRINT_DEBUG: { + + MethodInfo mi("print_debug"); + mi.return_val.type = Variant::NIL; + mi.flags |= METHOD_FLAG_VARARG; + return mi; + + } break; case VAR_TO_STR: { MethodInfo mi("var2str", PropertyInfo(Variant::NIL, "var")); mi.return_val.type = Variant::STRING; @@ -1813,6 +1856,11 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) { mi.return_val.type = Variant::NIL; return mi; } break; + case GET_STACK: { + MethodInfo mi("get_stack"); + mi.return_val.type = Variant::NIL; + return mi; + } break; case INSTANCE_FROM_ID: { MethodInfo mi("instance_from_id", PropertyInfo(Variant::INT, "instance_id")); diff --git a/modules/gdscript/gdscript_functions.h b/modules/gdscript/gdscript_functions.h index c4731d17a4..a29f06e839 100644 --- a/modules/gdscript/gdscript_functions.h +++ b/modules/gdscript/gdscript_functions.h @@ -96,6 +96,7 @@ public: TEXT_PRINT_SPACED, TEXT_PRINTERR, TEXT_PRINTRAW, + TEXT_PRINT_DEBUG, VAR_TO_STR, STR_TO_VAR, VAR_TO_BYTES, @@ -111,6 +112,7 @@ public: COLOR8, COLORN, PRINT_STACK, + GET_STACK, INSTANCE_FROM_ID, LEN, IS_INSTANCE_VALID, diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index e7b0700e76..d62112d3f1 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -716,6 +716,14 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s expr = constant; bfn = true; } + + if (!bfn && GDScriptLanguage::get_singleton()->get_named_globals_map().has(identifier)) { + //check from singletons + ConstantNode *constant = alloc_node<ConstantNode>(); + constant->value = GDScriptLanguage::get_singleton()->get_named_globals_map()[identifier]; + expr = constant; + bfn = true; + } } if (!bfn) { @@ -3104,6 +3112,28 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } } break; + case GDScriptTokenizer::TK_PR_CLASS_NAME: { + + if (p_class->owner) { + _set_error("'class_name' is only valid for the main class namespace."); + return; + } + if (tokenizer->get_token(1) != GDScriptTokenizer::TK_IDENTIFIER) { + + _set_error("'class_name' syntax: 'class_name <UniqueName>'"); + return; + } + + p_class->name = tokenizer->get_token_identifier(1); + + if (self_path != String() && ScriptServer::is_global_class(p_class->name) && ScriptServer::get_global_class_path(p_class->name) != self_path) { + _set_error("Unique global class '" + p_class->name + "' already exists at path: " + ScriptServer::get_global_class_path(p_class->name)); + return; + } + + tokenizer->advance(2); + + } break; case GDScriptTokenizer::TK_PR_TOOL: { if (p_class->tool) { @@ -3130,6 +3160,11 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { name = tokenizer->get_token_identifier(1); tokenizer->advance(2); + if (ScriptServer::is_global_class(name)) { + _set_error("Can't override name of unique global class '" + name + "' already exists at path: " + ScriptServer::get_global_class_path(p_class->name)); + return; + } + ClassNode *newclass = alloc_node<ClassNode>(); newclass->initializer = alloc_node<BlockNode>(); newclass->initializer->parent_class = newclass; @@ -3365,7 +3400,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { function->line = fnline; function->rpc_mode = rpc_mode; - rpc_mode = ScriptInstance::RPC_MODE_DISABLED; + rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED; if (_static) p_class->static_functions.push_back(function); @@ -3923,10 +3958,10 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { tokenizer->advance(); } - if (tokenizer->get_token() != GDScriptTokenizer::TK_PR_VAR && tokenizer->get_token() != GDScriptTokenizer::TK_PR_ONREADY && tokenizer->get_token() != GDScriptTokenizer::TK_PR_REMOTE && tokenizer->get_token() != GDScriptTokenizer::TK_PR_MASTER && tokenizer->get_token() != GDScriptTokenizer::TK_PR_SLAVE && tokenizer->get_token() != GDScriptTokenizer::TK_PR_SYNC) { + if (tokenizer->get_token() != GDScriptTokenizer::TK_PR_VAR && tokenizer->get_token() != GDScriptTokenizer::TK_PR_ONREADY && tokenizer->get_token() != GDScriptTokenizer::TK_PR_REMOTE && tokenizer->get_token() != GDScriptTokenizer::TK_PR_MASTER && tokenizer->get_token() != GDScriptTokenizer::TK_PR_SLAVE && tokenizer->get_token() != GDScriptTokenizer::TK_PR_SYNC && tokenizer->get_token() != GDScriptTokenizer::TK_PR_REMOTESYNC && tokenizer->get_token() != GDScriptTokenizer::TK_PR_MASTERSYNC && tokenizer->get_token() != GDScriptTokenizer::TK_PR_SLAVESYNC) { current_export = PropertyInfo(); - _set_error("Expected 'var', 'onready', 'remote', 'master', 'slave' or 'sync'."); + _set_error("Expected 'var', 'onready', 'remote', 'master', 'slave', 'sync', 'remotesync', 'mastersync', 'slavesync'."); return; } @@ -3959,7 +3994,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { return; } } - rpc_mode = ScriptInstance::RPC_MODE_REMOTE; + rpc_mode = MultiplayerAPI::RPC_MODE_REMOTE; continue; } break; @@ -3980,7 +4015,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } } - rpc_mode = ScriptInstance::RPC_MODE_MASTER; + rpc_mode = MultiplayerAPI::RPC_MODE_MASTER; continue; } break; case GDScriptTokenizer::TK_PR_SLAVE: { @@ -4000,9 +4035,10 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } } - rpc_mode = ScriptInstance::RPC_MODE_SLAVE; + rpc_mode = MultiplayerAPI::RPC_MODE_SLAVE; continue; } break; + case GDScriptTokenizer::TK_PR_REMOTESYNC: case GDScriptTokenizer::TK_PR_SYNC: { //may be fallthrough from export, ignore if so @@ -4015,7 +4051,37 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { return; } - rpc_mode = ScriptInstance::RPC_MODE_SYNC; + rpc_mode = MultiplayerAPI::RPC_MODE_SYNC; + continue; + } break; + case GDScriptTokenizer::TK_PR_MASTERSYNC: { + + //may be fallthrough from export, ignore if so + tokenizer->advance(); + if (tokenizer->get_token() != GDScriptTokenizer::TK_PR_VAR && tokenizer->get_token() != GDScriptTokenizer::TK_PR_FUNCTION) { + if (current_export.type) + _set_error("Expected 'var'."); + else + _set_error("Expected 'var' or 'func'."); + return; + } + + rpc_mode = MultiplayerAPI::RPC_MODE_MASTERSYNC; + continue; + } break; + case GDScriptTokenizer::TK_PR_SLAVESYNC: { + + //may be fallthrough from export, ignore if so + tokenizer->advance(); + if (tokenizer->get_token() != GDScriptTokenizer::TK_PR_VAR && tokenizer->get_token() != GDScriptTokenizer::TK_PR_FUNCTION) { + if (current_export.type) + _set_error("Expected 'var'."); + else + _set_error("Expected 'var' or 'func'."); + return; + } + + rpc_mode = MultiplayerAPI::RPC_MODE_SLAVESYNC; continue; } break; case GDScriptTokenizer::TK_PR_VAR: { @@ -4045,7 +4111,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { tokenizer->advance(); - rpc_mode = ScriptInstance::RPC_MODE_DISABLED; + rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED; if (tokenizer->get_token() == GDScriptTokenizer::TK_OP_ASSIGN) { @@ -4054,7 +4120,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { #endif tokenizer->advance(); - Node *subexpr = _parse_and_reduce_expression(p_class, false, autoexport); + Node *subexpr = _parse_and_reduce_expression(p_class, false, autoexport || member._export.type != Variant::NIL); if (!subexpr) { if (_recover_from_completion()) { break; @@ -4470,7 +4536,7 @@ void GDScriptParser::clear() { current_class = NULL; completion_found = false; - rpc_mode = ScriptInstance::RPC_MODE_DISABLED; + rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED; current_function = NULL; diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index 485ba1263d..b88a59537c 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -89,7 +89,7 @@ public: StringName getter; int line; Node *expression; - ScriptInstance::RPCMode rpc_mode; + MultiplayerAPI::RPCMode rpc_mode; }; struct Constant { StringName identifier; @@ -125,7 +125,7 @@ public: struct FunctionNode : public Node { bool _static; - ScriptInstance::RPCMode rpc_mode; + MultiplayerAPI::RPCMode rpc_mode; StringName name; Vector<StringName> arguments; Vector<Node *> default_values; @@ -134,7 +134,7 @@ public: FunctionNode() { type = TYPE_FUNCTION; _static = false; - rpc_mode = ScriptInstance::RPC_MODE_DISABLED; + rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED; } }; @@ -493,7 +493,7 @@ private: PropertyInfo current_export; - ScriptInstance::RPCMode rpc_mode; + MultiplayerAPI::RPCMode rpc_mode; void _set_error(const String &p_error, int p_line = -1, int p_column = -1); bool _recover_from_completion(); diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp index 6a844cd651..9517b95f3f 100644 --- a/modules/gdscript/gdscript_tokenizer.cpp +++ b/modules/gdscript/gdscript_tokenizer.cpp @@ -91,6 +91,7 @@ const char *GDScriptTokenizer::token_names[TK_MAX] = { "match", "func", "class", + "class_name", "extends", "is", "onready", @@ -110,6 +111,9 @@ const char *GDScriptTokenizer::token_names[TK_MAX] = { "sync", "master", "slave", + "remotesync", + "mastersync", + "slavesync", "'['", "']'", "'{'", @@ -184,6 +188,7 @@ static const _kws _keyword_list[] = { //func { GDScriptTokenizer::TK_PR_FUNCTION, "func" }, { GDScriptTokenizer::TK_PR_CLASS, "class" }, + { GDScriptTokenizer::TK_PR_CLASS_NAME, "class_name" }, { GDScriptTokenizer::TK_PR_EXTENDS, "extends" }, { GDScriptTokenizer::TK_PR_IS, "is" }, { GDScriptTokenizer::TK_PR_ONREADY, "onready" }, @@ -201,6 +206,9 @@ static const _kws _keyword_list[] = { { GDScriptTokenizer::TK_PR_MASTER, "master" }, { GDScriptTokenizer::TK_PR_SLAVE, "slave" }, { GDScriptTokenizer::TK_PR_SYNC, "sync" }, + { GDScriptTokenizer::TK_PR_REMOTESYNC, "remotesync" }, + { GDScriptTokenizer::TK_PR_MASTERSYNC, "mastersync" }, + { GDScriptTokenizer::TK_PR_SLAVESYNC, "slavesync" }, { GDScriptTokenizer::TK_PR_CONST, "const" }, { GDScriptTokenizer::TK_PR_ENUM, "enum" }, //controlflow @@ -247,6 +255,9 @@ bool GDScriptTokenizer::is_token_literal(int p_offset, bool variable_safe) const case TK_PR_MASTER: case TK_PR_SLAVE: case TK_PR_SYNC: + case TK_PR_REMOTESYNC: + case TK_PR_MASTERSYNC: + case TK_PR_SLAVESYNC: return true; // Literal for non-variables only: @@ -1128,7 +1139,7 @@ void GDScriptTokenizerText::advance(int p_amount) { ////////////////////////////////////////////////////////////////////////////////////////////////////// -#define BYTECODE_VERSION 12 +#define BYTECODE_VERSION 13 Error GDScriptTokenizerBuffer::set_code_buffer(const Vector<uint8_t> &p_buffer) { diff --git a/modules/gdscript/gdscript_tokenizer.h b/modules/gdscript/gdscript_tokenizer.h index b020c85199..c1f611fe73 100644 --- a/modules/gdscript/gdscript_tokenizer.h +++ b/modules/gdscript/gdscript_tokenizer.h @@ -96,6 +96,7 @@ public: TK_CF_MATCH, TK_PR_FUNCTION, TK_PR_CLASS, + TK_PR_CLASS_NAME, TK_PR_EXTENDS, TK_PR_IS, TK_PR_ONREADY, @@ -115,6 +116,9 @@ public: TK_PR_SYNC, TK_PR_MASTER, TK_PR_SLAVE, + TK_PR_REMOTESYNC, + TK_PR_MASTERSYNC, + TK_PR_SLAVESYNC, TK_BRACKET_OPEN, TK_BRACKET_CLOSE, TK_CURLY_BRACKET_OPEN, |