summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/classes/Object.xml4
-rw-r--r--doc/classes/Reference.xml3
-rw-r--r--doc/classes/Resource.xml5
-rw-r--r--doc/classes/String.xml2
-rw-r--r--editor/plugins/script_editor_plugin.cpp8
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp10
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/Godot.java40
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java10
-rw-r--r--scene/resources/visual_shader.cpp23
-rw-r--r--scene/resources/visual_shader.h4
-rw-r--r--scene/resources/visual_shader_nodes.cpp17
-rw-r--r--scene/resources/visual_shader_nodes.h1
12 files changed, 112 insertions, 15 deletions
diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml
index 3d8c2c5eb0..ca6b624359 100644
--- a/doc/classes/Object.xml
+++ b/doc/classes/Object.xml
@@ -17,8 +17,10 @@
[/codeblock]
The [code]in[/code] operator will evaluate to [code]true[/code] as long as the key exists, even if the value is [code]null[/code].
Objects also receive notifications. Notifications are a simple way to notify the object about different events, so they can all be handled together. See [method _notification].
+ [b]Note:[/b] Unlike references to a [Reference], references to an Object stored in a variable can become invalid without warning. Therefore, it's recommended to use [Reference] for data classes instead of [Object].
</description>
<tutorials>
+ <link title="When and how to avoid using nodes for everything">https://docs.godotengine.org/en/latest/getting_started/workflow/best_practices/node_alternatives.html</link>
</tutorials>
<methods>
<method name="_get" qualifiers="virtual">
@@ -518,7 +520,7 @@
One-shot connections disconnect themselves after emission.
</constant>
<constant name="CONNECT_REFERENCE_COUNTED" value="8" enum="ConnectFlags">
- Connect a signal as reference counted. This means that a given signal can be connected several times to the same target, and will only be fully disconnected once no references are left.
+ Connect a signal as reference-counted. This means that a given signal can be connected several times to the same target, and will only be fully disconnected once no references are left.
</constant>
</constants>
</class>
diff --git a/doc/classes/Reference.xml b/doc/classes/Reference.xml
index 860a47798c..9c3d1d5d9d 100644
--- a/doc/classes/Reference.xml
+++ b/doc/classes/Reference.xml
@@ -5,10 +5,11 @@
</brief_description>
<description>
Base class for any object that keeps a reference count. [Resource] and many other helper objects inherit this class.
- References keep an internal reference counter so that they are automatically released when no longer in use, and only then. References therefore do not need to be freed manually with [method Object.free].
+ Unlike [Object]s, References keep an internal reference counter so that they are automatically released when no longer in use, and only then. References therefore do not need to be freed manually with [method Object.free].
In the vast majority of use cases, instantiating and using [Reference]-derived types is all you need to do. The methods provided in this class are only for advanced users, and can cause issues if misused.
</description>
<tutorials>
+ <link title="When and how to avoid using nodes for everything">https://docs.godotengine.org/en/latest/getting_started/workflow/best_practices/node_alternatives.html</link>
</tutorials>
<methods>
<method name="init_ref">
diff --git a/doc/classes/Resource.xml b/doc/classes/Resource.xml
index 0aa40dffb3..e79a2e0ea9 100644
--- a/doc/classes/Resource.xml
+++ b/doc/classes/Resource.xml
@@ -4,10 +4,11 @@
Base class for all resources.
</brief_description>
<description>
- Resource is the base class for all Godot-specific resource types, serving primarily as data containers. They are reference counted and freed when no longer in use. They are also cached once loaded from disk, so that any further attempts to load a resource from a given path will return the same reference (all this in contrast to a [Node], which is not reference counted and can be instanced from disk as many times as desired). Resources can be saved externally on disk or bundled into another object, such as a [Node] or another resource.
+ Resource is the base class for all Godot-specific resource types, serving primarily as data containers. Unlike [Object]s, they are reference-counted and freed when no longer in use. They are also cached once loaded from disk, so that any further attempts to load a resource from a given path will return the same reference (all this in contrast to a [Node], which is not reference-counted and can be instanced from disk as many times as desired). Resources can be saved externally on disk or bundled into another object, such as a [Node] or another resource.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/getting_started/step_by_step/resources.html</link>
+ <link title="Resources">https://docs.godotengine.org/en/latest/getting_started/step_by_step/resources.html</link>
+ <link title="When and how to avoid using nodes for everything">https://docs.godotengine.org/en/latest/getting_started/workflow/best_practices/node_alternatives.html</link>
</tutorials>
<methods>
<method name="_setup_local_to_scene" qualifiers="virtual">
diff --git a/doc/classes/String.xml b/doc/classes/String.xml
index 71db03e84f..7e55f8bd9a 100644
--- a/doc/classes/String.xml
+++ b/doc/classes/String.xml
@@ -4,7 +4,7 @@
Built-in string class.
</brief_description>
<description>
- This is the built-in string class (and the one used by GDScript). It supports Unicode and provides all necessary means for string handling. Strings are reference counted and use a copy-on-write approach, so passing them around is cheap in resources.
+ This is the built-in string class (and the one used by GDScript). It supports Unicode and provides all necessary means for string handling. Strings are reference-counted and use a copy-on-write approach, so passing them around is cheap in resources.
</description>
<tutorials>
<link>https://docs.godotengine.org/en/latest/getting_started/scripting/gdscript/gdscript_format_string.html</link>
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 713d57ee95..edce2023ff 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -2092,7 +2092,9 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra
Ref<Script> script = p_resource;
// Don't open dominant script if using an external editor.
- const bool use_external_editor = EditorSettings::get_singleton()->get("text_editor/external/use_external_editor");
+ const bool use_external_editor =
+ EditorSettings::get_singleton()->get("text_editor/external/use_external_editor") ||
+ script->get_language()->overrides_external_editor();
const bool open_dominant = EditorSettings::get_singleton()->get("text_editor/files/open_dominant_script_on_scene_change");
const bool should_open = (open_dominant && !use_external_editor) || !EditorNode::get_singleton()->is_changing_scene();
@@ -3001,7 +3003,9 @@ Array ScriptEditor::_get_open_script_editors() const {
void ScriptEditor::set_scene_root_script(Ref<Script> p_script) {
// Don't open dominant script if using an external editor.
- const bool use_external_editor = EditorSettings::get_singleton()->get("text_editor/external/use_external_editor");
+ const bool use_external_editor =
+ EditorSettings::get_singleton()->get("text_editor/external/use_external_editor") ||
+ p_script->get_language()->overrides_external_editor();
const bool open_dominant = EditorSettings::get_singleton()->get("text_editor/files/open_dominant_script_on_scene_change");
if (open_dominant && !use_external_editor && p_script.is_valid()) {
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 51d93481b6..0843a54106 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -342,6 +342,16 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
return result;
}
+ if (first == "Object") {
+ result.kind = GDScriptParser::DataType::NATIVE;
+ result.native_type = "Object";
+ if (p_type->type_chain.size() > 1) {
+ push_error(R"("Object" type don't contain nested types.)", p_type->type_chain[1]);
+ return GDScriptParser::DataType();
+ }
+ return result;
+ }
+
if (GDScriptParser::get_builtin_type(first) < Variant::VARIANT_MAX) {
// Built-in types.
if (p_type->type_chain.size() > 1) {
diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
index 1ae400abb5..72746e06f7 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
@@ -70,6 +70,7 @@ import android.os.VibrationEffect;
import android.os.Vibrator;
import android.provider.Settings.Secure;
import android.view.Display;
+import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -82,6 +83,7 @@ import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.FrameLayout;
+import android.widget.PopupWindow;
import android.widget.ProgressBar;
import android.widget.TextView;
@@ -163,6 +165,8 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
public GodotRenderView mRenderView;
private boolean godot_initialized = false;
+ private PopupWindow mKeyboardWindow;
+
private SensorManager mSensorManager;
private Sensor mAccelerometer;
private Sensor mGravity;
@@ -219,11 +223,23 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
containerLayout = new FrameLayout(activity);
containerLayout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
+ // Create a popup window with an invisible layout for the virtual keyboard,
+ // so the view can be resized to get the vk height without resizing the main godot view.
+ final FrameLayout keyboardLayout = new FrameLayout(activity);
+ keyboardLayout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
+ keyboardLayout.setVisibility(View.INVISIBLE);
+ mKeyboardWindow = new PopupWindow(keyboardLayout, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+ mKeyboardWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
+ mKeyboardWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
+ mKeyboardWindow.setFocusable(true); // for the text edit to work
+ mKeyboardWindow.setTouchable(false); // inputs need to go through
+
// GodotEditText layout
GodotEditText editText = new GodotEditText(activity);
- editText.setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
- // ...add to FrameLayout
- containerLayout.addView(editText);
+ editText.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
+ editText.setKeyboardView(keyboardLayout);
+ // ...add to keyboard layout
+ keyboardLayout.addView(editText);
GodotLib.setup(command_line);
@@ -240,13 +256,13 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
editText.setView(mRenderView);
io.setEdit(editText);
- view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
+ keyboardLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Point fullSize = new Point();
activity.getWindowManager().getDefaultDisplay().getSize(fullSize);
Rect gameSize = new Rect();
- mRenderView.getView().getWindowVisibleDisplayFrame(gameSize);
+ mKeyboardWindow.getContentView().getWindowVisibleDisplayFrame(gameSize);
final int keyboardHeight = fullSize.y - gameSize.bottom;
GodotLib.setVirtualKeyboardHeight(keyboardHeight);
@@ -604,7 +620,21 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
}
@Override
+ public void onStart() {
+ super.onStart();
+
+ mRenderView.getView().post(new Runnable() {
+ @Override
+ public void run() {
+ mKeyboardWindow.showAtLocation(getActivity().getWindow().getDecorView(), Gravity.NO_GRAVITY, 0, 0);
+ }
+ });
+ }
+
+ @Override
public void onDestroy() {
+ mKeyboardWindow.dismiss();
+
for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
plugin.onMainDestroy();
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java
index c95339c583..042b3ac48a 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java
@@ -39,6 +39,7 @@ import android.text.InputFilter;
import android.text.InputType;
import android.util.AttributeSet;
import android.view.KeyEvent;
+import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
@@ -56,6 +57,7 @@ public class GodotEditText extends EditText {
// Fields
// ===========================================================
private GodotRenderView mRenderView;
+ private View mKeyboardView;
private GodotTextInputWrapper mInputWrapper;
private EditHandler sHandler = new EditHandler(this);
private String mOriginText;
@@ -129,7 +131,7 @@ public class GodotEditText extends EditText {
edit.mInputWrapper.setOriginText(text);
edit.addTextChangedListener(edit.mInputWrapper);
- final InputMethodManager imm = (InputMethodManager)mRenderView.getView().getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+ final InputMethodManager imm = (InputMethodManager)mKeyboardView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(edit, 0);
}
} break;
@@ -138,7 +140,7 @@ public class GodotEditText extends EditText {
GodotEditText edit = (GodotEditText)msg.obj;
edit.removeTextChangedListener(mInputWrapper);
- final InputMethodManager imm = (InputMethodManager)mRenderView.getView().getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+ final InputMethodManager imm = (InputMethodManager)mKeyboardView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(edit.getWindowToken(), 0);
edit.mRenderView.getView().requestFocus();
} break;
@@ -162,6 +164,10 @@ public class GodotEditText extends EditText {
view.getView().requestFocus();
}
+ public void setKeyboardView(final View keyboardView) {
+ mKeyboardView = keyboardView;
+ }
+
// ===========================================================
// Methods for/from SuperClass/Interfaces
// ===========================================================
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index 792e1ac2d7..0b8e435c19 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -74,6 +74,21 @@ void VisualShaderNode::set_output_port_connected(int p_port, bool p_connected) {
connected_output_ports[p_port] = p_connected;
}
+bool VisualShaderNode::is_input_port_connected(int p_port) const {
+ if (connected_input_ports.has(p_port)) {
+ return connected_input_ports[p_port];
+ }
+ return false;
+}
+
+void VisualShaderNode::set_input_port_connected(int p_port, bool p_connected) {
+ connected_input_ports[p_port] = p_connected;
+}
+
+bool VisualShaderNode::is_generate_input_var(int p_port) const {
+ return true;
+}
+
bool VisualShaderNode::is_code_generated() const {
return true;
}
@@ -444,6 +459,7 @@ void VisualShader::remove_node(Type p_type, int p_id) {
g->connections.erase(E);
if (E->get().from_node == p_id) {
g->nodes[E->get().to_node].prev_connected_nodes.erase(p_id);
+ g->nodes[E->get().to_node].node->set_input_port_connected(E->get().to_port, false);
}
}
E = N;
@@ -542,6 +558,7 @@ void VisualShader::connect_nodes_forced(Type p_type, int p_from_node, int p_from
g->connections.push_back(c);
g->nodes[p_to_node].prev_connected_nodes.push_back(p_from_node);
g->nodes[p_from_node].node->set_output_port_connected(p_from_port, true);
+ g->nodes[p_to_node].node->set_input_port_connected(p_to_port, true);
_queue_update();
}
@@ -574,6 +591,7 @@ Error VisualShader::connect_nodes(Type p_type, int p_from_node, int p_from_port,
g->connections.push_back(c);
g->nodes[p_to_node].prev_connected_nodes.push_back(p_from_node);
g->nodes[p_from_node].node->set_output_port_connected(p_from_port, true);
+ g->nodes[p_to_node].node->set_input_port_connected(p_to_port, true);
_queue_update();
return OK;
@@ -588,6 +606,7 @@ void VisualShader::disconnect_nodes(Type p_type, int p_from_node, int p_from_por
g->connections.erase(E);
g->nodes[p_to_node].prev_connected_nodes.erase(p_from_node);
g->nodes[p_from_node].node->set_output_port_connected(p_from_port, false);
+ g->nodes[p_to_node].node->set_input_port_connected(p_to_port, false);
_queue_update();
return;
}
@@ -1210,6 +1229,10 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui
inputs[i] = "int(" + src_var + ")";
}
} else {
+ if (!vsnode->is_generate_input_var(i)) {
+ continue;
+ }
+
Variant defval = vsnode->get_input_port_default_value(i);
if (defval.get_type() == Variant::FLOAT) {
float val = defval;
diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h
index cad567d32f..6d3fda1744 100644
--- a/scene/resources/visual_shader.h
+++ b/scene/resources/visual_shader.h
@@ -182,6 +182,7 @@ class VisualShaderNode : public Resource {
int port_preview;
Map<int, Variant> default_input_values;
+ Map<int, bool> connected_input_ports;
Map<int, bool> connected_output_ports;
protected:
@@ -225,6 +226,9 @@ public:
bool is_output_port_connected(int p_port) const;
void set_output_port_connected(int p_port, bool p_connected);
+ bool is_input_port_connected(int p_port) const;
+ void set_input_port_connected(int p_port, bool p_connected);
+ virtual bool is_generate_input_var(int p_port) const;
virtual bool is_code_generated() const;
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index 4cf382a933..0caa3cecd8 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -4457,6 +4457,13 @@ String VisualShaderNodeFresnel::get_output_port_name(int p_port) const {
return "result";
}
+bool VisualShaderNodeFresnel::is_generate_input_var(int p_port) const {
+ if (p_port == 2) {
+ return false;
+ }
+ return true;
+}
+
String VisualShaderNodeFresnel::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
String normal;
String view;
@@ -4471,7 +4478,15 @@ String VisualShaderNodeFresnel::generate_code(Shader::Mode p_mode, VisualShader:
view = p_input_vars[1];
}
- return "\t" + p_output_vars[0] + " = " + p_input_vars[2] + " ? (pow(clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + ")) : (pow(1.0 - clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + "));\n";
+ if (is_input_port_connected(2)) {
+ return "\t" + p_output_vars[0] + " = " + p_input_vars[2] + " ? (pow(clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + ")) : (pow(1.0 - clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + "));\n";
+ } else {
+ if (get_input_port_default_value(2)) {
+ return "\t" + p_output_vars[0] + " = pow(clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + ");\n";
+ } else {
+ return "\t" + p_output_vars[0] + " = pow(1.0 - clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + ");\n";
+ }
+ }
}
String VisualShaderNodeFresnel::get_input_port_default_hint(int p_port) const {
diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h
index b82d5c65c9..6c6e7b7580 100644
--- a/scene/resources/visual_shader_nodes.h
+++ b/scene/resources/visual_shader_nodes.h
@@ -1877,6 +1877,7 @@ public:
virtual String get_output_port_name(int p_port) const override;
virtual String get_input_port_default_hint(int p_port) const override;
+ virtual bool is_generate_input_var(int p_port) const override;
virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
VisualShaderNodeFresnel();