├── .gitignore
├── .travis.yml
├── ATTRIBUTIONS.md
├── Godot Node Extensions.csproj
├── Godot Node Extensions.sln
├── LICENSE
├── Properties
└── AssemblyInfo.cs
├── README.md
├── addons
├── godot-next-cs
│ ├── 2d
│ │ ├── Geometry2D.cs
│ │ └── Trail2D.cs
│ ├── 3d
│ │ └── Trail3D.cs
│ ├── godot_next_cs_plugin.gd
│ ├── icons
│ │ ├── icon_geometry_2d.svg
│ │ ├── icon_geometry_2d.svg.import
│ │ ├── icon_trail_2d.svg
│ │ ├── icon_trail_2d.svg.import
│ │ ├── icon_trail_3d.svg
│ │ └── icon_trail_3d.svg.import
│ └── plugin.cfg
└── godot-next
│ ├── 2d
│ ├── geometry_2d.gd
│ ├── trail_2d.gd
│ └── vector_display_2d.gd
│ ├── 3d
│ ├── trail_3d.gd
│ └── vector_display_3d.gd
│ ├── data
│ └── singleton_cache.tres
│ ├── global
│ ├── editor_tools.gd
│ ├── file_search.gd
│ ├── file_system_link.gd
│ ├── inspector_controls.gd
│ ├── physics_layers.gd
│ ├── project_tools.gd
│ ├── singletons.gd
│ └── variant.gd
│ ├── godot_next_plugin.gd
│ ├── gui
│ ├── cycle.gd
│ ├── debug_label.gd
│ └── v_box_item_list.gd
│ ├── icons
│ ├── icon_add.svg
│ ├── icon_add.svg.import
│ ├── icon_cycle.svg
│ ├── icon_cycle.svg.import
│ ├── icon_geometry_2d.svg
│ ├── icon_geometry_2d.svg.import
│ ├── icon_import_fail.svg
│ ├── icon_import_fail.svg.import
│ ├── icon_mirror_y.svg
│ ├── icon_mirror_y.svg.import
│ ├── icon_trail_2d.svg
│ ├── icon_trail_2d.svg.import
│ ├── icon_trail_3d.svg
│ ├── icon_trail_3d.svg.import
│ ├── icon_v_box_item_list.svg
│ └── icon_v_box_item_list.svg.import
│ ├── inspector_plugins
│ └── delegation_inspector_plugin.gd
│ ├── nodes
│ ├── callback_delegator.gd
│ └── message_dispatcher_wrapper.gd
│ ├── plugin.cfg
│ ├── references
│ ├── array_2d.gd
│ ├── bit_flag.gd
│ ├── bitset.gd
│ ├── class_type.gd
│ ├── csv_file.gd
│ ├── inflector.gd
│ ├── message_dispatcher.gd
│ ├── property_info.gd
│ ├── property_info_factory.gd
│ └── tween_sequence
│ │ ├── tween_sequence.gd
│ │ └── tweener.gd
│ ├── resources
│ ├── behavior.gd
│ ├── discrete_gradient_texture.gd
│ ├── resource_collections
│ │ ├── resource_array.gd
│ │ ├── resource_collection.gd
│ │ └── resource_set.gd
│ └── singletons
│ │ └── singleton_cache.gd
│ └── singletons
│ └── icons.gd
├── default_env.tres
├── demo
├── demo.tscn
├── demo_2d.tscn
├── demo_3d.tscn
└── scripts
│ ├── demo.gd
│ ├── test_vector_display.gd
│ ├── wandering_node_2d.gd
│ └── wandering_node_3d.gd
├── docs
└── use_cases.md
├── format.sh
├── icon.png
├── icon.png.import
├── licenses
└── LICENSE_Inflector.md
└── project.godot
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Godot-specific ignores
3 | .import/
4 | export.cfg
5 | export_presets.cfg
6 |
7 | # Imported translations (automatically generated from CSV files)
8 | *.translation
9 |
10 | # Mono-specific ignores
11 | .mono/
12 | data_*/
13 |
14 | # System/tool-specific ignores
15 | .directory
16 | *~
17 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | dist: bionic
2 |
3 | stages:
4 | - build
5 |
6 | matrix:
7 | include:
8 | - name: Static checks (format.sh)
9 | stage: build
10 | os: linux
11 | addons:
12 | apt:
13 | packages:
14 | - dos2unix
15 | - recode
16 |
17 | script:
18 | - bash ./format.sh
19 |
--------------------------------------------------------------------------------
/ATTRIBUTIONS.md:
--------------------------------------------------------------------------------
1 | This file is for recording any credits related to scripts or icons in the repository for which people's contributions would not otherwise be listed.
2 |
3 | - trail_2d.gd: The script work was started initially by following the [YouTube tutorial](https://www.youtube.com/watch?v=s5DwZZ0fZDg) on creating a Trail using Line2D by [@KrystianErber](https://twitter.com/KrystianErber).
4 |
5 | - csv_file.gd: The csv-parsing algorithm was extracted from a [Java tutorial](https://www.mkyong.com/java/how-to-read-and-parse-csv-file-in-java/) by [@mkyong](https://twitter.com/mkyong).
6 |
7 | - editor_tools.gd: 'is_in_edited_scene' sourced from [@Zylann](https://github.com/Zylann)
8 |
9 | - project_tools.gd: `try_set_setting` and `set_setting` initially derived from [/u/WordOfRabbit](https://www.reddit.com/user/WordOfRabbit)'s [blog](https://dfaction.net/handling-custom-project-settings-using-gdscript/).
10 |
--------------------------------------------------------------------------------
/Godot Node Extensions.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Tools
5 | AnyCPU
6 | {D437D4D4-7298-404E-96C3-567974A257A9}
7 | Library
8 | .mono\temp\bin\$(Configuration)
9 | GodotNodeExtensions
10 | Godot Node Extensions
11 | v4.7
12 | 1.0.7374.16792
13 | .mono\temp\obj
14 | $(BaseIntermediateOutputPath)\$(Configuration)
15 | Debug
16 | Release
17 |
18 |
19 | true
20 | portable
21 | false
22 | $(GodotDefineConstants);GODOT;DEBUG;
23 | prompt
24 | 4
25 | false
26 |
27 |
28 | portable
29 | true
30 | $(GodotDefineConstants);GODOT;
31 | prompt
32 | 4
33 | false
34 |
35 |
36 | true
37 | portable
38 | false
39 | $(GodotDefineConstants);GODOT;DEBUG;TOOLS;
40 | prompt
41 | 4
42 | false
43 |
44 |
45 |
46 | False
47 | $(ProjectDir)/.mono/assemblies/$(ApiConfiguration)/GodotSharp.dll
48 |
49 |
50 | False
51 | $(ProjectDir)/.mono/assemblies/$(ApiConfiguration)/GodotSharpEditor.dll
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/Godot Node Extensions.sln:
--------------------------------------------------------------------------------
1 | Microsoft Visual Studio Solution File, Format Version 12.00
2 | # Visual Studio 2012
3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Godot Node Extensions", "Godot Node Extensions.csproj", "{D437D4D4-7298-404E-96C3-567974A257A9}"
4 | EndProject
5 | Global
6 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
7 | Debug|Any CPU = Debug|Any CPU
8 | Release|Any CPU = Release|Any CPU
9 | Tools|Any CPU = Tools|Any CPU
10 | EndGlobalSection
11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
12 | {D437D4D4-7298-404E-96C3-567974A257A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
13 | {D437D4D4-7298-404E-96C3-567974A257A9}.Debug|Any CPU.Build.0 = Debug|Any CPU
14 | {D437D4D4-7298-404E-96C3-567974A257A9}.Release|Any CPU.ActiveCfg = Release|Any CPU
15 | {D437D4D4-7298-404E-96C3-567974A257A9}.Release|Any CPU.Build.0 = Release|Any CPU
16 | {D437D4D4-7298-404E-96C3-567974A257A9}.Tools|Any CPU.ActiveCfg = Tools|Any CPU
17 | {D437D4D4-7298-404E-96C3-567974A257A9}.Tools|Any CPU.Build.0 = Tools|Any CPU
18 | EndGlobalSection
19 | EndGlobal
20 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Will Nations
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 |
3 | // Information about this assembly is defined by the following attributes.
4 | // Change them to the values specific to your project.
5 |
6 | [assembly: AssemblyTitle("Godot Node Extensions")]
7 | [assembly: AssemblyDescription("")]
8 | [assembly: AssemblyConfiguration("")]
9 | [assembly: AssemblyCompany("")]
10 | [assembly: AssemblyProduct("")]
11 | [assembly: AssemblyCopyright("")]
12 | [assembly: AssemblyTrademark("")]
13 | [assembly: AssemblyCulture("")]
14 |
15 | // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
16 | // The form "{Major}.{Minor}.*" will automatically update the build and revision,
17 | // and "{Major}.{Minor}.{Build}.*" will update just the revision.
18 |
19 | [assembly: AssemblyVersion("1.0.*")]
20 |
21 | // The following attributes are used to specify the signing key for the assembly,
22 | // if desired. See the Mono documentation for more information about signing.
23 |
24 | //[assembly: AssemblyDelaySign(false)]
25 | //[assembly: AssemblyKeyFile("")]
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # godot-next
2 |
3 | ## Disclaimer
4 |
5 | Please note that this repository has been moved to `godot-extended-libraries/godot-next`. Please visit there if you would like to track its continued development! I am still the maintainer of it within that organization.
6 |
7 | ## Description
8 |
9 | Godot Node Extensions, AKA Godot NExt, is a Godot 3.1+ repository dedicated to collecting basic script classes that are currently unavailable in vanilla Godot.
10 |
11 | As you might have noticed, Godot Engine's initial node offerings are general purpose and are intentionally not oriented towards particular types of games.
12 |
13 | This repository's purpose is to create classes that fulfill a particular function and work out-of-the-box. Users should be able to use your class immediately after creating it. For nodes, don't be afraid to design ones that have an array of dynamically generated children. ;-)
14 |
15 | Note: The repository is named after Nodes, but ultimately any general-purpose type is welcome here (References, Resources, etc.).
16 |
17 | If you like the project, please star it. If you'd like to support its development, please [send tips to my Kofi](https://ko-fi.com/willnationsdev).
18 |
19 | [Jump to Class List](#classes)
20 |
21 | ## How to Use
22 |
23 | 1. Download the repo directly (the AssetLib version is no longer maintained)
24 |
25 | 2. Copy the addons directory to any project you would like to use them in
26 |
27 | 3. Open Project Settings and go to the Plugins tab.
28 |
29 | 4. Find the `godot-next` plugin and select "Active" from the dropdown on the right-hand side.
30 |
31 | 5. You should now be able to create each new type of node in your project!
32 |
33 | ## How to Contribute
34 |
35 | ### Ideas
36 | If you have an idea for a node that you would like to have added to the repository, create a new Issue.
37 |
38 | ### Scripts
39 |
40 | **All** scripts must be script classes, i.e. scripts with [registered names](http://docs.godotengine.org/en/latest/getting_started/step_by_step/scripting_continued.html#register-scripts-as-classes).
41 |
42 | **All** scripts must have the author's name at the top.
43 |
44 | **All** credits related to any associated script code or icons should be kept in the `ATTRIBUTIONS.md` file.
45 |
46 | **All** scripts must adhere to the relevant language's styling conventions, modeled after Godot Docs examples and the Godot Engine source code.
47 |
48 | **All C#** scripts must be submitted to a separate `addons/godot-next-cs` folder. This is to ensure that users who aren't using the Mono-enabled version of Godot do not have C# scripts present.
49 |
50 | Submissions are **encouraged** to do the following:
51 |
52 | 1. Provide a 16x16 SVG icon for each submitted script.
53 | 2. Use statically-typed GDScript if submitting GDScript files.
54 | 3. Create mirrored versions of GDScript and C# scripts between folders.
55 | 4. Add your node(s)' information to the bottom of the README, if possible (less work for maintainers).
56 |
57 | That's it! I hope you've got ideas of what you'd like to share with others.
58 |
59 | # Classes
60 |
61 | |Linkable Node Name|Description|Languages
62 | |-|-|-|
63 | |[Array2D](addons/godot-next/references/array_2d.gd)|A 2D Array class.|GDScript
64 | |[BitFlag](addons/godot-next/references/bit_flag.gd)|A class that allows abstracts away the complexity of handling bit flag enum types.|GDScript
65 | |[Bitset](addons/godot-next/references/bitset.gd)|A class that allows for easily manipulated bitmasks of any size.|GDScript
66 | |[Behavior](addons/godot-next/resources/behavior.gd)|A Resource type that automatically calls Node-like notification methods when paired with the CallbackDelegator class.|GDScript
67 | |[CallbackDelegator](addons/godot-next/nodes/callback_delegator.gd)|A Node that manages a ResourceSet of resources and delegates Node callbacks to each instance.|GDScript
68 | |[ClassType](addons/godot-next/references/class_type.gd)|A class abstraction, both for engine and user-defined types.|GDScript
69 | |[CSVFile](addons/godot-next/references/csv_file.gd)|Similar to ConfigFile, parses a .csv file. Can generate a key-value store from rows. Supports .tsv files.|GDScript
70 | |[Cycle](addons/godot-next/gui/cycle.gd)|Cycles through child nodes without any visibility or container effects.|GDScript
71 | |[DebugLabel](addons/godot-next/gui/debug_label.gd)|A label which displays a list of property values in any `Object`-derived instance at run-time for debugging purposes.|GDScript
72 | |[EditorTools](addons/godot-next/global/editor_tools.gd)|A utility for any features useful in the context of the Editor.|GDScript
73 | |[FileSearch](addons/godot-next/global/file_search.gd)|A utility with helpful methods to search through one's project files (or any directory).|GDScript
74 | |[FileSystemLink](addons/godot-next/global/file_system_link.gd)|A utility for creating links (file/directory, symbolic/hard).|GDScript
75 | |[Geometry2D](addons/godot-next/2d/geometry_2d.gd)|A utility that draws a Shape2D using CollisionShape2D's editor plugin handles.|GDScript, C#
76 | |[Inflector](addons/godot-next/references/inflector.gd)|A vocabulary wrapper of inflection tools to pluralize and singularize strings.|GDScript
77 | |[InspectorControls](addons/godot-next/global/inspector_controls.gd)|A utility for creating data-editing GUI elements.|GDScript
78 | |[MessageDispatcher](addons/godot-next/objects/message_dispatcher.gd)|A base object that handles signaling for non predetermined signals.|GDScript
79 | |[PhysicsLayers](addons/godot-next/global/physics_layers.gd)|A Utility class which allows easy access to your physics layers via their names in the project settings.|GDScript
80 | |[ProjectTools](addons/godot-next/global/project_tools.gd)|A utility for any features useful in the context of a Godot Project.|GDScript
81 | |[PropertyInfo](addons/godot-next/references/property_info.gd)|A wrapper and utility class for generating PropertyInfo Dictionaries, for use in `Object._get_property_list()`.|GDScript
82 | |[ResourceArray](addons/godot-next/resources/resource_collections/resource_array.gd)|A ResourceCollection implementation that manages an Array of Resources.|GDScript
83 | |[ResourceCollection](addons/godot-next/resources/resource_collections/resource_collection.gd)|An abstract base class for data structures that store Resource objects.|GDScript
84 | |[ResourceSet](addons/godot-next/resources/resource_collections/resource_set.gd)|A ResourceCollection implementation that manages a Set of Resources.|GDScript
85 | |[Singletons](addons/godot-next/global/singletons.gd)|A utility for caching Reference-derived singletons. Resources with a `SELF_RESOURCE` constant with a path to a `*.tres` file will be automatically loaded when accessed.|GDScript
86 | |[Trail2D](addons/godot-next/2d/trail_2d.gd)|Creates a variable-length trail that tracks a "target" node.|GDScript, C#
87 | |[Trail3D](addons/godot-next/3d/trail_3d.gd)|Creates a variable-length trail on an ImmediateGeometry node.|GDScript, C#
88 | |[Tween Sequence](addons/godot-next/references/tween_sequence.gd)|A helper class for easier management and chaining of Tweens dynamically from code.|GDScript
89 | |[VectorDisplay2D](addons/godot-next/2d/vector_display_2d.gd)|Displays Vector2 members in the editor via Position2D nodes.|GDScript
90 | |[VectorDisplay3D](addons/godot-next/3d/vector_display_3d.gd)|Displays Vector3 members in the editor via Position3D nodes.|GDScript
91 | |[Variant](addons/godot-next/global/variant.gd)|A utility class for handling Variants (the type wrapper for all variables in Godot's scripting API).|GDScript
92 | |[VBoxItemList](addons/godot-next/gui/v_box_item_list.gd)|Creates a vertical list of items that can be added or removed. Items are a user-specified Script or Scene Control.|GDScript
93 | |[DiscreteGradientTexture](addons/godot-next/resources/discrete_gradient_texture.gd)|Creates a not interpolated texture for a gradient.|GDScript
94 |
--------------------------------------------------------------------------------
/addons/godot-next-cs/2d/Geometry2D.cs:
--------------------------------------------------------------------------------
1 | using Godot;
2 |
3 | [Tool]
4 | public class Geometry2D : CollisionShape2D
5 | {
6 | private Color _color = Colors.White;
7 | private Vector2 _offsetPosition;
8 |
9 | [Export] public Color ShapeColor { get => _color; set { _color = value; Update(); } }
10 | [Export] public Vector2 OffsetPosition { get => _offsetPosition; set { _offsetPosition = value; Update(); } }
11 |
12 | public override void _Draw()
13 | {
14 | if (Shape is CircleShape2D)
15 | {
16 | DrawCircle(_offsetPosition, ((CircleShape2D)Shape).Radius, _color);
17 | }
18 | else if (Shape is RectangleShape2D)
19 | {
20 | RectangleShape2D rectangleShape = (RectangleShape2D)Shape;
21 | Rect2 rect = new Rect2(_offsetPosition - rectangleShape.Extents, rectangleShape.Extents * 2.0f);
22 | DrawRect(rect, _color);
23 | }
24 | else if (Shape is CapsuleShape2D)
25 | {
26 | CapsuleShape2D capsuleShape = (CapsuleShape2D)Shape;
27 | DrawCapsule(_offsetPosition, capsuleShape.Radius, capsuleShape.Height, _color);
28 | }
29 | }
30 |
31 | public void DrawCapsule(Vector2 capsulePosition, float capsuleRadius, float capsuleHeight, Color capsuleColor)
32 | {
33 | Vector2 upperCirclePosition = capsulePosition + new Vector2(0, capsuleHeight * 0.5f);
34 | DrawCircle(upperCirclePosition, capsuleRadius, capsuleColor);
35 |
36 | Vector2 lowerCirclePosition = capsulePosition - new Vector2(0, capsuleHeight * 0.5f);
37 | DrawCircle(lowerCirclePosition, capsuleRadius, capsuleColor);
38 |
39 | Vector2 rectPosition = capsulePosition - new Vector2(capsuleRadius, capsuleHeight * 0.5f);
40 | Rect2 rect = new Rect2(rectPosition, new Vector2(capsuleRadius * 2, capsuleHeight));
41 | DrawRect(rect, capsuleColor);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/addons/godot-next-cs/2d/Trail2D.cs:
--------------------------------------------------------------------------------
1 | using Godot;
2 |
3 | public class Trail2D : Line2D
4 | {
5 | public enum Persistence
6 | {
7 | Off, // Do not persist. Remove all points after the trailLength.
8 | Always, // Always persist. Do not remove any points.
9 | Conditional, // Sometimes persist. Choose an algorithm for when to add and remove points.
10 | }
11 |
12 | public enum PersistWhen
13 | {
14 | OnMovement, // Add points during movement and remove points when not moving.
15 | Custom, // Override ShouldGrow() and ShouldShrink() to define when to add/remove points.
16 | }
17 |
18 | // The target node to track
19 | private Node2D _target;
20 |
21 | // The NodePath to the target
22 | [Export] public NodePath targetPath = "..";
23 | // if not persisting, the number of points that should be allowed in the trail
24 | [Export] public int trailLength = 10;
25 | // To what degree the trail should remain in existence before automatically removing points.
26 | [Export] public Persistence persistence = Persistence.Off;
27 | // During conditional persistence, which persistence algorithm to use
28 | [Export] public PersistWhen persistWhen = PersistWhen.OnMovement;
29 | // During conditional persistence, how many points to remove per frame
30 | [Export] public int degenRate = 1;
31 | // if true, automatically set ZIndex to be one less than the 'target'
32 | [Export] public bool autoZIndex = true;
33 | // if true, will automatically setup a gradient for a gradually transparent trail
34 | [Export] public bool autoAlphaGradient = true;
35 |
36 | public override void _EnterTree()
37 | {
38 | SetAsToplevel(true);
39 | GlobalPosition = Vector2.Zero;
40 | GlobalRotation = 0;
41 | if (autoAlphaGradient && Gradient == null)
42 | {
43 | Gradient = new Gradient();
44 | Color first = DefaultColor;
45 | first.a = 0; // TODO: Use https://github.com/godotengine/godot/pull/31658 instead.
46 | Gradient.SetColor(0, first);
47 | Gradient.SetColor(1, DefaultColor);
48 | }
49 | _target = GetNodeOrNull(targetPath);
50 | }
51 |
52 | public override void _Notification(int p_what)
53 | {
54 | switch (p_what)
55 | {
56 | case Node.NotificationParented:
57 | if (autoZIndex)
58 | {
59 | ZIndex = _target != null ? _target.ZIndex - 1 : 0;
60 | }
61 | break;
62 | case Node.NotificationUnparented:
63 | targetPath = @"";
64 | trailLength = 0;
65 | break;
66 | }
67 | }
68 |
69 | public override void _Process(float delta)
70 | {
71 | if (_target == null)
72 | {
73 | _target = GetNodeOrNull(targetPath);
74 | return;
75 | }
76 |
77 | switch (persistence)
78 | {
79 | case Persistence.Off:
80 | AddPoint(_target.GlobalPosition);
81 | while (GetPointCount() > trailLength)
82 | {
83 | RemovePoint(0);
84 | }
85 | break;
86 | case Persistence.Always:
87 | AddPoint(_target.GlobalPosition);
88 | break;
89 | case Persistence.Conditional:
90 | switch (persistWhen)
91 | {
92 | case PersistWhen.OnMovement:
93 | bool moved = GetPointCount() > 0 ? GetPointPosition(GetPointCount() - 1) != _target.GlobalPosition : false;
94 | if (GetPointCount() == 0 || moved)
95 | {
96 | AddPoint(_target.GlobalPosition);
97 | }
98 | else
99 | {
100 | for (int i = 0; i < degenRate; i++)
101 | {
102 | RemovePoint(0);
103 | }
104 | }
105 | break;
106 | case PersistWhen.Custom:
107 | if (ShouldGrow())
108 | {
109 | AddPoint(_target.GlobalPosition);
110 | if (ShouldShrink())
111 | {
112 | for (int i = 0; i < degenRate; i++)
113 | {
114 | RemovePoint(0);
115 | }
116 | }
117 | break;
118 | }
119 | break;
120 | }
121 | break;
122 | }
123 | }
124 |
125 | protected bool ShouldGrow() { return true; }
126 | protected bool ShouldShrink() { return true; }
127 |
128 | public void EraseTrail()
129 | {
130 | for (int i = 0; i < GetPointCount(); i++)
131 | {
132 | RemovePoint(0);
133 | }
134 | }
135 |
136 | public void SetTarget(Node2D value)
137 | {
138 | if (value != null)
139 | {
140 | if (GetPathTo(value) != targetPath)
141 | {
142 | targetPath = GetPathTo(value);
143 | }
144 | }
145 | else
146 | {
147 | targetPath = @"";
148 | }
149 | }
150 |
151 | public void SetTargetPath(NodePath value)
152 | {
153 | targetPath = value;
154 | _target = GetNode(value) as Node2D;
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/addons/godot-next-cs/3d/Trail3D.cs:
--------------------------------------------------------------------------------
1 | using Godot;
2 |
3 | public class Trail3D : ImmediateGeometry
4 | {
5 | [Export] public float length = 10.0f;
6 | [Export] public float maxRadius = 0.5f;
7 | [Export] public int densityLengthwise = 25;
8 | [Export] public int densityAround = 5;
9 | [Export] public float shape = 0;
10 | [Export] public Godot.Collections.Array points = new Godot.Collections.Array();
11 | [Export] public float segmentLength = 1.0f;
12 |
13 | public override void _Ready()
14 | {
15 | if (length <= 0) length = 2;
16 | if (densityAround < 3) densityAround = 3;
17 | if (densityLengthwise < 2) densityLengthwise = 2;
18 |
19 | segmentLength = length / densityLengthwise;
20 | for (int i = 0; i < densityLengthwise; i++)
21 | {
22 | points.Add(GlobalTransform.origin);
23 | }
24 | }
25 |
26 | public override void _Process(float delta)
27 | {
28 | UpdateTrail();
29 | RenderTrail();
30 | }
31 |
32 | public void UpdateTrail()
33 | {
34 | int i = 0;
35 | Vector3 lastP = GlobalTransform.origin;
36 | foreach (Vector3 p in points)
37 | {
38 | Vector3 v = p; // We can't assign to foreach iterators in C#.
39 | float dis = v.DistanceTo(lastP);
40 | float segLen = segmentLength;
41 | if (i == 0)
42 | {
43 | segLen = 0.05f;
44 | }
45 | if (dis > segLen)
46 | {
47 | v = lastP + (v - lastP) / dis * segLen;
48 | }
49 | lastP = v;
50 | points[i] = v;
51 | i += 1;
52 | }
53 | }
54 |
55 | public void RenderTrail()
56 | {
57 | Clear();
58 | Begin(Mesh.PrimitiveType.Triangles);
59 | Godot.Collections.Array localPoints = new Godot.Collections.Array();
60 | foreach (Vector3 p in points)
61 | {
62 | localPoints.Add(p - GlobalTransform.origin);
63 | }
64 | Vector3 lastP = Vector3.Zero;
65 | Godot.Collections.Array> verts = new Godot.Collections.Array>();
66 | int ind = 0;
67 | bool firstIteration = true;
68 | Vector3 lastFirstVec = Vector3.Zero;
69 | foreach (Vector3 p in localPoints)
70 | {
71 | Godot.Collections.Array newLastPoints = new Godot.Collections.Array();
72 | var offset = lastP - p;
73 | if (offset == Vector3.Zero)
74 | {
75 | continue;
76 | }
77 | var yVec = offset.Normalized(); // get vector pointing from this point to last point
78 | var xVec = Vector3.Zero;
79 | if (firstIteration)
80 | {
81 | xVec = yVec.Cross(yVec.Rotated(Vector3.Right, 0.3f)); //cross product with random vector to get a perpendicular vector
82 | }
83 | else
84 | {
85 | xVec = yVec.Cross(lastFirstVec).Cross(yVec).Normalized(); // keep each loop at the same rotation as the previous
86 | }
87 | var width = maxRadius;
88 | if (shape != 0)
89 | {
90 | width = (1 - Mathf.Ease((ind + 1.0f) / densityLengthwise, shape)) * maxRadius;
91 | }
92 | Godot.Collections.Array segVerts = new Godot.Collections.Array();
93 | var fIter = true;
94 | for (int i = 0; i < densityAround; i++) // set up row of verts for each level
95 | {
96 | var newVert = p + width * xVec.Rotated(yVec, i * 2 * Mathf.Pi / densityAround).Normalized();
97 | if (fIter)
98 | {
99 | lastFirstVec = newVert - p;
100 | fIter = false;
101 | }
102 | segVerts.Add(newVert);
103 | }
104 | verts.Add(segVerts);
105 | lastP = p;
106 | ind += 1;
107 | firstIteration = false;
108 | }
109 | for (int j = 0; j < verts.Count - 1; j++)
110 | {
111 |
112 | var cur = verts[j];
113 | var nxt = verts[j + 1];
114 | for (int i = 0; i < densityAround; i++)
115 | {
116 | var nxtI = (i + 1) % densityAround;
117 | //order added affects normal
118 | AddVertex(cur[i]);
119 | AddVertex(cur[nxtI]);
120 | AddVertex(nxt[i]);
121 | AddVertex(cur[nxtI]);
122 | AddVertex(nxt[nxtI]);
123 | AddVertex(nxt[i]);
124 | }
125 | }
126 | if (verts.Count > 1)
127 | {
128 | for (int i = 0; i < densityAround; i++)
129 | {
130 | var nxt = (i + 1) % densityAround;
131 | AddVertex(verts[0][i]);
132 | AddVertex(Vector3.Zero);
133 | AddVertex(verts[0][nxt]);
134 | }
135 |
136 | for (int i = 0; i < densityAround; i++)
137 | {
138 | var nxt = (i + 1) % densityAround;
139 | AddVertex(verts[verts.Count - 1][i]);
140 | AddVertex(verts[verts.Count - 1][nxt]);
141 | AddVertex(lastP);
142 | }
143 | }
144 | End();
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/addons/godot-next-cs/godot_next_cs_plugin.gd:
--------------------------------------------------------------------------------
1 | tool
2 | extends EditorPlugin
3 |
4 | const DelegationInspectorPlugin = preload("res://addons/godot-next/inspector_plugins/delegation_inspector_plugin.gd")
5 |
6 | var delegation_inspector_plugin
7 |
8 | func _enter_tree() -> void:
9 | # When this plugin node enters tree, add the custom types
10 | add_custom_type("Geometry2D", "CollisionShape2D", preload("2d/Geometry2D.cs"), preload("icons/icon_geometry_2d.svg"))
11 | add_custom_type("Trail2D", "Line2D", preload("2d/Trail2D.cs"), preload("icons/icon_trail_2d.svg"))
12 | add_custom_type("Trail3D", "ImmediateGeometry", preload("3d/Trail3D.cs"), preload("icons/icon_trail_3d.svg"))
13 |
14 | Singletons._register_editor_singletons(self)
15 |
16 | delegation_inspector_plugin = DelegationInspectorPlugin.new()
17 | add_inspector_plugin(delegation_inspector_plugin)
18 |
19 |
20 | func _exit_tree() -> void:
21 | remove_inspector_plugin(delegation_inspector_plugin)
22 | remove_custom_type("Trail3D")
23 | remove_custom_type("Trail2D")
24 | remove_custom_type("Geometry2D")
25 |
--------------------------------------------------------------------------------
/addons/godot-next-cs/icons/icon_geometry_2d.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/addons/godot-next-cs/icons/icon_geometry_2d.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/icon_geometry_2d.svg-8eb868eaf31d28cd6a6d6e2990755585.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://addons/godot-next-cs/icons/icon_geometry_2d.svg"
13 | dest_files=[ "res://.import/icon_geometry_2d.svg-8eb868eaf31d28cd6a6d6e2990755585.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | stream=false
32 | size_limit=0
33 | detect_3d=true
34 | svg/scale=1.0
35 |
--------------------------------------------------------------------------------
/addons/godot-next-cs/icons/icon_trail_2d.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
72 |
--------------------------------------------------------------------------------
/addons/godot-next-cs/icons/icon_trail_2d.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/icon_trail_2d.svg-d47bf3d7df5294a0d532782f6dd5fa94.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://addons/godot-next-cs/icons/icon_trail_2d.svg"
13 | dest_files=[ "res://.import/icon_trail_2d.svg-d47bf3d7df5294a0d532782f6dd5fa94.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | stream=false
32 | size_limit=0
33 | detect_3d=true
34 | svg/scale=1.0
35 |
--------------------------------------------------------------------------------
/addons/godot-next-cs/icons/icon_trail_3d.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
79 |
--------------------------------------------------------------------------------
/addons/godot-next-cs/icons/icon_trail_3d.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/icon_trail_3d.svg-186ee87dfc04951744fc8103a0c04cca.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://addons/godot-next-cs/icons/icon_trail_3d.svg"
13 | dest_files=[ "res://.import/icon_trail_3d.svg-186ee87dfc04951744fc8103a0c04cca.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | stream=false
32 | size_limit=0
33 | detect_3d=true
34 | svg/scale=1.0
35 |
--------------------------------------------------------------------------------
/addons/godot-next-cs/plugin.cfg:
--------------------------------------------------------------------------------
1 | [plugin]
2 |
3 | name="Godot Node Extensions C#"
4 | description="A plugin filled with basic type extensions and utilities for Godot C#."
5 | author="Will Nations, Aaron Franke"
6 | version="0.1"
7 | script="godot_next_cs_plugin.gd"
8 |
--------------------------------------------------------------------------------
/addons/godot-next/2d/geometry_2d.gd:
--------------------------------------------------------------------------------
1 | tool
2 | class_name Geometry2D, "../icons/icon_geometry_2d.svg"
3 | extends CollisionShape2D
4 | # author: Henrique "Pigdev" Campos
5 | # license: MIT
6 | # description: Draws a Shape2D using CollisionShape2D's editor plugin handles.
7 | # notes:
8 | # - Don't use it as direct child of CollisionBody2D classes unless you intent
9 | # to use it as its CollisionShape2D.
10 |
11 | export (Color) var color := Color.white setget set_color
12 | export (Vector2) var offset_position := Vector2.ZERO setget set_offset
13 |
14 | func _draw() -> void:
15 | if shape is CircleShape2D:
16 | draw_circle(offset_position, shape.radius, color)
17 | elif shape is RectangleShape2D:
18 | var rect := Rect2(offset_position - shape.extents, shape.extents * 2.0)
19 | draw_rect(rect, color)
20 | elif shape is CapsuleShape2D:
21 | draw_capsule(offset_position, shape.radius, shape.height, color)
22 |
23 |
24 | func draw_capsule(capsule_position: Vector2, capsule_radius: float,
25 | capsule_height: float, capsule_color: Color) -> void:
26 |
27 | var upper_circle_position: Vector2 = capsule_position + Vector2(0, capsule_height * 0.5)
28 | draw_circle(upper_circle_position, capsule_radius, capsule_color)
29 |
30 | var lower_circle_position: Vector2 = capsule_position - Vector2(0, capsule_height * 0.5)
31 | draw_circle(lower_circle_position, capsule_radius, capsule_color)
32 |
33 | var rect_position: Vector2 = capsule_position - Vector2(capsule_radius, capsule_height * 0.5)
34 | var rect := Rect2(rect_position, Vector2(capsule_radius * 2, capsule_height))
35 | draw_rect(rect, capsule_color)
36 |
37 |
38 | func set_color(new_color: Color) -> void:
39 | color = new_color
40 | update()
41 |
42 |
43 | func set_offset(offset: Vector2) -> void:
44 | offset_position = offset
45 | update()
46 |
--------------------------------------------------------------------------------
/addons/godot-next/2d/trail_2d.gd:
--------------------------------------------------------------------------------
1 | class_name Trail2D, "../icons/icon_trail_2d.svg"
2 | extends Line2D
3 | # author: willnationsdev
4 | # brief description: Creates a variable-length trail that tracks the "target" node.
5 | # API details:
6 | # - Use CanvasItem.show_behind_parent or Node2D.z_index (Inspector) to control its layer visibility
7 | # - 'target' and 'target_path' (the 'target vars') will update each other as they are modified
8 | # - If you assign an empty 'target var', the value will automatically update to grab the parent.
9 | # - To completely turn off the Trail2D, set its `trail_length` to 0
10 | # - The node will automatically update its target vars when it is moved around in the tree
11 | # - You can set the "persistence" mode to have it...
12 | # - vanish the trail over time (Off)
13 | # - persist the trail forever, unless modified directly (Always)
14 | # - persist conditionally:
15 | # - persist automatically during movement and then shrink over time when you stop
16 | # - persist according to your own custom logic:
17 | # - use `bool _should_grow()` to return under what conditions
18 | # a point should be added underneath the target.
19 | # - use `bool _should_shrink()` to return under what conditions
20 | # the degen_rate should be removed from the trail's list of points.
21 |
22 | enum Persistence {
23 | OFF, # Do not persist. Remove all points after the trail_length.
24 | ALWAYS, # Always persist. Do not remove any points.
25 | CONDITIONAL, # Sometimes persist. Choose an algorithm for when to add and remove points.
26 | }
27 |
28 | enum PersistWhen {
29 | ON_MOVEMENT, # Add points during movement and remove points when not moving.
30 | CUSTOM, # Override _should_grow() and _should_shrink() to define when to add/remove points.
31 | }
32 |
33 | # The NodePath to the target.
34 | export var target_path: NodePath = @".." setget set_target_path
35 | # If not persisting, the number of points that should be allowed in the trail.
36 | export var trail_length: int = 10
37 | # To what degree the trail should remain in existence before automatically removing points.
38 | export(int, "Off", "Always", "Conditional") var persistence: int = Persistence.OFF
39 | # During conditional persistence, which persistence algorithm to use.
40 | export(int, "On Movement", "Custom") var persistence_condition: int = PersistWhen.ON_MOVEMENT
41 | # During conditional persistence, how many points to remove per frame.
42 | export var degen_rate: int = 1
43 | # If true, automatically set z_index to be one less than the 'target'.
44 | export var auto_z_index: bool = true
45 | # If true, will automatically setup a gradient for a gradually transparent trail.
46 | export var auto_alpha_gradient: bool = true
47 |
48 | # The target node to track.
49 | var target: Node2D setget set_target
50 |
51 | func _init():
52 | set_as_toplevel(true)
53 | global_position = Vector2()
54 | global_rotation = 0
55 | if auto_alpha_gradient and not gradient:
56 | gradient = Gradient.new()
57 | var first = default_color
58 | first.a = 0
59 | gradient.set_color(0, first)
60 | gradient.set_color(1, default_color)
61 |
62 |
63 | func _notification(p_what: int):
64 | match p_what:
65 | NOTIFICATION_PARENTED:
66 | self.target_path = target_path
67 | if auto_z_index:
68 | z_index = target.z_index - 1 if target else 0
69 | NOTIFICATION_UNPARENTED:
70 | self.target_path = @""
71 | self.trail_length = 0
72 |
73 |
74 | func _process(_delta: float):
75 | if target:
76 | match persistence:
77 | Persistence.OFF:
78 | add_point(target.global_position)
79 | while get_point_count() > trail_length:
80 | remove_point(0)
81 | Persistence.ALWAYS:
82 | add_point(target.global_position)
83 | pass
84 | Persistence.CONDITIONAL:
85 | match persistence_condition:
86 | PersistWhen.ON_MOVEMENT:
87 | var moved: bool = get_point_position(get_point_count()-1) != target.global_position if get_point_count() else false
88 | if not get_point_count() or moved:
89 | add_point(target.global_position)
90 | else:
91 | #warning-ignore:unused_variable
92 | for i in range(degen_rate):
93 | remove_point(0)
94 | PersistWhen.CUSTOM:
95 | if _should_grow():
96 | add_point(target.global_position)
97 | if _should_shrink():
98 | #warning-ignore:unused_variable
99 | for i in range(degen_rate):
100 | remove_point(0)
101 |
102 |
103 | func erase_trail():
104 | #warning-ignore:unused_variable
105 | for i in range(get_point_count()):
106 | remove_point(0)
107 |
108 |
109 | func set_target(p_value: Node2D):
110 | if p_value:
111 | if get_path_to(p_value) != target_path:
112 | set_target_path(get_path_to(p_value))
113 | else:
114 | target_path = @""
115 |
116 |
117 | func set_target_path(p_value: NodePath):
118 | target_path = p_value
119 | target = get_node(p_value) as Node2D if has_node(p_value) else null
120 |
121 |
122 | func _should_grow() -> bool:
123 | return true
124 |
125 |
126 | func _should_shrink() -> bool:
127 | return true
128 |
--------------------------------------------------------------------------------
/addons/godot-next/2d/vector_display_2d.gd:
--------------------------------------------------------------------------------
1 | tool
2 | class_name VectorDisplay2D
3 | extends Node
4 | # Displays Vector2 members in the editor via Position2D nodes.
5 |
6 | export(String) var variable_name = ""
7 | export(bool) var relative = true
8 |
9 | var _old_variable_name = null
10 | var _storage: Node2D
11 |
12 |
13 | func _process(delta):
14 | if Engine.is_editor_hint():
15 | if not variable_name:
16 | if _old_variable_name != variable_name:
17 | _old_variable_name = variable_name
18 | printerr("VectorDisplay2D: Please provide a variable name.")
19 | return
20 |
21 | if not _storage:
22 | _storage = Node2D.new()
23 | get_tree().get_edited_scene_root().add_child(_storage)
24 | return
25 |
26 | for child in _storage.get_children():
27 | child.queue_free()
28 |
29 | var parent = get_parent()
30 | if relative:
31 | _storage.transform.origin = parent.global_transform.origin
32 | else:
33 | _storage.transform.origin = Vector2.ZERO
34 |
35 | var variable = parent.get(variable_name)
36 | if variable == null:
37 | if _old_variable_name != variable_name:
38 | _old_variable_name = variable_name
39 | printerr("VectorDisplay2D: Variable '" + variable_name + "' not found or invalid on parent node '" + get_parent().get_name() + "'.")
40 | elif variable is Vector2:
41 | _add_position_child(variable)
42 | elif variable is PoolVector2Array:
43 | for item in variable:
44 | _add_position_child(item)
45 | elif variable is Array:
46 | for item in variable:
47 | if item is Vector2:
48 | _add_position_child(item)
49 |
50 |
51 | func _add_position_child(vector):
52 | var node = Position2D.new()
53 | node.transform.origin = vector
54 | _storage.add_child(node)
55 | node.set_owner(get_tree().get_edited_scene_root())
56 |
--------------------------------------------------------------------------------
/addons/godot-next/3d/trail_3d.gd:
--------------------------------------------------------------------------------
1 | class_name Trail3D, "../icons/icon_trail_3d.svg"
2 | extends ImmediateGeometry
3 | # author: miziziziz
4 | # brief description: Creates a variable-length trail on an ImmediateGeometry node.
5 | # API details:
6 | # - density_lengthwise: number of vertex loops in trail
7 | # - density_around: number of vertexes in each loop
8 | # - shape: curve used to shape trail, right click on this in inspector to see curve options
9 |
10 | export(float) var length = 10.0
11 | export var max_radius = 0.5
12 | export(int) var density_lengthwise = 25
13 | export(int) var density_around = 5
14 | export(float, EASE) var shape
15 |
16 | var points = []
17 | var segment_length = 1.0
18 |
19 | func _ready():
20 | if length <= 0:
21 | length = 2
22 | if density_around < 3:
23 | density_around = 3
24 | if density_lengthwise < 2:
25 | density_lengthwise = 2
26 |
27 | segment_length = length / density_lengthwise
28 | for i in range(density_lengthwise):
29 | points.append(global_transform.origin)
30 |
31 |
32 | func _process(_delta):
33 | update_trail()
34 | render_trail()
35 |
36 |
37 | func update_trail():
38 | var ind = 0
39 | var last_p = global_transform.origin
40 | for p in points:
41 | var dis = p.distance_to(last_p)
42 | var seg_len = segment_length
43 | if ind == 0:
44 | seg_len = 0.05
45 | if dis > seg_len:
46 | p = last_p + (p - last_p) / dis * seg_len
47 | last_p = p
48 | points[ind] = p
49 | ind += 1
50 |
51 |
52 | func render_trail():
53 | clear()
54 | begin(Mesh.PRIMITIVE_TRIANGLES)
55 | #begin(Mesh.PRIMITIVE_LINE_STRIP)
56 | var local_points = []
57 | for p in points:
58 | local_points.append(p - global_transform.origin)
59 | var last_p = Vector3()
60 | var verts = []
61 | var ind = 0
62 | var first_iteration = true
63 | var last_first_vec = Vector3()
64 | # Create vertex loops around points.
65 | for p in local_points:
66 | var new_last_points = []
67 | var offset = last_p - p
68 | if offset == Vector3():
69 | continue
70 | # Get vector pointing from this point to last point.
71 | var y_vec = offset.normalized()
72 | var x_vec = Vector3()
73 | if first_iteration:
74 | # Cross product with random vector to get a perpendicular vector.
75 | x_vec = y_vec.cross(y_vec.rotated(Vector3.RIGHT, 0.3))
76 | else:
77 | # Keep each loop at the same rotation as the previous.
78 | x_vec = y_vec.cross(last_first_vec).cross(y_vec).normalized()
79 | var width = max_radius
80 | if shape != 0:
81 | width = (1 - ease((ind + 1.0) / density_lengthwise, shape)) * max_radius
82 | var seg_verts = []
83 | var f_iter = true
84 | for i in range(density_around): # Set up row of verts for each level.
85 | var new_vert = p + width * x_vec.rotated(y_vec, i * TAU / density_around).normalized()
86 | if f_iter:
87 | last_first_vec = new_vert - p
88 | f_iter = false
89 | seg_verts.append(new_vert)
90 | verts.append(seg_verts)
91 | last_p = p
92 | ind += 1
93 | first_iteration = false
94 |
95 | # Create tris.
96 | for j in range(len(verts) - 1):
97 | var cur = verts[j]
98 | var nxt = verts[j + 1]
99 | for i in range(density_around):
100 | var nxt_i = (i + 1) % density_around
101 | # Order added affects normal.
102 | add_vertex(cur[i])
103 | add_vertex(cur[nxt_i])
104 | add_vertex(nxt[i])
105 | add_vertex(cur[nxt_i])
106 | add_vertex(nxt[nxt_i])
107 | add_vertex(nxt[i])
108 |
109 | if verts.size() > 1:
110 | # Cap off top.
111 | for i in range(density_around):
112 | var nxt = (i + 1) % density_around
113 | add_vertex(verts[0][i])
114 | add_vertex(Vector3())
115 | add_vertex(verts[0][nxt])
116 |
117 | # Cap off bottom.
118 | for i in range(density_around):
119 | var nxt = (i + 1) % density_around
120 | add_vertex(verts[verts.size() - 1][i])
121 | add_vertex(verts[verts.size() - 1][nxt])
122 | add_vertex(last_p)
123 | end()
124 |
--------------------------------------------------------------------------------
/addons/godot-next/3d/vector_display_3d.gd:
--------------------------------------------------------------------------------
1 | tool
2 | class_name VectorDisplay3D
3 | extends Node
4 | # Displays Vector3 members in the editor via Position3D nodes.
5 |
6 | export(String) var variable_name = ""
7 | export(bool) var relative = true
8 |
9 | var _old_variable_name = null
10 | var _storage: Spatial
11 |
12 |
13 | func _process(delta):
14 | if Engine.is_editor_hint():
15 | if not variable_name:
16 | if _old_variable_name != variable_name:
17 | _old_variable_name = variable_name
18 | printerr("VectorDisplay3D: Please provide a variable name.")
19 | return
20 |
21 | if not _storage:
22 | _storage = Spatial.new()
23 | get_tree().get_edited_scene_root().add_child(_storage)
24 | return
25 |
26 | for child in _storage.get_children():
27 | child.queue_free()
28 |
29 | var parent = get_parent()
30 | if relative:
31 | _storage.transform.origin = parent.global_transform.origin
32 | else:
33 | _storage.transform.origin = Vector3.ZERO
34 |
35 | var variable = parent.get(variable_name)
36 | if variable == null:
37 | if _old_variable_name != variable_name:
38 | _old_variable_name = variable_name
39 | printerr("VectorDisplay3D: Variable '" + variable_name + "' not found or invalid on parent node '" + get_parent().get_name() + "'.")
40 | elif variable is Vector3:
41 | _add_position_child(variable)
42 | elif variable is PoolVector3Array:
43 | for item in variable:
44 | _add_position_child(item)
45 | elif variable is Array:
46 | for item in variable:
47 | if item is Vector3:
48 | _add_position_child(item)
49 |
50 |
51 | func _add_position_child(vector):
52 | var node = Position3D.new()
53 | node.transform.origin = vector
54 | _storage.add_child(node)
55 | node.set_owner(get_tree().get_edited_scene_root())
56 |
--------------------------------------------------------------------------------
/addons/godot-next/data/singleton_cache.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="Resource" load_steps=2 format=2]
2 |
3 | [ext_resource path="res://addons/godot-next/resources/singletons/singleton_cache.gd" type="Script" id=1]
4 |
5 | [resource]
6 | script = ExtResource( 1 )
7 |
--------------------------------------------------------------------------------
/addons/godot-next/global/editor_tools.gd:
--------------------------------------------------------------------------------
1 | tool
2 | class_name EditorTools
3 | extends Reference
4 | # author: willnationsdev
5 | # description: A utility for any features useful in the context of the Editor.
6 |
7 | static func is_in_edited_scene(p_node: Node):
8 | if not p_node.is_inside_tree():
9 | return false
10 | var edited_scene := p_node.get_tree().edited_scene_root
11 | if p_node == edited_scene:
12 | return true
13 | return edited_scene.is_parent_of(p_node)
14 |
--------------------------------------------------------------------------------
/addons/godot-next/global/file_search.gd:
--------------------------------------------------------------------------------
1 | tool
2 | class_name FileSearch
3 | extends Reference
4 | # author: willnationsdev
5 | # license: MIT
6 | # description: A utility with helpful methods to search through one's project files (or any directory).
7 |
8 | class FileEvaluator extends Reference:
9 | var file_path: String = "" setget set_file_path
10 |
11 | # Assigns a new file path to the object.
12 | func _is_match() -> bool:
13 | return true
14 |
15 |
16 | # If _is_match() returns true, returns the key used to store the data.
17 | func _get_key():
18 | return file_path
19 |
20 |
21 | # If _is_match() returns true, returns the data associated with the file.
22 | func _get_value() -> Dictionary:
23 | return { "path": file_path }
24 |
25 |
26 | # Assigns a new file path to the object.
27 | func set_file_path(p_value):
28 | file_path = p_value
29 |
30 |
31 | class FilesThatHaveString extends FileEvaluator:
32 | var _compare: String
33 |
34 | func _init(p_compare: String = ""):
35 | _compare = p_compare
36 |
37 |
38 | func _is_match() -> bool:
39 | return file_path.find(_compare) != -1
40 |
41 |
42 | class FilesThatAreSubsequenceOf extends FileEvaluator:
43 | var _compare: String
44 | var _case_sensitive: bool
45 |
46 | func _init(p_compare: String = "", p_case_sensitive: bool = false):
47 | _compare = p_compare
48 | _case_sensitive = p_case_sensitive
49 |
50 |
51 | func _is_match() -> bool:
52 | if _case_sensitive:
53 | return _compare.is_subsequence_of(file_path)
54 | return _compare.is_subsequence_ofi(file_path)
55 |
56 |
57 | class FilesThatMatchRegex extends FileEvaluator:
58 | var _regex: RegEx = RegEx.new()
59 | var _compare_full_path
60 | var _match: RegExMatch = null
61 |
62 | func _init(p_regex_str: String, p_compare_full_path: bool = false):
63 | _compare_full_path = p_compare_full_path
64 | if _regex.compile(p_regex_str) != OK:
65 | push_error("Check failed. FilesThatMatchRegex failed to compile regex: " + p_regex_str)
66 | return
67 |
68 |
69 | func _is_match() -> bool:
70 | if not _regex.is_valid():
71 | return false
72 | _match = _regex.search(file_path if _compare_full_path else file_path.get_file())
73 | return _match != null
74 |
75 |
76 | func _get_value() -> Dictionary:
77 | var data = ._get_value()
78 | data.match = _match
79 | return data
80 |
81 |
82 | class FilesThatExtendResource extends FileEvaluator:
83 | var _match_func: FuncRef
84 | var _exts: Dictionary
85 |
86 | func _init(p_types: PoolStringArray = PoolStringArray(["Resource"]), p_match_func: FuncRef = null, p_block_base_resource: bool = false):
87 | _match_func = p_match_func
88 | for type in p_types:
89 | for a_ext in ResourceLoader.get_recognized_extensions_for_type(type):
90 | _exts[a_ext] = null
91 | if p_block_base_resource:
92 | #warning-ignore:return_value_discarded
93 | #warning-ignore:return_value_discarded
94 | _exts.erase("tres")
95 | _exts.erase("res")
96 |
97 |
98 | func _is_match() -> bool:
99 | for a_ext in _exts:
100 | if file_path.get_file().get_extension() == a_ext:
101 | if _match_func:
102 | return _match_func.call_func(file_path)
103 | return true
104 | return false
105 |
106 |
107 | const SELF_PATH: String = "res://addons/godot-next/global/file_search.gd"
108 |
109 | static func search_string(p_str: String, p_from_dir: String = "res://", p_recursive: bool = true) -> Dictionary:
110 | return _search(FilesThatHaveString.new(p_str), p_from_dir, p_recursive)
111 |
112 |
113 | static func search_subsequence(p_str: String, p_from_dir: String = "res://", p_recursive: bool = true) -> Dictionary:
114 | return _search(FilesThatAreSubsequenceOf.new(p_str, false), p_from_dir, p_recursive)
115 |
116 |
117 | static func search_subsequence_i(p_str: String, p_from_dir: String = "res://", p_recursive: bool = true) -> Dictionary:
118 | return _search(FilesThatAreSubsequenceOf.new(p_str, true), p_from_dir, p_recursive)
119 |
120 |
121 | static func search_regex(p_regex: String, p_from_dir: String = "res://", p_recursive: bool = true) -> Dictionary:
122 | return _search(FilesThatMatchRegex.new(p_regex, false), p_from_dir, p_recursive)
123 |
124 |
125 | static func search_regex_full_path(p_regex: String, p_from_dir: String = "res://", p_recursive: bool = true) -> Dictionary:
126 | return _search(FilesThatMatchRegex.new(p_regex, true), p_from_dir, p_recursive)
127 |
128 |
129 | static func search_scripts(p_match_func: FuncRef = null, p_from_dir: String = "res://", p_recursive: bool = true) -> Dictionary:
130 | return _search(FilesThatExtendResource.new(["Script"], p_match_func), p_from_dir, p_recursive)
131 |
132 |
133 | static func search_scenes(p_match_func: FuncRef = null, p_from_dir: String = "res://", p_recursive: bool = true) -> Dictionary:
134 | return _search(FilesThatExtendResource.new(["PackedScene"], p_match_func), p_from_dir, p_recursive)
135 |
136 |
137 | static func search_types(p_match_func: FuncRef = null, p_from_dir: String = "res://", p_recursive: bool = true) -> Dictionary:
138 | return _search(FilesThatExtendResource.new(["Script", "PackedScene"], p_match_func), p_from_dir, p_recursive)
139 |
140 |
141 | static func search_resources(p_types: PoolStringArray = ["Resource"], p_match_func: FuncRef = null, p_from_dir: String = "res://", p_recursive: bool = true) -> Dictionary:
142 | return _search(FilesThatExtendResource.new(p_types, p_match_func), p_from_dir, p_recursive)
143 |
144 |
145 | static func _this() -> Script:
146 | return load(SELF_PATH) as Script
147 |
148 |
149 | # p_evaluator: A FileEvaluator type.
150 | # p_from_dir: The starting location from which to scan.
151 | # p_recursive: If true, scan all sub-directories, not just the given one.
152 | static func _search(p_evaluator: FileEvaluator, p_from_dir: String = "res://", p_recursive: bool = true) -> Dictionary:
153 | var dirs: Array = [p_from_dir]
154 | var dir: Directory = Directory.new()
155 | var data: Dictionary = {}
156 | var eval: FileEvaluator = p_evaluator
157 |
158 | # Generate 'data' map.
159 | while not dirs.empty():
160 | var dir_name = dirs.back()
161 | dirs.pop_back()
162 |
163 | if dir.open(dir_name) == OK:
164 | #warning-ignore:return_value_discarded
165 | dir.list_dir_begin()
166 | var file_name = dir.get_next()
167 | while file_name:
168 | # Ignore hidden content.
169 | if not file_name.begins_with("."):
170 | var a_path = dir.get_current_dir().plus_file(file_name)
171 | eval.set_file_path(a_path)
172 |
173 | # If a directory, then add to list of directories to visit.
174 | if p_recursive and dir.current_is_dir():
175 | dirs.push_back(a_path)
176 | # If a file, check if we already have a record for the same name.
177 | # Only use files with extensions.
178 | elif not data.has(a_path) and eval._is_match():
179 | data[eval._get_key()] = eval._get_value()
180 |
181 | # Move on to the next file in this directory.
182 | file_name = dir.get_next()
183 |
184 | # We've exhausted all files in this directory. Close the iterator.
185 | dir.list_dir_end()
186 |
187 | return data
188 |
--------------------------------------------------------------------------------
/addons/godot-next/global/file_system_link.gd:
--------------------------------------------------------------------------------
1 | class_name FileSystemLink
2 | extends Reference
3 | # author: willnationsdev
4 | # description: A utility for creating links (file/directory, symbolic/hard).
5 | # API details:
6 | # - All methods' parameters are ordered in Unix fashion, {,}
7 | # - Methods are aliased so that the parameters are implied by the method name.
8 |
9 | enum LinkTypes {
10 | SOFT,
11 | HARD
12 | }
13 |
14 | enum TargetTypes {
15 | FILE,
16 | DIR,
17 | WINDOWS_JUNCTION
18 | }
19 |
20 | static func mk_hard_file(p_target: String, p_linkpath: String = "") -> int:
21 | return _make_link(p_target, p_linkpath, TargetTypes.FILE, LinkTypes.HARD)
22 |
23 |
24 | static func mk_soft_file(p_target: String, p_linkpath: String = "") -> int:
25 | return _make_link(p_target, p_linkpath, TargetTypes.FILE, LinkTypes.SOFT)
26 |
27 |
28 | static func mk_hard_dir(p_target: String, p_linkpath: String = "") -> int:
29 | return _make_link(p_target, p_linkpath, TargetTypes.DIR, LinkTypes.HARD)
30 |
31 |
32 | static func mk_soft_dir(p_target: String, p_linkpath: String = "") -> int:
33 | return _make_link(p_target, p_linkpath, TargetTypes.DIR, LinkTypes.SOFT)
34 |
35 |
36 | static func mk_windows_junction(p_target: String, p_linkpath: String = "") -> int:
37 | return _make_link(p_target, p_linkpath, TargetTypes.WINDOWS_JUNCTION, LinkTypes.SOFT)
38 |
39 |
40 | static func _make_link(p_target: String, p_linkpath: String = "", p_target_type = TargetTypes.FILE, p_link_type: int = LinkTypes.SOFT) -> int:
41 | var params := PoolStringArray()
42 | var dir := Directory.new()
43 | var output := []
44 | var target := ProjectSettings.globalize_path(p_target)
45 | var linkpath := ProjectSettings.globalize_path(p_linkpath)
46 | match p_target_type:
47 | TargetTypes.FILE:
48 | if not dir.file_exists(target):
49 | return ERR_FILE_NOT_FOUND
50 | TargetTypes.DIR, TargetTypes.WINDOWS_JUNCTION:
51 | if not dir.dir_exists(target):
52 | return ERR_FILE_NOT_FOUND
53 |
54 | match OS.get_name():
55 | "Windows":
56 | match p_link_type:
57 | LinkTypes.SOFT:
58 | pass
59 | LinkTypes.HARD:
60 | params.append("/H")
61 | _:
62 | printerr("Unknown link type passed to FileSystemLink.make_link: ", p_link_type)
63 | return ERR_INVALID_PARAMETER
64 | #warning-ignore:unreachable_code
65 | match p_target_type:
66 | TargetTypes.FILE:
67 | pass
68 | TargetTypes.DIR:
69 | params.append("/D")
70 | TargetTypes.WINDOWS_JUNCTION:
71 | params.append("/J")
72 | _:
73 | printerr("Unknown target type passed to FileSystemLink.make_link: ", p_target_type)
74 | return ERR_INVALID_PARAMETER
75 |
76 | params.append(linkpath)
77 | params.append(target)
78 | #warning-ignore:return_value_discarded
79 | OS.execute("mklink", params, true, output)
80 | return OK
81 | "X11", "OSX", "LinuxBSD":
82 | match p_link_type:
83 | LinkTypes.SOFT:
84 | params.append("-s")
85 | LinkTypes.HARD:
86 | pass
87 | _:
88 | printerr("Unknown link type passed to FileSystemLink.make_link", p_link_type)
89 | return ERR_INVALID_PARAMETER
90 |
91 | match p_target_type:
92 | TargetTypes.FILE:
93 | pass
94 | TargetTypes.DIR:
95 | params.append("-d")
96 | TargetTypes.WINDOWS_JUNCTION:
97 | printerr("Junctions are a Windows feature")
98 | return ERR_INVALID_PARAMETER
99 | _:
100 | printerr("Unknown target type passed to FileSystemLink.make_link: ", p_target_type)
101 | return ERR_INVALID_PARAMETER
102 |
103 | params.append(target)
104 | params.append(linkpath)
105 | #warning-ignore:return_value_discarded
106 | OS.execute("ln", params, true, output)
107 | return OK
108 | _:
109 | return ERR_UNAVAILABLE
110 |
--------------------------------------------------------------------------------
/addons/godot-next/global/inspector_controls.gd:
--------------------------------------------------------------------------------
1 | class_name InspectorControls
2 | extends Reference
3 | # author: xdgamestudios
4 | # license: MIT
5 | # description:
6 | # A collection of classes and factory methods for generating Controls
7 | # oriented towards editing data. Useful for modifying the
8 | # EditorInspector or generating your own in-game data-editing tools.
9 |
10 | const ADD_ICON = preload("res://addons/godot-next/icons/icon_add.svg")
11 |
12 | class DropdownAppender extends HBoxContainer:
13 | func get_button() -> ToolButton:
14 | return get_node("ToolButton") as ToolButton
15 |
16 |
17 | func get_dropdown() -> OptionButton:
18 | return get_node("Dropdown") as OptionButton
19 |
20 |
21 | func get_selected_label() -> String:
22 | var dropdown := get_dropdown()
23 | var index := dropdown.get_selected_id()
24 | return dropdown.get_item_text(index)
25 |
26 |
27 | func get_selected_meta():
28 | return get_dropdown().get_selected_metadata()
29 |
30 |
31 | # Instantiates a Label. If align is not set the dafault ALIGN_LEFT will be used.
32 | static func new_label(p_label: String, p_align: int = Label.ALIGN_LEFT) -> Label:
33 | var label = Label.new()
34 | label.text = p_label
35 | label.align = p_align
36 | return label
37 |
38 |
39 | # Instantiates an empty control used to insert space between properties.
40 | static func new_space(p_size: Vector2, p_horizontal_flag: int = Control.SIZE_EXPAND_FILL, p_vertical_flag: int = Control.SIZE_EXPAND_FILL) -> Control:
41 | var control = Control.new()
42 | control.size_flags_horizontal = p_horizontal_flag
43 | control.size_flags_vertical = p_vertical_flag
44 | control.rect_min_size = p_size
45 | return control
46 |
47 |
48 | # Instantiates a Button. If toggle mode is set, p_object/p_callback
49 | # will connect to its "toggled" signal. Else, "pressed".
50 | static func new_button(p_label: String, p_toggle_mode: bool = false, p_object: Object = null, p_callback: String = "") -> Button:
51 | var button = Button.new()
52 | button.text = p_label
53 | button.name = "Button"
54 | button.toggle_mode = p_toggle_mode
55 |
56 | if p_object and p_callback:
57 | if p_toggle_mode:
58 | button.connect("toggled", p_object, p_callback)
59 | else:
60 | button.connect("pressed", p_object, p_callback)
61 |
62 | return button
63 |
64 |
65 | # Instantiates a ToolButton. If toggle mode is set, p_object/p_callback
66 | # will connect to its "toggled" signal. Else, "pressed".
67 | static func new_tool_button(p_icon: Texture, p_toggle_mode: bool = false, p_object: Object = null, p_callback: String = "") -> ToolButton:
68 | var button = ToolButton.new()
69 | button.icon = p_icon
70 | button.name = "ToolButton"
71 | button.toggle_mode = p_toggle_mode
72 |
73 | if p_object and p_callback:
74 | if p_toggle_mode:
75 | button.connect("toggled", p_object, p_callback)
76 | else:
77 | button.connect("pressed", p_object, p_callback)
78 |
79 | return button
80 |
81 |
82 | static func new_dropdown(p_elements: Dictionary, p_object: Object = null, p_callback: String = "") -> OptionButton:
83 | var dropdown := OptionButton.new()
84 | var index = 0
85 | for a_label in p_elements:
86 | dropdown.add_item(a_label, index)
87 | dropdown.set_item_metadata(index, p_elements[a_label])
88 | index += 1
89 | dropdown.name = "Dropdown"
90 | dropdown.size_flags_horizontal = HBoxContainer.SIZE_EXPAND_FILL
91 |
92 | if p_object and p_callback:
93 | dropdown.connect("item_selected", p_object, p_callback, [dropdown])
94 |
95 | return dropdown
96 |
97 |
98 | static func new_dropdown_appender(p_elements: Dictionary, p_object: Object = null, p_callback: String = "") -> DropdownAppender:
99 | var dropdown_appender := DropdownAppender.new()
100 |
101 | var dropdown := new_dropdown(p_elements)
102 |
103 | var tool_button = ToolButton.new()
104 | tool_button.name = "ToolButton"
105 | tool_button.icon = ADD_ICON
106 |
107 | dropdown_appender.add_child(dropdown)
108 | dropdown_appender.add_child(tool_button)
109 |
110 | if p_object and p_callback:
111 | tool_button.connect("pressed", p_object, p_callback, [dropdown_appender])
112 |
113 | return dropdown_appender
114 |
--------------------------------------------------------------------------------
/addons/godot-next/global/physics_layers.gd:
--------------------------------------------------------------------------------
1 | tool
2 | class_name PhysicsLayers
3 | extends Resource
4 | # author: xaguzman
5 | # license: MIT
6 | # description:
7 | # A Utility class which allows easy access to your physics
8 | # layers via their names in the project settings.
9 |
10 | const _PHYSICS_LAYERS_BIT: Dictionary = {}
11 | const _PHYSICS_2D_PREFIX = "2d_physics"
12 | const _PHYSICS_3D_PREFIX = "3d_physics"
13 |
14 | static func setup() -> void:
15 | for prefix in [_PHYSICS_2D_PREFIX, _PHYSICS_3D_PREFIX]:
16 | var path : String = "layer_names/".plus_file(prefix)
17 | for i in range(1, 21):
18 | var layer_path: String = path.plus_file(str("layer_", i))
19 | var layer_name: String = ProjectSettings.get(layer_path)
20 |
21 | if not layer_name:
22 | layer_name = str("Layer ", i)
23 |
24 | var layer_key: String = prefix.plus_file(layer_name)
25 | _PHYSICS_LAYERS_BIT[layer_key] = i - 1
26 |
27 |
28 | # Get the corresponding bit of the layer named
29 | static func _get_physics_layer_index(layer_name: String) -> int:
30 | if not _PHYSICS_LAYERS_BIT.has(layer_name):
31 | setup()
32 |
33 | assert (_PHYSICS_LAYERS_BIT.has(layer_name))
34 | return _PHYSICS_LAYERS_BIT[layer_name]
35 |
36 |
37 | # Get the layer that corresponds to to the combination of all the passed layer names.
38 | static func get_physics_layer(layer_names: Array, is_layer_3d := false) -> int:
39 | var res: int = 0
40 | for i in range(layer_names.size()):
41 | var layer_bit : int = get_physics_layer_index(layer_names[i], is_layer_3d)
42 | res |= 1 << layer_bit
43 | return res
44 |
45 |
46 | static func get_physics_layer_index(layer_name: String, is_layer_3d := false) -> int:
47 | var res: int
48 | if is_layer_3d:
49 | res = _get_physics_layer_index(_PHYSICS_3D_PREFIX.plus_file(layer_name))
50 | else:
51 | res = _get_physics_layer_index(_PHYSICS_2D_PREFIX.plus_file(layer_name))
52 |
53 | return res
54 |
--------------------------------------------------------------------------------
/addons/godot-next/global/project_tools.gd:
--------------------------------------------------------------------------------
1 | tool
2 | class_name ProjectTools
3 | extends Reference
4 | # author: willnationsdev
5 | # license: MIT
6 | # description: A utility for any features useful in the context of a Godot Project.
7 |
8 | static func try_set_setting(p_name: String, p_default_value, p_pinfo: PropertyInfo) -> bool:
9 | if ProjectSettings.has_setting(p_name):
10 | return false
11 | set_setting(p_name, p_default_value, p_pinfo)
12 | return true
13 |
14 |
15 | static func set_setting(p_name: String, p_default_value, p_pinfo: PropertyInfo) -> void:
16 | ProjectSettings.set_setting(p_name, p_default_value)
17 | ProjectSettings.add_property_info(p_pinfo.to_dict())
18 | ProjectSettings.set_initial_value(p_name, p_default_value)
19 |
--------------------------------------------------------------------------------
/addons/godot-next/global/singletons.gd:
--------------------------------------------------------------------------------
1 | tool
2 | class_name Singletons
3 | extends Reference
4 | # author: xdgamestudios
5 | # license: MIT
6 | # description: An API for accessing singletons
7 | # deps:
8 | # - singleton_cache.tres
9 |
10 | const SINGLETON_CACHE = preload("res://addons/godot-next/data/singleton_cache.tres")
11 |
12 | # Look up a singleton by its script. If it doesn't exist yet, make it.
13 | # If it's a Resource with a persistent file path, load it in from memory.
14 | static func fetch(p_script: Script) -> Object:
15 | var cache: Dictionary = SINGLETON_CACHE.get_cache()
16 | if not cache.has(p_script):
17 | if p_script is Resource:
18 | var path = _get_persistent_path(p_script)
19 | if path:
20 | var paths: Dictionary = SINGLETON_CACHE.get_paths()
21 | cache[p_script] = ResourceLoader.load(path) if ResourceLoader.exists(path) else p_script.new()
22 | paths[p_script] = path
23 | else:
24 | cache[p_script] = p_script.new()
25 | else:
26 | cache[p_script] = p_script.new()
27 | return cache[p_script]
28 |
29 |
30 | # Returns a singleton by its class_name as a String.
31 | static func fetchs(p_name: String) -> Object:
32 | var ct = ClassType.new(p_name)
33 | if ct.res:
34 | return fetch(ct.res)
35 | return null
36 |
37 |
38 | # Returns an editor-only singleton by its class name.
39 | static func fetch_editor(p_class: GDScriptNativeClass) -> Object:
40 | if not Engine.editor_hint:
41 | push_warning("Cannot access '%s' (editor-only class) at runtime." % p_class.get_class())
42 | return null
43 |
44 | var cache: Dictionary = SINGLETON_CACHE.get_cache()
45 | if cache.has(p_class):
46 | return cache[p_class]
47 | return null
48 |
49 |
50 | # Remove a singleton from the cache and any paths associated with it.
51 | static func erase(p_script: Script) -> bool:
52 | var cache: Dictionary = SINGLETON_CACHE.get_cache()
53 | var paths: Dictionary = SINGLETON_CACHE.get_paths()
54 | var erased = cache.erase(p_script)
55 | #warning-ignore:return_value_discarded
56 | paths.erase(p_script)
57 | return erased
58 |
59 |
60 | static func save(p_script: Script) -> void:
61 | var paths: Dictionary = SINGLETON_CACHE.get_paths()
62 | if not paths.has(p_script):
63 | return
64 | var cache: Dictionary = SINGLETON_CACHE.get_cache()
65 | #warning-ignore:return_value_discarded
66 | ResourceSaver.save(paths[p_script], cache[p_script])
67 |
68 |
69 | static func save_all() -> void:
70 | var cache: Dictionary = SINGLETON_CACHE.get_cache()
71 | var paths: Dictionary = SINGLETON_CACHE.get_paths()
72 | for a_script in paths:
73 | #warning-ignore:return_value_discarded
74 | ResourceSaver.save(paths[a_script], cache[a_script])
75 |
76 |
77 | static func _get_persistent_path(p_script: Script):
78 | return p_script.get("SELF_RESOURCE")
79 |
80 |
81 | # Register all editor-only singletons.
82 | static func _register_editor_singletons(plugin: EditorPlugin):
83 | var cache: Dictionary = SINGLETON_CACHE.get_cache()
84 |
85 | cache[UndoRedo] = plugin.get_undo_redo()
86 |
87 | cache[EditorInterface] = plugin.get_editor_interface()
88 |
89 | cache[ScriptEditor] = plugin.get_editor_interface().get_script_editor()
90 | cache[EditorSelection] = plugin.get_editor_interface().get_selection()
91 | cache[EditorSettings] = plugin.get_editor_interface().get_editor_settings()
92 | cache[EditorFileSystem] = plugin.get_editor_interface().get_resource_filesystem()
93 | cache[EditorResourcePreview] = plugin.get_editor_interface().get_resource_previewer()
94 |
--------------------------------------------------------------------------------
/addons/godot-next/global/variant.gd:
--------------------------------------------------------------------------------
1 | tool
2 | class_name Variant
3 | extends Reference
4 | # author: willnationsdev
5 | # license: MIT
6 | # description: A utility class for handling Variants.
7 |
8 | # Returns a string form of all types, but allows Objects to override their string conversion.
9 | static func var_to_string(p_value) -> String:
10 | if typeof(p_value) == TYPE_OBJECT and p_value.has_method("_to_string"):
11 | return p_value._to_string() as String
12 | return var2str(p_value)
13 |
14 |
15 | # Returns the string text of a type's name, for all types.
16 | static func get_type(p_value) -> String:
17 | match typeof(p_value):
18 | TYPE_NIL:
19 | return "null"
20 | TYPE_BOOL:
21 | return "bool"
22 | TYPE_INT:
23 | return "int"
24 | TYPE_REAL:
25 | # can update this to conditionally display "double" once the engine
26 | # adds support for it and sets up an Engine.get_real_type() method or something.
27 | return "float"
28 | TYPE_STRING:
29 | return "String"
30 | TYPE_VECTOR2:
31 | return "Vector2"
32 | TYPE_RECT2:
33 | return "Rect2"
34 | TYPE_VECTOR3:
35 | return "Vector3"
36 | TYPE_TRANSFORM2D:
37 | return "Transform2D"
38 | TYPE_PLANE:
39 | return "Plane"
40 | TYPE_QUAT:
41 | return "Quat"
42 | TYPE_AABB:
43 | return "AABB"
44 | TYPE_BASIS:
45 | return "Basis"
46 | TYPE_TRANSFORM:
47 | return "Transform"
48 | TYPE_COLOR:
49 | return "Color"
50 | TYPE_NODE_PATH:
51 | return "NodePath"
52 | TYPE_RID:
53 | return "RID"
54 | TYPE_OBJECT:
55 | var ct := ClassType.new(p_value)
56 | return ct.get_type_class()
57 | #return p_value.get_class()
58 | TYPE_DICTIONARY:
59 | return "Dictionary"
60 | TYPE_ARRAY:
61 | return "Array"
62 | TYPE_RAW_ARRAY:
63 | return "PoolByteArray"
64 | TYPE_INT_ARRAY:
65 | return "PoolIntArray"
66 | TYPE_REAL_ARRAY:
67 | return "PoolRealArray"
68 | TYPE_STRING_ARRAY:
69 | return "PoolStringArray"
70 | TYPE_VECTOR2_ARRAY:
71 | return "PoolVector2Array"
72 | TYPE_VECTOR3_ARRAY:
73 | return "PoolVector3Array"
74 | TYPE_COLOR_ARRAY:
75 | return "PoolColorArray"
76 | return ""
77 |
--------------------------------------------------------------------------------
/addons/godot-next/godot_next_plugin.gd:
--------------------------------------------------------------------------------
1 | tool
2 | extends EditorPlugin
3 |
4 | const DelegationInspectorPlugin = preload("res://addons/godot-next/inspector_plugins/delegation_inspector_plugin.gd")
5 |
6 | var delegation_inspector_plugin
7 |
8 | func _enter_tree() -> void:
9 | Singletons._register_editor_singletons(self)
10 |
11 | delegation_inspector_plugin = DelegationInspectorPlugin.new()
12 | add_inspector_plugin(delegation_inspector_plugin)
13 |
14 |
15 | func _exit_tree() -> void:
16 | remove_inspector_plugin(delegation_inspector_plugin)
17 |
--------------------------------------------------------------------------------
/addons/godot-next/gui/cycle.gd:
--------------------------------------------------------------------------------
1 | class_name Cycle, "../icons/icon_cycle.svg"
2 | extends TabContainer
3 | # author: willnationsdev
4 | # description: Cycles through child nodes without any visibility or container effects.
5 |
6 | func _init():
7 | tabs_visible = false
8 | self_modulate = Color(1, 1, 1, 0)
9 |
10 |
11 | func _ready():
12 | for a_child in get_children():
13 | if a_child is Control:
14 | (a_child as Control).set_as_toplevel(true)
15 |
16 |
17 | func add_child(p_value: Node, p_legible_unique_name: bool = false):
18 | .add_child(p_value, p_legible_unique_name)
19 | if p_value and p_value is Control:
20 | (p_value as Control).set_as_toplevel(true)
21 |
22 |
23 | func remove_child(p_value: Node):
24 | .remove_child(p_value)
25 | if p_value and p_value is Control:
26 | (p_value as Control).set_as_toplevel(false)
27 |
--------------------------------------------------------------------------------
/addons/godot-next/gui/debug_label.gd:
--------------------------------------------------------------------------------
1 | tool
2 | class_name DebugLabel
3 | extends Label
4 | # author: Xrayez
5 | # license: MIT
6 | # description:
7 | # A label which displays a list of property values in any Object
8 | # instance, suitable for both in-game and editor debugging.
9 | # usage:
10 | # var debug_label = DebugLabel.new(node)
11 | # debug_label.watchv(["position:x", "scale", "rotation"])
12 | #
13 | # todo:
14 | # Use RichTextLabel or custom drawing for color coding of core data types.
15 | # Unfortunately, it doesn't compute its minimum size the same way as a Label
16 |
17 | # Advanced: depending on the properties inspected, you may need to switch
18 | # to either "IDLE" or "PHYSICS" update mode to avoid thread issues.
19 | enum UpdateMode {
20 | IDLE,
21 | PHYSICS,
22 | MANUAL,
23 | }
24 |
25 | export(UpdateMode) var update_mode = UpdateMode.IDLE setget set_update_mode
26 |
27 | # Assign a node via inspector. If empty, a parent node is inspected instead.
28 | export var target_path := NodePath() setget set_target_path
29 |
30 | export var show_label_name := false
31 | export var show_target_name := false
32 |
33 | # A list of property names to be inspected and printed in the `target`.
34 | # Use indexed syntax (:) to access nested properties: "position:x".
35 | # Indexing will also work with any `onready` vars defined via script.
36 | # These can be set beforehand via inspector or via code with "watch()".
37 | export var properties := PoolStringArray()
38 |
39 | # Inspected object, not restricted to "Node" type, may be assigned via code.
40 | var target: Object
41 |
42 | func _init(p_target: Object = null) -> void:
43 | if p_target != null:
44 | target = p_target
45 |
46 | # # TODO: RichTextLabel relevant overrides
47 | # rect_clip_content = false
48 | # scroll_active = false
49 | # selection_enabled = true
50 |
51 |
52 | func _enter_tree() -> void:
53 | set_process_internal(true)
54 |
55 | if not OS.is_debug_build():
56 | text = ""
57 | hide()
58 | return
59 | if target == null:
60 | if not target_path.is_empty():
61 | _update_target_from_path()
62 | else:
63 | target = get_parent()
64 |
65 |
66 | func _exit_tree() -> void:
67 | set_process_internal(false)
68 | set_physics_process_internal(false)
69 |
70 | target = null
71 |
72 |
73 | func _notification(what: int) -> void:
74 | # Using internal processing as it guarantees that
75 | # debug info is updated even if the scene tree is paused.
76 | match what:
77 | NOTIFICATION_INTERNAL_PROCESS:
78 | _update_debug_info()
79 | NOTIFICATION_INTERNAL_PHYSICS_PROCESS:
80 | _update_debug_info()
81 |
82 |
83 | func set_target_path(p_path: NodePath) -> void:
84 | target_path = p_path
85 | call_deferred("_update_target_from_path")
86 |
87 |
88 | func set_update_mode(p_mode: int) -> void:
89 | update_mode = p_mode
90 |
91 | match update_mode:
92 | UpdateMode.IDLE:
93 | set_process_internal(true)
94 | set_physics_process_internal(false)
95 | UpdateMode.PHYSICS:
96 | set_process_internal(false)
97 | set_physics_process_internal(true)
98 | UpdateMode.MANUAL:
99 | set_process_internal(false)
100 | set_physics_process_internal(false)
101 |
102 |
103 | func watch(p_what: String) -> void:
104 | properties = PoolStringArray([p_what])
105 |
106 |
107 | func watchv(p_what: PoolStringArray) -> void:
108 | properties = p_what
109 |
110 |
111 | func watch_append(p_what: String) -> void:
112 | properties.append(p_what)
113 |
114 |
115 | func watch_appendv(p_what: PoolStringArray) -> void:
116 | properties.append_array(p_what)
117 |
118 |
119 | func clear() -> void:
120 | properties = PoolStringArray()
121 |
122 |
123 | func update() -> void:
124 | # Have to be called manually if operating in UpdateMode.MANUAL
125 | _update_debug_info()
126 | .update()
127 |
128 |
129 | func _update_debug_info() -> void:
130 | if not OS.is_debug_build():
131 | return
132 |
133 | text = ""
134 |
135 | if not is_instance_valid(target):
136 | text = "null"
137 | return
138 |
139 | if show_label_name:
140 | text += "%s\n" % [name]
141 |
142 | if show_target_name:
143 | var object_name := String()
144 |
145 | if target is Node:
146 | object_name = target.name
147 | elif target is Resource:
148 | object_name = target.resource_name
149 |
150 | if not object_name.empty():
151 | text += "%s\n" % [object_name]
152 |
153 | for prop in properties:
154 | if prop.empty():
155 | continue
156 | var var_str = var2str(target.get_indexed(prop))
157 | text += "%s = %s\n" % [prop, var_str]
158 |
159 |
160 | func _update_target_from_path() -> void:
161 | if has_node(target_path):
162 | target = get_node(target_path)
163 | # target = get_node_or_null(target_path) # 3.2
164 |
--------------------------------------------------------------------------------
/addons/godot-next/gui/v_box_item_list.gd:
--------------------------------------------------------------------------------
1 | class_name VBoxItemList, "../icons/icon_v_box_item_list.svg"
2 | extends VBoxContainer
3 | # author: willnationsdev
4 | # description: Creates a vertical list of items that can be added or removed. Items are a user-specified Script or Scene Control.
5 | # API details:
6 | # - The '_item_added' and '_item_removed' methods may be overridden for custom behaviors.
7 | # - External nodes can connect to the 'item_added' and 'item_removed' signals for custom reactions.
8 | # - Note that the node provided in the '_item_removed' virtual method and 'item_removed' signal is free'd after their conclusion.
9 | # - Note that the virtual methods will execute just ahead of emitting their signal counterpart.
10 | # - Items may define their own "_get_label" method which returns the string for their label text.
11 | # - If either 'allow_reordering' or 'editable_labels' is true, labels will not be generated automatically via item_prefix + index.
12 |
13 | signal item_inserted(p_index, p_control)
14 | signal item_removed(p_index, p_control)
15 |
16 | const ICON_ADD: Texture = preload("../icons/icon_add.svg")
17 | const ICON_DELETE: Texture = preload("../icons/icon_import_fail.svg")
18 | const ICON_SLIDE: Texture = preload("../icons/icon_mirror_y.svg")
19 |
20 | # The title text at the top of the node.
21 | export var title: String = "" setget set_title
22 | # The script for the item. Incompatible with item_scene.
23 | export var item_script: Script = null setget set_item_script
24 | # The scene for the item. Incompatible with item_script.
25 | export var item_scene: PackedScene = null setget set_item_scene
26 | # label: The prefix text before enumeration, e.g. 'Item' results in Item 1, Item 2, etc.
27 | # If empty, will generate no labels at all unless the item has '_get_label' implemented.
28 | export var item_prefix: String = "" setget set_item_prefix
29 | # label: The color of the highlighted (hovered over) label.
30 | export var label_tint: Color = Color(1, 1, 1, 1) setget set_label_tint
31 | # settings: If true, users may reorder items by dragging from the slide icon. Else the slide icon is hidden.
32 | export var allow_reordering: bool = true setget set_allow_reordering
33 | # settings: If true, users may double-click a label to edit its name. Else no effect.
34 | export var editable_labels: bool = true
35 | # settings: If true, users may click the delete button to delete an item. Else the delete button is hidden.
36 | export var deletable_items: bool = true setget set_deletable_items
37 | # settings: If true, indexes items with size + 1. Else indexes items with a constantly growing ID, i.e. doesn't reset due to item deletion.
38 | export var index_by_size: bool = false
39 |
40 | var label: Label
41 | var add_button: ToolButton
42 | var content: VBoxContainer
43 |
44 | var _dragged_item: HBoxContainer = null
45 | var _hovered_item: HBoxContainer = null
46 | var _insertions: int = 0
47 | var _removals: int = 0
48 |
49 | func _init(p_title: String = "", p_item_prefix: String = "", p_type: Resource = null):
50 | if p_type:
51 | if p_type is Script:
52 | item_script = p_type
53 | elif p_type is PackedScene:
54 | item_scene = p_type
55 | else:
56 | printerr("'p_type' in VBoxItemList.new() is not a Script or PackedScene")
57 |
58 | var main_toolbar := HBoxContainer.new()
59 | main_toolbar.name = "Toolbar"
60 | add_child(main_toolbar)
61 |
62 | label = Label.new()
63 | label.name = "Title"
64 | label.text = p_title
65 | main_toolbar.add_child(label)
66 |
67 | add_button = ToolButton.new()
68 | add_button.icon = ICON_ADD
69 | add_button.name = "AddButton"
70 | #warning-ignore:return_value_discarded
71 | add_button.connect("pressed", self, "append_item")
72 | main_toolbar.add_child(add_button)
73 |
74 | content = VBoxContainer.new()
75 | content.name = "Content"
76 | add_child(content)
77 |
78 | item_prefix = p_item_prefix
79 |
80 |
81 | func _process(_delta: float):
82 | if not get_global_rect().has_point(get_global_mouse_position()):
83 | for a_child in content.get_children():
84 | (a_child.get_node("ItemEdit") as LineEdit).hide()
85 | (a_child.get_node("ItemLabel") as Label).show()
86 |
87 |
88 | #warning-ignore:unused_argument
89 | #warning-ignore:unused_argument
90 | func _item_inserted(p_index: int, p_control: Control):
91 | pass
92 |
93 |
94 | #warning-ignore:unused_argument
95 | #warning-ignore:unused_argument
96 | func _item_removed(p_index: int, p_control: Control):
97 | pass
98 |
99 |
100 | func insert_item(p_index: int) -> Control:
101 | var node: Control = _get_node_from_type()
102 | if not node:
103 | return null
104 |
105 | node.name = "Item"
106 |
107 | var hbox := HBoxContainer.new()
108 | #warning-ignore:return_value_discarded
109 | hbox.connect("gui_input", self, "_on_hbox_gui_input", [hbox])
110 |
111 | var rect := TextureRect.new()
112 | rect.texture = ICON_SLIDE
113 | #warning-ignore:return_value_discarded
114 | rect.connect("gui_input", self, "_on_slide_gui_input", [rect])
115 | rect.name = "ItemSlide"
116 | rect.set_visible(allow_reordering)
117 | hbox.add_child(rect)
118 |
119 | var item_label := Label.new()
120 | item_label.name = "ItemLabel"
121 | hbox.add_child(item_label)
122 |
123 | var item_edit := LineEdit.new()
124 | item_edit.name = "ItemEdit"
125 | item_edit.hide()
126 | #warning-ignore:return_value_discarded
127 | item_edit.connect("text_entered", self, "_on_edit_text_entered", [item_edit, item_label])
128 | hbox.add_child(item_edit)
129 |
130 | hbox.add_child(node)
131 |
132 | var del_btn := ToolButton.new()
133 | del_btn.icon = ICON_DELETE
134 | del_btn.name = "DeleteButton"
135 | if not deletable_items:
136 | del_btn.visible = false
137 | hbox.add_child(del_btn)
138 |
139 | content.add_child(hbox)
140 | if p_index >= 0:
141 | content.move_child(node, p_index)
142 | else:
143 | p_index = len(content.get_children())-1
144 |
145 | _reset_prefix_on_label(item_label, p_index)
146 | #warning-ignore:return_value_discarded
147 | del_btn.connect("pressed", self, "_on_remove_item", [del_btn])
148 | _item_inserted(p_index, node)
149 |
150 | emit_signal("item_inserted", p_index, node)
151 |
152 | _insertions += 1
153 |
154 | return node
155 |
156 |
157 | func get_item(p_index: int) -> Control:
158 | if p_index < 0 or p_index >= len(content.get_children()):
159 | return null
160 | return content.get_child(p_index).get_node("Item") as Control
161 |
162 |
163 | func append_item():
164 | return insert_item(-1)
165 |
166 |
167 | func remove_item(p_idx: int):
168 | var node := content.get_child(p_idx) as HBoxContainer
169 | content.remove_child(node)
170 | if not (allow_reordering or editable_labels):
171 | _reset_prefixes()
172 | _item_removed(p_idx, node)
173 | emit_signal("item_removed", p_idx, node)
174 | if is_instance_valid(node):
175 | node.free()
176 | _removals += 1
177 |
178 |
179 | func _on_remove_item(p_del_btn: ToolButton):
180 | remove_item(p_del_btn.get_parent().get_index())
181 |
182 |
183 | func _on_slide_gui_input(p_event: InputEvent, p_rect: TextureRect):
184 | if p_event is InputEventMouseButton:
185 | var mb := p_event as InputEventMouseButton
186 | if not mb.is_echo() and mb.button_index == BUTTON_LEFT and mb.pressed:
187 | _dragged_item = p_rect.get_parent() as HBoxContainer
188 |
189 |
190 | func _on_hbox_gui_input(p_event: InputEvent, p_hbox: HBoxContainer):
191 | if p_event is InputEventMouseButton:
192 | var mb := p_event as InputEventMouseButton
193 | if not mb.is_echo() and mb.button_index == BUTTON_LEFT and not mb.pressed and _dragged_item:
194 | _dragged_item = null
195 | print(p_hbox, ": stopped dragging")
196 | if mb.doubleclick and editable_labels:
197 | var edit := _hovered_item.get_node("ItemEdit") as LineEdit
198 | var label := _hovered_item.get_node("ItemLabel") as Label
199 | edit.text = label.text
200 | edit.show()
201 | label.hide()
202 |
203 | if p_event is InputEventMouseMotion:
204 | var mm := p_event as InputEventMouseMotion
205 |
206 | if _hovered_item and is_instance_valid(_hovered_item):
207 | (_hovered_item.get_node("ItemLabel") as Label).modulate = Color(1, 1, 1, 1)
208 | _hovered_item = p_hbox
209 | (_hovered_item.get_node("ItemLabel") as Label).modulate = label_tint
210 |
211 | if _dragged_item:
212 | var prev_idx = max(p_hbox.get_index() - 1, 0)
213 | var next_idx = min(p_hbox.get_index() + 1, p_hbox.get_parent().get_child_count() - 1)
214 | var previous = p_hbox.get_parent().get_child(prev_idx)
215 | var next = p_hbox.get_parent().get_child(next_idx)
216 | var moved := false
217 |
218 | if previous.get_global_rect().has_point(mm.global_position):
219 | content.move_child(_dragged_item, prev_idx)
220 | moved = true
221 | elif next.get_global_rect().has_point(mm.global_position):
222 | content.move_child(_dragged_item, next_idx)
223 | moved = true
224 |
225 | if moved:
226 | var del_btn := _dragged_item.get_node("DeleteButton") as ToolButton
227 | if del_btn.is_connected("pressed", self, "remove_item"):
228 | del_btn.disconnect("pressed", self, "remove_item")
229 | #warning-ignore:return_value_discarded
230 | del_btn.connect("pressed", self, "remove_item", [prev_idx])
231 |
232 |
233 | func _on_edit_text_entered(p_text: String, p_edit: LineEdit, p_label: Label):
234 | p_label.text = p_text
235 | p_label.show()
236 | p_edit.hide()
237 |
238 |
239 | func _get_node_from_type() -> Control:
240 | if item_script:
241 | return item_script.new() as Control
242 | elif item_scene:
243 | return item_scene.instance() as Control
244 | else:
245 | return null
246 |
247 |
248 | func _reset_prefixes():
249 | var index: int = 0
250 | for hbox in content.get_children():
251 | var a_label: Label = null
252 | if (hbox as HBoxContainer).has_node("ItemLabel"):
253 | a_label = (hbox as HBoxContainer).get_node("ItemLabel") as Label
254 | _reset_prefix_on_label(a_label, index)
255 | index += 1
256 |
257 |
258 | func _reset_prefix_on_label(p_label: Label, p_index: int = -1):
259 | if not p_label:
260 | return
261 | if content.get_child(p_index).get_node("Item").has_method("_get_label"):
262 | var item := content.get_child(p_index).get_node("Item") as Node
263 | p_label.text = item._get_label() as String
264 | p_label.show()
265 | elif item_prefix:
266 | var idx = p_index
267 | if index_by_size:
268 | if p_index < 0:
269 | idx = len(content.get_children()) - 1
270 | else:
271 | idx = _insertions
272 |
273 | p_label.text = "%s %d" % [item_prefix, idx]
274 | p_label.show()
275 | else:
276 | p_label.hide()
277 |
278 |
279 | func _validate_item_type(p_res: Resource) -> bool:
280 | if not p_res:
281 | return true
282 | var node: Node = null
283 | if p_res is Script:
284 | node = p_res.new() as Control
285 | elif p_res is PackedScene:
286 | node = p_res.instance() as Control
287 | else:
288 | printerr("Item Resource is unassigned.")
289 | return false
290 |
291 | if not node:
292 | printerr("An error occurred in creating a node from the Item Resource.")
293 | return false
294 | elif not node is Control:
295 | printerr("Item Resource does not create a Control.")
296 | return false
297 |
298 | if node is Node:
299 | node.queue_free()
300 |
301 | return true
302 |
303 |
304 | func set_title(p_value: String):
305 | title = p_value
306 | label.text = title
307 |
308 |
309 | func set_item_prefix(p_value: String):
310 | item_prefix = p_value
311 | if not (allow_reordering or editable_labels):
312 | _reset_prefixes()
313 |
314 |
315 | func set_item_script(p_value: Script):
316 | if _validate_item_type(p_value):
317 | item_script = p_value
318 |
319 |
320 | func set_item_scene(p_value: PackedScene):
321 | if _validate_item_type(p_value):
322 | item_scene = p_value
323 |
324 |
325 | func set_allow_reordering(p_value: bool):
326 | allow_reordering = p_value
327 | if _hovered_item:
328 | (_hovered_item.get_node("ItemSlide") as TextureRect).set_visible(p_value)
329 |
330 |
331 | func set_label_tint(p_value: Color):
332 | label_tint = p_value
333 | if _hovered_item:
334 | (_hovered_item.get_node("ItemLabel") as Label).modulate = label_tint
335 |
336 |
337 | func set_deletable_items(p_value: bool):
338 | deletable_items = p_value
339 | for a_hbox in content.get_children():
340 | var del_btn := (a_hbox as HBoxContainer).get_node("DeleteButton") as ToolButton
341 | del_btn.visible = p_value
342 |
--------------------------------------------------------------------------------
/addons/godot-next/icons/icon_add.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/addons/godot-next/icons/icon_add.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/icon_add.svg-d3e2a1bf01ab1646fd533c0ae739c6af.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://addons/godot-next/icons/icon_add.svg"
13 | dest_files=[ "res://.import/icon_add.svg-d3e2a1bf01ab1646fd533c0ae739c6af.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | stream=false
32 | size_limit=0
33 | detect_3d=true
34 | svg/scale=1.0
35 |
--------------------------------------------------------------------------------
/addons/godot-next/icons/icon_cycle.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
101 |
--------------------------------------------------------------------------------
/addons/godot-next/icons/icon_cycle.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/icon_cycle.svg-704a1bd2b44d109f39c24978002f0840.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://addons/godot-next/icons/icon_cycle.svg"
13 | dest_files=[ "res://.import/icon_cycle.svg-704a1bd2b44d109f39c24978002f0840.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | stream=false
32 | size_limit=0
33 | detect_3d=true
34 | svg/scale=1.0
35 |
--------------------------------------------------------------------------------
/addons/godot-next/icons/icon_geometry_2d.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/addons/godot-next/icons/icon_geometry_2d.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/icon_geometry_2d.svg-3e8b75bb6a38693255a76162660a3237.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://addons/godot-next/icons/icon_geometry_2d.svg"
13 | dest_files=[ "res://.import/icon_geometry_2d.svg-3e8b75bb6a38693255a76162660a3237.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | stream=false
32 | size_limit=0
33 | detect_3d=true
34 | svg/scale=1.0
35 |
--------------------------------------------------------------------------------
/addons/godot-next/icons/icon_import_fail.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/addons/godot-next/icons/icon_import_fail.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/icon_import_fail.svg-7ad0927b5823c3399ba221a5daf198eb.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://addons/godot-next/icons/icon_import_fail.svg"
13 | dest_files=[ "res://.import/icon_import_fail.svg-7ad0927b5823c3399ba221a5daf198eb.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | stream=false
32 | size_limit=0
33 | detect_3d=true
34 | svg/scale=1.0
35 |
--------------------------------------------------------------------------------
/addons/godot-next/icons/icon_mirror_y.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/addons/godot-next/icons/icon_mirror_y.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/icon_mirror_y.svg-6c3f2164b83aecbf9b78540511f7cf06.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://addons/godot-next/icons/icon_mirror_y.svg"
13 | dest_files=[ "res://.import/icon_mirror_y.svg-6c3f2164b83aecbf9b78540511f7cf06.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | stream=false
32 | size_limit=0
33 | detect_3d=true
34 | svg/scale=1.0
35 |
--------------------------------------------------------------------------------
/addons/godot-next/icons/icon_trail_2d.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
72 |
--------------------------------------------------------------------------------
/addons/godot-next/icons/icon_trail_2d.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/icon_trail_2d.svg-51013538d456b189cea8a9180694fa86.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://addons/godot-next/icons/icon_trail_2d.svg"
13 | dest_files=[ "res://.import/icon_trail_2d.svg-51013538d456b189cea8a9180694fa86.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | stream=false
32 | size_limit=0
33 | detect_3d=true
34 | svg/scale=1.0
35 |
--------------------------------------------------------------------------------
/addons/godot-next/icons/icon_trail_3d.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
79 |
--------------------------------------------------------------------------------
/addons/godot-next/icons/icon_trail_3d.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/icon_trail_3d.svg-6391c60a03eaeff4d2799492f411ae5b.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://addons/godot-next/icons/icon_trail_3d.svg"
13 | dest_files=[ "res://.import/icon_trail_3d.svg-6391c60a03eaeff4d2799492f411ae5b.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | stream=false
32 | size_limit=0
33 | detect_3d=true
34 | svg/scale=1.0
35 |
--------------------------------------------------------------------------------
/addons/godot-next/icons/icon_v_box_item_list.svg:
--------------------------------------------------------------------------------
1 |
2 |
91 |
--------------------------------------------------------------------------------
/addons/godot-next/icons/icon_v_box_item_list.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/icon_v_box_item_list.svg-883dcb141d0b41e3fd00f437f70206b0.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://addons/godot-next/icons/icon_v_box_item_list.svg"
13 | dest_files=[ "res://.import/icon_v_box_item_list.svg-883dcb141d0b41e3fd00f437f70206b0.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | stream=false
32 | size_limit=0
33 | detect_3d=true
34 | svg/scale=1.0
35 |
--------------------------------------------------------------------------------
/addons/godot-next/inspector_plugins/delegation_inspector_plugin.gd:
--------------------------------------------------------------------------------
1 | tool
2 | extends EditorInspectorPlugin
3 | # author: willnationsdev and xdgamestudios
4 | # license: MIT
5 | # description:
6 | # Attempts to call EditorInspectorPlugin 'parse' methods on every
7 | # object that appears in an EditorInspector anywhere. Enables
8 | # objects to define their own EditorInspector GUI logic without
9 | # the need for additional plugins.
10 |
11 | var obj_stack: Array
12 |
13 | #warning-ignore:unused_argument
14 | func can_handle(p_object: Object) -> bool:
15 | return true
16 |
17 |
18 | func parse_begin(p_object: Object) -> void:
19 | obj_stack.push_back(p_object)
20 | if p_object.has_method("_parse_begin"):
21 | p_object._parse_begin(self)
22 |
23 |
24 | func parse_category(p_object: Object, p_category: String) -> void:
25 | if p_object.has_method("_parse_category"):
26 | p_object._parse_category(self, p_category)
27 |
28 |
29 | func parse_property(p_object: Object, p_type: int, p_path: String, p_hint: int, p_hint_text: String, p_usage: int) -> bool:
30 | if p_object and p_object.has_method("_parse_property"):
31 | var pinfo = PropertyInfo.new(p_path, p_type, p_hint, p_hint_text, p_usage)
32 | return p_object._parse_property(self, pinfo)
33 | return false
34 |
35 |
36 | func parse_end() -> void:
37 | var obj = obj_stack.pop_back()
38 | if obj.has_method("_parse_end"):
39 | obj._parse_end(self)
40 |
--------------------------------------------------------------------------------
/addons/godot-next/nodes/callback_delegator.gd:
--------------------------------------------------------------------------------
1 | tool
2 | class_name CallbackDelegator
3 | extends Node
4 | # author: xdgamestudios
5 | # license: MIT
6 | # description:
7 | # Manages a ResourceSet of resources and delegates Node callbacks to each instance.
8 | # As a ResourceSet, only one element of any given type is allowed on a single elements node.
9 | # deps:
10 | # - ResourceSet
11 | # - PropertyInfo
12 | # - ClassType
13 | # usage:
14 | # - Creating:
15 | # elements = elements.new()
16 | # - Adding elements:
17 | # elements.add_element(MyResource) # Returns a new or pre-existing instance of the element or null if given an invalid element script.
18 | # - Checking elements:
19 | # elements.has_element(MyResource) # Returns true if the element exists in the collection.
20 | # - Retrieving elements:
21 | # elements.get_element(MyResource) # Returns the element instance of the given type or null if not in the collection.
22 | # - Removing elements:
23 | # elements.remove_element(MyResource) # Removes the element from the collection. Returns true if successful. Else, returns false.
24 | # notes:
25 | # - Public interface of each stored Resource type:
26 | # - var owner: Node
27 | # - func get_enabled() -> bool
28 | # - Initialization Sequence:
29 | # 1. _awake() called during _enter_tree() after CallbackDelegator initializes owner (for Unity familiarity).
30 | # 2. _enter_tree() called immediately after (so they are virtually aliases for each other)
31 | # 3. _ready() called during _ready().
32 |
33 | # The collection of Resources. Only one Resource of each type is allowed.
34 | var _elements: ResourceSet = ResourceSet.new()
35 |
36 | # The set of resource instances that have successfully registered themselves to each callback.
37 | var _callbacks: Dictionary = {
38 | "_enter_tree" : {},
39 | "_exit_tree" : {},
40 | "_ready" : {},
41 | "_process" : {},
42 | "_physics_process" : {},
43 | "_input" : {},
44 | "_unhandled_input" : {},
45 | "_unhandled_key_input" : {}
46 | }
47 |
48 | # Assists with inheritance checks and name identification of script classes.
49 | var _class_type: ClassType = ClassType.new()
50 |
51 | func _ready() -> void:
52 | _handle_notification("_ready")
53 |
54 |
55 | # Initialize every element and de-activate any non-essential CallbackDelegator notifications.
56 | func _enter_tree() -> void:
57 | var elements = _elements.get_data().values()
58 | for an_element in elements:
59 | if not an_element.owner:
60 | _initialize_element(an_element)
61 | _check_for_empty_callbacks()
62 |
63 | _handle_notification("_enter_tree")
64 |
65 |
66 | func _exit_tree() -> void:
67 | _handle_notification("_exit_tree")
68 |
69 |
70 | func _process(delta: float) -> void:
71 | _handle_notification("_process", delta)
72 |
73 |
74 | func _physics_process(delta: float) -> void:
75 | _handle_notification("_physics_process", delta)
76 |
77 |
78 | func _input(event: InputEvent) -> void:
79 | _handle_notification("_input", event)
80 |
81 |
82 | func _unhandled_input(event: InputEvent) -> void:
83 | _handle_notification("_unhandled_input", event)
84 |
85 |
86 | func _unhandled_key_input(event: InputEventKey) -> void:
87 | _handle_notification("_unhandled_key_input", event)
88 |
89 |
90 | # Add an element to the CallbackDelegator. Does nothing if no
91 | # base_type is assigned. See `set_base_type(...)`.
92 | func add_element(p_type: Script) -> Resource:
93 | var elements = _elements.get_data()
94 |
95 | _class_type.res = p_type
96 | if not _class_type.is_type(_elements.get_base_type()):
97 | return null
98 | if has_element(p_type):
99 | return get_element(p_type)
100 |
101 | var element: Resource = p_type.new()
102 |
103 | elements[_class_type.get_script_class()] = element
104 | _initialize_element(element)
105 |
106 | return element
107 |
108 |
109 | # Return the element with the same type as p_type.
110 | func get_element(p_type: Script) -> Resource:
111 | var elements = _elements.get_data()
112 | _class_type.res = p_type
113 | return elements.get(_class_type.get_script_class(), null)
114 |
115 |
116 | # Returns true if the element exists in the internal collection.
117 | func has_element(p_type: Script) -> bool:
118 | var elements = _elements.get_data()
119 | _class_type.res = p_type
120 | return elements.has(_class_type.get_script_class())
121 |
122 |
123 | # Returns true if successfully able to remove the element
124 | # from the internal collection. Else, returns false.
125 | func remove_element(p_type: Script) -> bool:
126 | var elements = _elements.get_data()
127 | var element = get_element(p_type)
128 | if element:
129 | _remove_from_callbacks(element)
130 | _class_type.res = p_type
131 | return elements.erase(_class_type.get_script_class())
132 | return false
133 |
134 |
135 | # The order of returned Scripts is not deterministic.
136 | func get_element_types() -> Array:
137 | return _elements.get_data().keys()
138 |
139 |
140 | # The order of returned Resources is not deterministic.
141 | func get_elements() -> Array:
142 | return _elements.get_data().values()
143 |
144 |
145 | func _parse_property(p_inspector: EditorInspectorPlugin, p_pinfo: PropertyInfo) -> void:
146 | match p_pinfo.name:
147 | "_elements":
148 | p_inspector.add_custom_control(InspectorControls.new_button("Initialize Default Behavior", false, self, "_set_base_type_behavior"))
149 |
150 |
151 | func _get_property_list() -> Array:
152 | return [ PropertyInfoFactory.new_resource("_elements").to_dict() ]
153 |
154 |
155 | # Helper method to facilitate delegation of the callback.
156 | func _handle_notification(p_name: String, p_param = null) -> void:
157 | if Engine.editor_hint:
158 | return
159 | if p_param:
160 | for an_element in _callbacks[p_name]:
161 | an_element.call(p_name, p_param)
162 | else:
163 | for an_element in _callbacks[p_name]:
164 | an_element.call(p_name)
165 |
166 |
167 | # Setup the owner and initialization of the element. Ensure it updates its callbacks if the script is modified.
168 | func _initialize_element(p_element: Resource) -> void:
169 | _awake(p_element)
170 | #warning-ignore:return_value_discarded
171 | p_element.connect("script_changed", self, "_refresh_callbacks", [p_element])
172 | _add_to_callbacks(p_element)
173 |
174 |
175 | # Register necessary callbacks for the element.
176 | func _add_to_callbacks(p_element: Resource) -> void:
177 | for a_callback in _callbacks:
178 | if p_element.has_method(a_callback) and p_element.get_enabled():
179 | _callbacks[a_callback][p_element] = null
180 |
181 |
182 | # Unregister all callbacks for the element.
183 | func _remove_from_callbacks(p_element: Resource) -> void:
184 | for a_callback in _callbacks:
185 | _callbacks[a_callback].erase(p_element)
186 | _check_for_empty_callbacks()
187 |
188 |
189 | # Only delegate the call if a callback-implementing, enabled resource relies on it.
190 | func _check_for_empty_callbacks() -> void:
191 | for a_callback in _callbacks:
192 | match a_callback:
193 | "_process":
194 | set_process(not _callbacks[a_callback].empty())
195 | "_physics_process":
196 | set_physics_process(not _callbacks[a_callback].empty())
197 | "_input":
198 | set_process_input(not _callbacks[a_callback].empty())
199 | "_unhandled_input":
200 | set_process_unhandled_input(not _callbacks[a_callback].empty())
201 | "_unhandled_key_input":
202 | set_process_unhandled_key_input(not _callbacks[a_callback].empty())
203 |
204 |
205 | # Sets up the owner instance on the Behavior.
206 | func _awake(p_element: Resource) -> void:
207 | p_element.owner = self
208 | if p_element.has_method("_awake"):
209 | p_element._awake()
210 |
211 |
212 | # Reset callback registrations in the event that the script is modified.
213 | func _on_element_script_change(p_element: Resource) -> void:
214 | _remove_from_callbacks(p_element)
215 | _add_to_callbacks(p_element)
216 |
217 |
218 | func _set_base_type_behavior() -> void:
219 | _class_type.name = "Behavior"
220 | _elements.set_base_type(_class_type.res)
221 |
--------------------------------------------------------------------------------
/addons/godot-next/nodes/message_dispatcher_wrapper.gd:
--------------------------------------------------------------------------------
1 | class_name MessageDispatcherWrapper
2 | extends Node
3 | # author: MunWolf (Rikhardur Bjarni Einarsson)
4 | # license: MIT
5 | # copyright: Copyright (c) 2019 Rikhardur Bjarni Einarsson
6 | # description:
7 | # A wrapper for MessageDispatcher that is extendable on a Node,
8 | # people can also use this as a template to implement it on
9 | # their own if they want to extend something else.
10 |
11 | var _message_dispatcher = MessageDispatcher.new()
12 |
13 | # See same function on MessageDispatcher.
14 | func connect_message(message_type: String, obj: Object, function: String) -> void:
15 | _message_dispatcher.connect_message(message_type, obj, function)
16 |
17 |
18 | # See same function on MessageDispatcher.
19 | func disconnect_message(message_type: String, obj: Object, function: String) -> void:
20 | _message_dispatcher.disconnect_message(message_type, obj, function)
21 |
22 |
23 | # See same function on MessageDispatcher.
24 | func disconnect_all_message() -> void:
25 | _message_dispatcher.disconnect_all_message()
26 |
27 |
28 | # See same function on MessageDispatcher.
29 | func emit_message(message_type: String, message_data: Dictionary) -> bool:
30 | return _message_dispatcher.emit_message(message_type, message_data)
31 |
--------------------------------------------------------------------------------
/addons/godot-next/plugin.cfg:
--------------------------------------------------------------------------------
1 | [plugin]
2 |
3 | name="Godot Node Extensions"
4 | description="A plugin filled with basic type extensions and utilities for Godot."
5 | author="Will Nations"
6 | version="1.0"
7 | script="godot_next_plugin.gd"
8 |
--------------------------------------------------------------------------------
/addons/godot-next/references/array_2d.gd:
--------------------------------------------------------------------------------
1 | class_name Array2D
2 | extends Reference
3 | # author: willnationsdev
4 | # description: A 2D Array class
5 |
6 | var data: Array = []
7 |
8 |
9 | func _init(p_array: Array = [], p_deep_copy : bool = true):
10 | if p_deep_copy:
11 | for row in p_array:
12 | if row is Array:
13 | data.append(row.duplicate())
14 | else:
15 | data = p_array
16 |
17 |
18 | func get_data() -> Array:
19 | return data
20 |
21 |
22 | func has_cell(p_row: int, p_col: int) -> bool:
23 | return len(data) > p_row and len(data[p_row]) > p_col
24 |
25 |
26 | func set_cell(p_row: int, p_col: int, p_value):
27 | assert(has_cell(p_row, p_col))
28 | data[p_row][p_col] = p_value
29 |
30 |
31 | func get_cell(p_row: int, p_col: int):
32 | assert(has_cell(p_row, p_col))
33 | return data[p_row][p_col]
34 |
35 |
36 | func set_cell_if_exists(p_row: int, p_col: int, p_value) -> bool:
37 | if has_cell(p_row, p_col):
38 | set_cell(p_row, p_col, p_value)
39 | return true
40 | return false
41 |
42 |
43 | func has_cellv(p_pos: Vector2) -> bool:
44 | return len(data) > p_pos.x and len(data[p_pos.x]) > p_pos.y
45 |
46 |
47 | func set_cellv(p_pos: Vector2, p_value):
48 | assert(has_cellv(p_pos))
49 | data[p_pos.x][p_pos.y] = p_value
50 |
51 |
52 | func get_cellv(p_pos: Vector2):
53 | assert(has_cellv(p_pos))
54 | return data[p_pos.x][p_pos.y]
55 |
56 |
57 | func set_cellv_if_exists(p_pos: Vector2, p_value) -> bool:
58 | if has_cellv(p_pos):
59 | set_cellv(p_pos, p_value)
60 | return true
61 | return false
62 |
63 |
64 | func get_row(p_idx: int):
65 | assert(len(data) > p_idx)
66 | assert(p_idx >= 0)
67 | return data[p_idx].duplicate()
68 |
69 |
70 | func get_col(p_idx: int):
71 | var result = []
72 | for a_row in data:
73 | assert(len(a_row) > p_idx)
74 | assert(p_idx >= 0)
75 | result.push_back(a_row[p_idx])
76 | return result
77 |
78 |
79 | func get_row_ref(p_idx: int):
80 | assert(len(data) > p_idx)
81 | assert(p_idx >= 0)
82 | return data[p_idx]
83 |
84 |
85 | func get_rows() -> Array:
86 | return data
87 |
88 |
89 | func set_row(p_idx: int, p_row):
90 | assert(len(data) > p_idx)
91 | assert(p_idx >= 0)
92 | assert(len(data) == len(p_row))
93 | data[p_idx] = p_row
94 |
95 |
96 | func set_col(p_idx: int, p_col):
97 | assert(len(data) > 0 and len(data[0]) > 0)
98 | assert(len(data) == len(p_col))
99 | var idx = 0
100 | for a_row in data:
101 | assert(len(a_row) > p_idx)
102 | assert(p_idx >= 0)
103 | a_row[p_idx] = p_col[idx]
104 | idx += 1
105 |
106 |
107 | func insert_row(p_idx: int, p_array: Array):
108 | if p_idx < 0:
109 | data.append(p_array)
110 | else:
111 | data.insert(p_idx, p_array)
112 |
113 |
114 | func insert_col(p_idx: int, p_array: Array):
115 | var idx = 0
116 | for a_row in data:
117 | if p_idx < 0:
118 | a_row.append(p_array[idx])
119 | else:
120 | a_row.insert(p_idx, p_array[idx])
121 | idx += 1
122 |
123 |
124 | func append_row(p_array: Array):
125 | insert_row(-1, p_array)
126 |
127 |
128 | func append_col(p_array: Array):
129 | insert_col(-1, p_array)
130 |
131 |
132 | func sort_row(p_idx: int):
133 | _sort_axis(p_idx, true)
134 |
135 |
136 | func sort_col(p_idx: int):
137 | _sort_axis(p_idx, false)
138 |
139 |
140 | func sort_row_custom(p_idx: int, p_obj: Object, p_func: String):
141 | _sort_axis_custom(p_idx, true, p_obj, p_func)
142 |
143 |
144 | func sort_col_custom(p_idx: int, p_obj: Object, p_func: String):
145 | _sort_axis_custom(p_idx, false, p_obj, p_func)
146 |
147 |
148 | func duplicate() -> Reference:
149 | return load(get_script().resource_path).new(data)
150 |
151 |
152 | func hash() -> int:
153 | return hash(self)
154 |
155 |
156 | func shuffle():
157 | for a_row in data:
158 | a_row.shuffle()
159 |
160 |
161 | func empty() -> bool:
162 | return len(data) == 0
163 |
164 |
165 | func size() -> int:
166 | if len(data) <= 0:
167 | return 0
168 | return len(data) * len(data[0])
169 |
170 |
171 | func resize(p_height: int, p_width: int):
172 | data.resize(p_height)
173 | for i in range(len(data)):
174 | data[i] = []
175 | data[i].resize(p_width)
176 |
177 |
178 | func resizev(p_dimensions: Vector2):
179 | resize(int(p_dimensions.x), int(p_dimensions.y))
180 |
181 |
182 | func clear():
183 | data = []
184 |
185 |
186 | func fill(p_value):
187 | for a_row in range(data.size()):
188 | for a_col in range(data[a_row].size()):
189 | data[a_row][a_col] = p_value
190 |
191 |
192 | func fill_row(p_idx: int, p_value):
193 | assert(p_idx >= 0)
194 | assert(len(data) > p_idx)
195 | assert(len(data[0]) > 0)
196 | var arr = []
197 | for i in len(data[0]):
198 | arr.push_back(p_value)
199 | data[p_idx] = arr
200 |
201 |
202 | func fill_col(p_idx: int, p_value):
203 | assert(p_idx >= 0)
204 | assert(len(data) > 0)
205 | assert(len(data[0]) > p_idx)
206 | var arr = []
207 | for i in len(data):
208 | arr.push_back(p_value)
209 | set_col(p_idx, arr)
210 |
211 |
212 | func remove_row(p_idx: int):
213 | assert(p_idx >= 0)
214 | assert(len(data) > p_idx)
215 | data.remove(p_idx)
216 |
217 |
218 | func remove_col(p_idx: int):
219 | assert(len(data) > 0)
220 | assert(p_idx >= 0 and len(data[0]) > p_idx)
221 | for a_row in data:
222 | a_row.remove(p_idx)
223 |
224 |
225 | func count(p_value) -> int:
226 | var count = 0
227 | for a_row in data:
228 | for a_col in a_row:
229 | if p_value == data[a_row][a_col]:
230 | count += 1
231 | return count
232 |
233 |
234 | func has(p_value) -> bool:
235 | for a_row in data:
236 | for a_col in a_row:
237 | if p_value == data[a_row][a_col]:
238 | return true
239 | return false
240 |
241 |
242 | func invert() -> Reference:
243 | data.invert()
244 | return self
245 |
246 |
247 | func invert_row(p_idx: int) -> Reference:
248 | assert(p_idx >= 0 and len(data) > p_idx)
249 | data[p_idx].invert()
250 | return self
251 |
252 |
253 | func invert_col(p_idx: int) -> Reference:
254 | assert(len(data) > 0)
255 | assert(p_idx >= 0 and len(data[0]) > p_idx)
256 | var col = get_col(p_idx)
257 | col.invert()
258 | set_col(p_idx, col)
259 | return self
260 |
261 |
262 | func bsearch_row(p_idx: int, p_value, p_before: bool) -> int:
263 | assert(p_idx >= 0 and len(data) > p_idx)
264 | return data[p_idx].bsearch(p_value, p_before)
265 |
266 |
267 | func bsearch_col(p_idx: int, p_value, p_before: bool) -> int:
268 | assert(len(data) > 0)
269 | assert(p_idx >= 0 and len(data[0]) > p_idx)
270 | var col = get_col(p_idx)
271 | col.sort()
272 | return col[p_idx].bsearch(p_value, p_before)
273 |
274 |
275 | func find(p_value) -> Vector2:
276 | for a_row in data:
277 | for a_col in a_row:
278 | if p_value == data[a_row][a_col]:
279 | return Vector2(a_row, a_col)
280 | return Vector2(-1, -1)
281 |
282 |
283 | func rfind(p_value) -> Vector2:
284 | var i: int = len(data) - 1
285 | var j: int = len(data[0]) - 1
286 | while i:
287 | while j:
288 | if p_value == data[i][j]:
289 | return Vector2(i, j)
290 | j -= 1
291 | i -= 1
292 | return Vector2(-1, -1)
293 |
294 |
295 | func transpose() -> Reference:
296 | var width : int = len(data)
297 | var height : int = len(data[0])
298 | var transposed_matrix : Array
299 | for i in range(height):
300 | transposed_matrix.append([])
301 | var h : int = 0
302 | while h < height:
303 | for w in range(width):
304 | transposed_matrix[h].append(data[w][h])
305 | h += 1
306 | return load(get_script().resource_path).new(transposed_matrix, false)
307 |
308 |
309 | func _to_string() -> String:
310 | var ret: String
311 | var width: int = len(data)
312 | var height: int = len(data[0])
313 | for h in range(height):
314 | for w in range(width):
315 | ret += "[" + str(data[w][h]) + "]"
316 | if w == width - 1 and h != height -1:
317 | ret += "\n"
318 | else:
319 | if w == width - 1:
320 | ret += "\n"
321 | else:
322 | ret += ", "
323 | return ret
324 |
325 |
326 | func _sort_axis(p_idx: int, p_is_row: bool):
327 | if p_is_row:
328 | data[p_idx].sort()
329 | return
330 | var col = get_col(p_idx)
331 | col.sort()
332 | set_col(p_idx, col)
333 |
334 |
335 | func _sort_axis_custom(p_idx: int, p_is_row: bool, p_obj: Object, p_func: String):
336 | if p_is_row:
337 | data[p_idx].sort_custom(p_obj, p_func)
338 | return
339 | var col = get_col(p_idx)
340 | col.sort_custom(p_obj, p_func)
341 | set_col(p_idx, col)
342 |
--------------------------------------------------------------------------------
/addons/godot-next/references/bit_flag.gd:
--------------------------------------------------------------------------------
1 | tool
2 | class_name BitFlag
3 | extends Reference
4 | # author: xdgamestudios
5 | # license: MIT
6 | # description: A class that allows abstracts away the complexity of handling bit flag enum types.
7 | # todo: Implement additional features
8 | # usage:
9 | # - Initial setup:
10 | # enum my_enum { a, b, c }
11 | #
12 | # - Creating:
13 | # bf = BitFlag.new(my_enum, to_flag = false) # Creates a new BitFlag given an enum. If 'to_flag' converts to flag enum
14 | # - Flag access:
15 | # bf. = true/false # Allows to set the current bit
16 | # - Set/Put flag:
17 | # bf.put(bf.a) # Enables the flag 'a'. Another BitFlag can be provided.
18 | # - Clear flag:
19 | # bf.clear(bf.b) # Disables the flag 'b'. Another BitFlag can be provided.
20 | # - Toggle flag:
21 | # bf.toggle(bf.b) # Inverts the flag 'b'. Another BitFlag can be provided.
22 | # - Check flag:
23 | # bf.check(bf.b) # Checks flag 'b'. Another BitFlag can be provided.
24 | # - Get flag names:
25 | # bf.get_active_keys() # Returns an array of active keys.
26 | # bf.get_active_keys_raw() # Returns the integer represented by the flag, example: a=true,b=true,c=false will return 3
27 | # bf.get_keys() # Returns an array of all flag keys.
28 | # - Convert to PropertyInfo dict
29 | # bf.to_pinfo_dict("property_name") # Returns a dictionary with export structure.
30 |
31 | var _enum: Dictionary = {}
32 | var _flags: int = 0 setget set_flags, get_flags
33 |
34 | func _init(p_enum: Dictionary, p_to_flag: bool = false):
35 | if p_to_flag:
36 | for a_key in p_enum:
37 | _enum[a_key] = 1 << p_enum[a_key]
38 | else:
39 | _enum = p_enum
40 |
41 |
42 | func _get(p_property: String) -> int:
43 | if _enum.has(p_property):
44 | return _enum[p_property]
45 | return 0
46 |
47 |
48 | func _set(p_property: String, p_value: bool) -> bool:
49 | if _enum.has(p_property):
50 | if p_value:
51 | _flags |= _enum[p_property]
52 | else:
53 | _flags &= _enum[p_property]
54 | return true
55 | return false
56 |
57 |
58 | func _get_value_flags(p_value) -> int:
59 | match typeof(p_value):
60 | TYPE_OBJECT:
61 | if p_value.get_script() == get_script():
62 | return p_value._flags
63 | TYPE_INT:
64 | return p_value
65 | assert(false)
66 | return -1
67 |
68 |
69 | func put(p_value) -> int:
70 | if p_value == null:
71 | return _flags
72 | _flags |= _get_value_flags(p_value)
73 | return _flags
74 |
75 |
76 | func clear(p_value) -> int:
77 | if p_value == null:
78 | return _flags
79 | _flags &= ~(_get_value_flags(p_value))
80 | return _flags
81 |
82 |
83 | func toggle(p_value) -> int:
84 | if p_value == null:
85 | return _flags
86 | _flags ^= _get_value_flags(p_value)
87 | return _flags
88 |
89 |
90 | func check(p_value) -> bool:
91 | if p_value == null:
92 | return false
93 | var flags: int = _get_value_flags(p_value)
94 | return (_flags & flags) == flags
95 |
96 |
97 | func get_active_keys() -> Array:
98 | var out: Array = []
99 | for a_flag in _enum:
100 | if check(_enum[a_flag]):
101 | out.append(a_flag)
102 | return out
103 |
104 | func get_active_keys_raw() -> int:
105 | var value = 0
106 | for a_flag in _enum:
107 | if check(_enum[a_flag]):
108 | value += _get(a_flag)
109 | return value
110 |
111 | func get_keys() -> Array:
112 | return _enum.keys()
113 |
114 |
115 | func to_pinfo_dict(p_name: String) -> Dictionary:
116 | var hint_string = PoolStringArray(get_keys()).join(",")
117 | return PropertyInfo.new(p_name, TYPE_INT, PROPERTY_HINT_FLAGS, hint_string).to_dict()
118 |
119 |
120 | func get_flags() -> int:
121 | return _flags
122 |
123 |
124 | func set_flags(p_value) -> void:
125 | if p_value == null:
126 | return
127 | _flags = _get_value_flags(p_value)
128 |
--------------------------------------------------------------------------------
/addons/godot-next/references/bitset.gd:
--------------------------------------------------------------------------------
1 | class_name Bitset
2 | extends Reference
3 | # author: milesturin
4 | # license: MIT
5 | # description: A class that allows for easily manipulated bitmasks of any size
6 | # usage:
7 | # By setting enforce_soft_size to false, the Bitset will allow the user to access
8 | # bits that have been reserved by the script, but are outside of the requested size.
9 |
10 | const MASK_SIZE := 32
11 |
12 | var bitmasks: PoolIntArray = []
13 | var bits: int
14 |
15 | func _init(size: int, default_state: bool = false, enforce_soft_size: bool = true) -> void:
16 | resize(size, default_state, enforce_soft_size)
17 |
18 |
19 | func resize(size: int, default_state: bool = false, enforce_soft_size: bool = true) -> void:
20 | assert(size >= 0)
21 | var old_masks := bitmasks.size()
22 | if old_masks > 0 and bits % MASK_SIZE:
23 | if default_state:
24 | bitmasks[old_masks - 1] |= (~0 << (bits % MASK_SIZE))
25 | else:
26 | bitmasks[old_masks - 1] &= ~((~0) << (bits % MASK_SIZE))
27 | bitmasks.resize(ceil(size / float(MASK_SIZE)))
28 | bits = size if enforce_soft_size else bitmasks.size() * MASK_SIZE
29 | for i in range(old_masks, bitmasks.size()):
30 | bitmasks[i] = ~0 if default_state else 0
31 |
32 |
33 | func check_bit(index: int) -> bool:
34 | assert(index < bits)
35 | return bitmasks[index / MASK_SIZE] & (1 << (index % MASK_SIZE)) != 0
36 |
37 |
38 | func set_bit(index: int, state: bool) -> void:
39 | assert(index < bits)
40 | if state:
41 | bitmasks[index / MASK_SIZE] |= (1 << (index % MASK_SIZE))
42 | else:
43 | bitmasks[index / MASK_SIZE] &= ~(1 << (index % MASK_SIZE))
44 |
45 |
46 | func flip_bit(index: int) -> void:
47 | assert(index < bits)
48 | set_bit(index, !check_bit(index))
49 |
50 |
51 | func print_bits(multiline: bool = true) -> void:
52 | if multiline:
53 | for i in range(bits):
54 | print("bit " + String(i) + ": " + String(check_bit(i)))
55 | else:
56 | var output := ""
57 | for i in range(bits):
58 | output += '1' if check_bit(i) else '0'
59 | print(output)
60 |
--------------------------------------------------------------------------------
/addons/godot-next/references/csv_file.gd:
--------------------------------------------------------------------------------
1 | tool
2 | class_name CSVFile
3 | extends Reference
4 | # author: willnationsdev
5 | # description: Provides utilities for loading, saving, and editing CSV files.
6 | # dependencies: Array2D
7 | # API details:
8 | # - The data is stored internally as an Array2D. The 0th row is the headers.
9 | # - Use 'get_array()' to fetch the Array2D
10 | # - Use 'get_headers()' to get a Dictionary of the headers (values are their index in the first row)
11 | # - Use 'get_map()' to get a Dictionary of string keys to rows.
12 | # - if '_uses_map' is true, the key will be generated from the '_get_key()' virtual method (defaults to returning row[0]).
13 | # Else _map will be empty. Defaults to false.
14 | # - The CSVFile object dynamically generates properties that match the keys of the _map Dictionary.
15 | # - A .tsv file can be made simply by changing the '_sep' property to "\t".
16 |
17 | signal file_loaded(p_filepath)
18 | signal file_saved(p_filepath)
19 |
20 | const DEFAULT_SEP = ","
21 | const DEFAULT_QUOTE = "\""
22 |
23 | var _filepath := ""
24 |
25 | var _array := Array2D.new()
26 | var _headers := {}
27 | var _map := {}
28 |
29 | var _sep := DEFAULT_SEP
30 | var _quote := DEFAULT_QUOTE
31 | var _uses_map := true
32 |
33 | func _init(p_sep: String = DEFAULT_SEP, p_quote: String = DEFAULT_QUOTE, p_uses_map: bool = true):
34 | _sep = p_sep
35 | _quote = p_quote
36 | _uses_map = p_uses_map
37 |
38 |
39 | func _get(p_property):
40 | if _map.has(p_property):
41 | return _map[p_property]
42 |
43 |
44 | func _set(p_property, p_value):
45 | if _map.has(p_property):
46 | _map[p_property] = p_value
47 |
48 |
49 | func _get_property_list():
50 | var ret := []
51 | for a_key in _map:
52 | ret.append({
53 | "name": a_key,
54 | "type": typeof(_map[a_key])
55 | })
56 | return ret
57 |
58 |
59 | func _get_key(p_row: Array) -> String:
60 | if not p_row:
61 | return ""
62 | return p_row[0]
63 |
64 |
65 | func load_file(p_filepath: String) -> int:
66 | var f = File.new()
67 | var err = f.open(p_filepath, File.READ)
68 | if err != OK:
69 | return err
70 | _headers.clear()
71 | _map.clear()
72 | _array.clear()
73 |
74 | var headers = _parse_line(f.get_line())
75 | _array.append_row(headers)
76 | for i in range(headers.size()):
77 | _headers[headers[i]] = i
78 |
79 | if not _uses_map:
80 | for a_header in _headers:
81 | _map[a_header] = []
82 |
83 | #warning-ignore:unused_variable
84 | var line: String
85 | while not f.eof_reached():
86 | var row = _parse_line(f.get_line())
87 | if _uses_map:
88 | _map[_get_key(row)] = row
89 | _array.append_row(row)
90 |
91 | f.close()
92 | _filepath = p_filepath
93 | emit_signal("file_loaded", p_filepath)
94 | return OK
95 |
96 |
97 | func save_file(p_filepath: String) -> int:
98 | var f := File.new()
99 | var err := f.open(p_filepath, File.WRITE)
100 | if err != OK:
101 | return err
102 | for a_row in _array.data:
103 | var strings := PoolStringArray()
104 | for a_cell in a_row:
105 | var text := str(a_cell)
106 | text = text.replace(_quote, _quote + _quote)
107 | if text.find(_sep) != -1:
108 | text = _quote + text + _quote
109 | strings.push_back(text)
110 | f.store_line(strings.join(_sep))
111 | f.close()
112 | emit_signal("file_saved", p_filepath)
113 | return OK
114 |
115 |
116 | func get_headers() -> Dictionary:
117 | return _headers
118 |
119 |
120 | func get_map() -> Dictionary:
121 | return _map
122 |
123 |
124 | func get_array2d() -> Array2D:
125 | return _array
126 |
127 |
128 | func map_has_value(p_key: String, p_header: String) -> bool:
129 | return _map.has(p_key) and _headers.has(p_header)
130 |
131 |
132 | func map_get_value(p_key: String, p_header: String):
133 | if not _uses_map:
134 | printerr("CSVFile is not using map, but 'get_map_value' was called")
135 | return null
136 | if not map_has_value(p_key, p_header):
137 | return null
138 | return _map[p_key][_headers[p_header]]
139 |
140 |
141 | func map_set_value(p_key: String, p_header: String, p_value):
142 | if not _uses_map:
143 | printerr("CSVFile is not using map, but 'get_map_value' was called")
144 | return null
145 | if not map_has_value(p_key, p_header):
146 | return null
147 | _map[p_key][_headers[p_header]] = p_value
148 |
149 |
150 | func _parse_line(p_line: String) -> Array:
151 | if not p_line:
152 | return []
153 |
154 | var ret := []
155 | var val := ""
156 |
157 | var in_quotes := false
158 | var start_collect_char := false
159 | var double_quotes_in_column := false
160 |
161 | var chars := p_line.to_utf8()
162 | for a_char in chars:
163 | var s := char(a_char)
164 | if in_quotes:
165 | start_collect_char = true
166 | if s == _sep:
167 | in_quotes = false
168 | double_quotes_in_column = false
169 | else:
170 | if s == "\"":
171 | if not double_quotes_in_column:
172 | val += s
173 | double_quotes_in_column = true
174 | else:
175 | val += s
176 | else:
177 | if s == _quote:
178 | in_quotes = true
179 |
180 | if p_line[0] != "\"" and _quote == "\"":
181 | val += "\""
182 |
183 | if start_collect_char:
184 | val += "\""
185 | elif s == _sep:
186 | ret.append(val)
187 | val = ""
188 | start_collect_char = false
189 | elif s == "\r":
190 | continue
191 | elif s == "\n":
192 | break
193 | else:
194 | val += s
195 | ret.append(val)
196 | return ret
197 |
--------------------------------------------------------------------------------
/addons/godot-next/references/inflector.gd:
--------------------------------------------------------------------------------
1 | tool
2 | class_name Inflector
3 | extends Reference
4 | # author: xdgamestudios (adapted from C# .NET Humanizer, licensed under MIT)
5 | # license: MIT
6 | # description: Provides inflection tools to pluralize and singularize strings.
7 | # todo: Add more functionality
8 | # usage:
9 | # - Creating Inflector:
10 | # inflector = Inflector.new() # new inflector with empty vocabulary
11 | # inflector = Inflector.new(vocabulary) # new inflector with vocabulary
12 | # Note:
13 | # - Inflector with no vocabulary will not be able to apply convertion out-of-the-box.
14 | # - Creating Vocabulary:
15 | # vocabulary = Inflector.Vocabulary.new() # creates new empty vocabulary
16 | # vocabulary = Inflector.Vocabulary.build_default_vocabulary()
17 | # Note:
18 | # - Empty vocabulary can be manually configured with custom rules.
19 | # - Default vocabulary will apply convertions for english language.
20 | # - Get Vocabulary:
21 | # vocabulary = inflector.get_vocabulary() # reference to the vocabulary used by the inflector.
22 | # - Add Rules:
23 | # vocabulary.add_plural(rule, replacement) # adds convertion rule to plural
24 | # vocabulary.add_singular(rule, replacement) # adds convertion rule to singular
25 | # vocabulary.add_irregular(rule, replacement) # adds irregular convertion
26 | # vocabulary.add_uncountable(word) # add unconvertable word
27 | # Note:
28 | # - 'rule' is a String with regex syntax.
29 | # - 'replacement' is a String with regex systax.
30 | # - Using Inflector:
31 | # inflector.pluralize(word, p_force = false) # returns the plural of the word
32 | # inflector.singularize(word, p_force = false) # returns the singular of the word
33 | # Note:
34 | # - If the first parameter's state is unknown, use 'p_force = true' to force an unknown term into the desired state.
35 |
36 | class Rule extends Reference:
37 | var _regex: RegEx
38 | var _replacement: String
39 |
40 | func _init(p_rule: String, p_replacement: String) -> void:
41 | _regex = RegEx.new()
42 | #warning-ignore:return_value_discarded
43 | _regex.compile(p_rule)
44 | _replacement = p_replacement
45 |
46 |
47 | func apply(p_word: String):
48 | if not _regex.search(p_word):
49 | return null
50 | return _regex.sub(p_word, _replacement)
51 |
52 |
53 | class Vocabulary extends Reference:
54 | var _plurals: Array = [] setget, get_plurals
55 | var _singulars: Array = [] setget, get_singulars
56 | var _uncountables: Array = [] setget, get_uncountables
57 |
58 |
59 | func get_plurals() -> Array:
60 | return _plurals
61 |
62 |
63 | func get_singulars() -> Array:
64 | return _singulars
65 |
66 |
67 | func get_uncountables() -> Array:
68 | return _uncountables
69 |
70 |
71 | func add_plural(p_rule: String, p_replacement: String) -> void:
72 | _plurals.append(Rule.new(p_rule, p_replacement))
73 |
74 |
75 | func add_singular(p_rule: String, p_replacement: String) -> void:
76 | _singulars.append(Rule.new(p_rule, p_replacement))
77 |
78 |
79 | func add_irregular(p_singular: String, p_plural: String, p_match_ending: bool = true) -> void:
80 | if p_match_ending:
81 | var sfirst = p_singular[0]
82 | var pfirst = p_plural[0]
83 | var strimmed = p_singular.trim_prefix(sfirst)
84 | var ptrimmed = p_plural.trim_prefix(pfirst)
85 | add_plural("(" + sfirst + ")" + strimmed + "$", "$1" + ptrimmed)
86 | add_singular("(" + pfirst + ")" + ptrimmed + "$", "$1" + strimmed)
87 | else:
88 | add_plural("^%s$" % p_singular, p_plural)
89 | add_singular("^%s$" % p_plural, p_singular)
90 |
91 |
92 | func add_uncountable(p_word: String) -> void:
93 | _uncountables.append(p_word.to_lower())
94 |
95 |
96 | func is_uncountable(p_word: String) -> bool:
97 | return _uncountables.has(p_word.to_lower())
98 |
99 |
100 | static func build_default_vocabulary() -> Vocabulary:
101 | var vocabulary = Vocabulary.new()
102 |
103 | # Plural rules.
104 | vocabulary._plurals = [
105 | Rule.new("$", "s"),
106 | Rule.new("s$", "s"),
107 | Rule.new("(ax|test)is$", "$1es"),
108 | Rule.new("(octop|vir|alumn|fung|cact|foc|hippopotam|radi|stimul|syllab|nucle)us$", "$1i"),
109 | Rule.new("(alias|bias|iris|status|campus|apparatus|virus|walrus|trellis)$", "$1es"),
110 | Rule.new("(buffal|tomat|volcan|ech|embarg|her|mosquit|potat|torped|vet)o$", "$1oes"),
111 | Rule.new("([dti])um$", "$1a"),
112 | Rule.new("sis$", "ses"),
113 | Rule.new("([lr])f$", "$1ves"),
114 | Rule.new("([^f])fe$", "$1ves"),
115 | Rule.new("(hive)$", "$1s"),
116 | Rule.new("([^aeiouy]|qu)y$", "$1ies"),
117 | Rule.new("(x|ch|ss|sh)$", "$1es"),
118 | Rule.new("(matr|vert|ind|d)ix|ex$", "$1ices"),
119 | Rule.new("([m|l])ouse$", "$1ice"),
120 | Rule.new("^(ox)$", "$1en"),
121 | Rule.new("(quiz)$", "$1zes"),
122 | Rule.new("(buz|blit|walt)z$", "$1zes"),
123 | Rule.new("(hoo|lea|loa|thie)f$", "$1ves"),
124 | Rule.new("(alumn|alg|larv|vertebr)a$", "$1ae"),
125 | Rule.new("(criteri|phenomen)on$", "$1a")
126 | ]
127 |
128 | # Singular rules.
129 | vocabulary._singulars = [
130 | Rule.new("s$", ""),
131 | Rule.new("(n)ews$", "$1ews"),
132 | Rule.new("([dti])a$", "$1um"),
133 | Rule.new("(analy|ba|diagno|parenthe|progno|synop|the|ellip|empha|neuro|oa|paraly)ses$", "$1sis"),
134 | Rule.new("([^f])ves$", "$1fe"),
135 | Rule.new("(hive)s$", "$1"),
136 | Rule.new("(tive)s$", "$1"),
137 | Rule.new("([lr]|hoo|lea|loa|thie)ves$", "$1f"),
138 | Rule.new("(^zomb)?([^aeiouy]|qu)ies$", "$2y"),
139 | Rule.new("(s)eries$", "$1eries"),
140 | Rule.new("(m)ovies$", "$1ovie"),
141 | Rule.new("(x|ch|ss|sh)es$", "$1"),
142 | Rule.new("([m|l])ice$", "$1ouse"),
143 | Rule.new("(o)es$", "$1"),
144 | Rule.new("(shoe)s$", "$1"),
145 | Rule.new("(cris|ax|test)es$", "$1is"),
146 | Rule.new("(octop|vir|alumn|fung|cact|foc|hippopotam|radi|stimul|syllab|nucle)i$", "$1us"),
147 | Rule.new("(alias|bias|iris|status|campus|apparatus|virus|walrus|trellis)es$", "$1"),
148 | Rule.new("^(ox)en", "$1"),
149 | Rule.new("(matr|d)ices$", "$1ix"),
150 | Rule.new("(vert|ind)ices$", "$1ex"),
151 | Rule.new("(quiz)zes$", "$1"),
152 | Rule.new("(buz|blit|walt)zes$", "$1z"),
153 | Rule.new("(alumn|alg|larv|vertebr)ae$", "$1a"),
154 | Rule.new("(criteri|phenomen)a$", "$1on"),
155 | Rule.new("([b|r|c]ook|room|smooth)ies$", "$1ie")
156 | ]
157 |
158 | # Irregular rules.
159 | vocabulary.add_irregular("person", "people")
160 | vocabulary.add_irregular("man", "men")
161 | vocabulary.add_irregular("human", "humans")
162 | vocabulary.add_irregular("child", "children")
163 | vocabulary.add_irregular("sex", "sexes")
164 | vocabulary.add_irregular("move", "moves")
165 | vocabulary.add_irregular("goose", "geese")
166 | vocabulary.add_irregular("wave", "waves")
167 | vocabulary.add_irregular("die", "dice")
168 | vocabulary.add_irregular("foot", "feet")
169 | vocabulary.add_irregular("tooth", "teeth")
170 | vocabulary.add_irregular("curriculum", "curricula")
171 | vocabulary.add_irregular("database", "databases")
172 | vocabulary.add_irregular("zombie", "zombies")
173 | vocabulary.add_irregular("personnel", "personnel")
174 |
175 | vocabulary.add_irregular("is", "are", true)
176 | vocabulary.add_irregular("that", "those", true)
177 | vocabulary.add_irregular("this", "these", true)
178 | vocabulary.add_irregular("bus", "buses", true)
179 | vocabulary.add_irregular("staff", "staff", true)
180 |
181 | # Uncountables.
182 | vocabulary._uncountables = [
183 | "equipment",
184 | "information",
185 | "corn",
186 | "milk",
187 | "rice",
188 | "money",
189 | "species",
190 | "series",
191 | "fish",
192 | "sheep",
193 | "deer",
194 | "aircraft",
195 | "oz",
196 | "tsp",
197 | "tbsp",
198 | "ml",
199 | "l",
200 | "water",
201 | "waters",
202 | "semen",
203 | "sperm",
204 | "bison",
205 | "grass",
206 | "hair",
207 | "mud",
208 | "elk",
209 | "luggage",
210 | "moose",
211 | "offspring",
212 | "salmon",
213 | "shrimp",
214 | "someone",
215 | "swine",
216 | "trout",
217 | "tuna",
218 | "corps",
219 | "scissors",
220 | "means",
221 | "mail"
222 | ]
223 |
224 | return vocabulary
225 |
226 |
227 | var _vocabulary: Vocabulary setget, get_vocabulary
228 |
229 | func _init(p_vocabulary = null) -> void:
230 | if not p_vocabulary:
231 | p_vocabulary = Vocabulary.build_default_vocabulary()
232 | else:
233 | _vocabulary = p_vocabulary
234 |
235 |
236 | func get_vocabulary() -> Vocabulary:
237 | return _vocabulary
238 |
239 |
240 | func pluralize(p_word: String, p_force: bool = false) -> String:
241 | var result = apply_rules(_vocabulary.get_plurals(), p_word)
242 |
243 | if not p_force:
244 | return result
245 |
246 | var as_singular = apply_rules(_vocabulary.get_singulars(), p_word)
247 | var as_singular_as_plural = apply_rules(_vocabulary.get_plurals(), as_singular)
248 |
249 | if as_singular and as_singular != p_word and as_singular + "s" != p_word and as_singular_as_plural == p_word and result != p_word:
250 | return p_word
251 |
252 | return result
253 |
254 |
255 | func singularize(p_word: String, p_force: bool = false) -> String:
256 | var result = apply_rules(_vocabulary.get_singulars(), p_word)
257 |
258 | if not p_force:
259 | return result
260 |
261 | var as_plural = apply_rules(_vocabulary.get_plurals(), p_word)
262 | var as_plural_as_singular = apply_rules(_vocabulary.get_singulars(), as_plural)
263 |
264 | if as_plural and p_word + "s" != as_plural and as_plural_as_singular == p_word and result != p_word:
265 | return p_word
266 |
267 | return result
268 |
269 |
270 | func apply_rules(p_rules: Array, p_word: String):
271 | if not p_word:
272 | return null
273 |
274 | if _vocabulary.is_uncountable(p_word):
275 | return p_word
276 |
277 | var result = p_word
278 | for i in range(len(p_rules) - 1, -1, -1):
279 | result = p_rules[i].apply(p_word)
280 | if result:
281 | break
282 |
283 | return result
284 |
--------------------------------------------------------------------------------
/addons/godot-next/references/message_dispatcher.gd:
--------------------------------------------------------------------------------
1 | class_name MessageDispatcher
2 | extends Reference
3 | # author: MunWolf (Rikhardur Bjarni Einarsson)
4 | # license: MIT
5 | # copyright: Copyright (c) 2019 Rikhardur Bjarni Einarsson
6 | # description:
7 | # A message handler for non predefined signals, if you want to use this
8 | # by extending it on a Node, please use MessageDispatcherWrapper.
9 |
10 | var _message_handlers := {}
11 |
12 | # Connect a handler, obj has to have a function that corresponds to the parameter.
13 | # message_type: type of the message, we call obj.function(message) based on this.
14 | # obj: object that holds the callback.
15 | # function: function to be called on the object.
16 | func connect_message(message_type: String, obj: Object, function: String) -> void:
17 | assert(obj.has_method(function))
18 | if !_message_handlers.has(message_type):
19 | _message_handlers[message_type] = []
20 |
21 | _message_handlers[message_type].push_back([obj, function])
22 |
23 |
24 | # Disconnect a handler, this assumes that some handler with this message type has been registered
25 | # message_type: type of the message, we call obj.function(message) based on this.
26 | # obj: object that holds the callback.
27 | # function: function to be called on the object.
28 | func disconnect_message(message_type: String, obj: Object, function: String) -> void:
29 | assert(_message_handlers[message_type] != null)
30 | _message_handlers[message_type].erase([obj, function])
31 |
32 |
33 | # Disconnect all handlers.
34 | func disconnect_all_message() -> void:
35 | _message_handlers = {}
36 |
37 |
38 | # Emits a message to all handlers, message can be modified by the handlers
39 | # and it will show up inside the dictionary that was passed by the caller.
40 | # message_type: the type of the message, decides which handlers to call.
41 | # message_data: extra data that can be used by the handler or where the handler can store results.
42 | # return: returns if it was passed to any handler or not.
43 | func emit_message(message_type: String, message_data: Dictionary) -> bool:
44 | var handlers = _message_handlers[message_type]
45 | if handlers != null:
46 | var invalid = []
47 | for handler in handlers:
48 | if is_instance_valid(handler[0]):
49 | handler[0].call(handler[1], message_type, message_data)
50 | else:
51 | invalid.push_back(handler)
52 |
53 | for handler in invalid:
54 | handlers.erase(handler)
55 |
56 | return handlers != null && !handlers.empty()
57 |
--------------------------------------------------------------------------------
/addons/godot-next/references/property_info.gd:
--------------------------------------------------------------------------------
1 | tool
2 | class_name PropertyInfo
3 | extends Reference
4 | # author: xdgamestudios
5 | # license: MIT
6 | # description:
7 | # A wrapper and utility class for generating PropertyInfo
8 | # Dictionaries, of which Object._get_property_list()
9 | # returns an Array.
10 |
11 | var name: String
12 | var type: int
13 | var hint: int
14 | var hint_string: String
15 | var usage: int
16 |
17 | func _init(p_name: String = "", p_type: int = TYPE_NIL, p_hint: int = PROPERTY_HINT_NONE, p_hint_string: String = "", p_usage: int = PROPERTY_USAGE_DEFAULT) -> void:
18 | name = p_name
19 | type = p_type
20 | hint = p_hint
21 | hint_string = p_hint_string
22 | usage = p_usage
23 |
24 |
25 | func to_dict() -> Dictionary:
26 | return {
27 | "name": name,
28 | "type": type,
29 | "hint": hint,
30 | "hint_string": hint_string,
31 | "usage": usage
32 | }
33 |
34 |
35 |
--------------------------------------------------------------------------------
/addons/godot-next/references/property_info_factory.gd:
--------------------------------------------------------------------------------
1 | tool
2 | class_name PropertyInfoFactory
3 | extends Reference
4 |
5 | static func from_dict(p_dict: Dictionary) -> Reference:
6 | var name: String = p_dict.name if p_dict.has("name") else ""
7 | var type: int = p_dict.type if p_dict.has("type") else TYPE_NIL
8 | var hint: int = p_dict.hint if p_dict.has("hint") else PROPERTY_HINT_NONE
9 | var hint_string: String = p_dict.hint_string if p_dict.has("hint_string") else ""
10 | var usage: int = p_dict.usage if p_dict.has("usage") else PROPERTY_USAGE_DEFAULT
11 | return PropertyInfo.new(name, type, hint, hint_string, usage)
12 |
13 |
14 | static func new_nil(p_name: String) -> Reference:
15 | return PropertyInfo.new(p_name, TYPE_NIL, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR)
16 |
17 |
18 | static func new_group(p_name: String, p_prefix: String = "") -> Reference:
19 | return PropertyInfo.new(p_name, TYPE_NIL, PROPERTY_HINT_NONE, p_prefix, PROPERTY_USAGE_GROUP)
20 |
21 |
22 | static func new_array(p_name: String, p_hint: int = PROPERTY_HINT_NONE, p_hint_string: String = "", p_usage: int = PROPERTY_USAGE_DEFAULT) -> Reference:
23 | return PropertyInfo.new(p_name, TYPE_ARRAY, p_hint, p_hint_string, p_usage)
24 |
25 |
26 | static func new_dictionary(p_name: String, p_hint: int = PROPERTY_HINT_NONE, p_hint_string: String = "", p_usage: int = PROPERTY_USAGE_DEFAULT) -> Reference:
27 | return PropertyInfo.new(p_name, TYPE_DICTIONARY, p_hint, p_hint_string, p_usage)
28 |
29 |
30 | static func new_resource(p_name: String, p_hint_string: String = "", p_usage: int = PROPERTY_USAGE_DEFAULT) -> Reference:
31 | return PropertyInfo.new(p_name, TYPE_OBJECT, PROPERTY_HINT_RESOURCE_TYPE, p_hint_string, p_usage)
32 |
33 |
34 | static func new_editor_only(p_name: String):
35 | return PropertyInfo.new(p_name, TYPE_NIL, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_SCRIPT_VARIABLE)
36 |
37 |
38 | static func new_storage_only(p_name: String):
39 | return PropertyInfo.new(p_name, TYPE_NIL, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_SCRIPT_VARIABLE)
40 |
--------------------------------------------------------------------------------
/addons/godot-next/references/tween_sequence/tween_sequence.gd:
--------------------------------------------------------------------------------
1 | class_name TweenSequence
2 | extends Reference
3 | # author: KoBeWi
4 | # license: MIT
5 | # description:
6 | # A helper class for easier management and chaining of Tweens.
7 | # dynamically from code.
8 | #
9 | # Example usage:
10 | # var seq := TweenSequence.new(get_tree())
11 | # seq.append($Sprite, "modulate", Color.red, 1)
12 | # seq.append($Sprite, "modulate", Color(1, 0, 0, 0), 1).set_delay(1)
13 | # This will create a Tween and automatically start it,
14 | # changing the Sprite to red color in one second
15 | # and then making it transparent after a delay.
16 |
17 | # Tweener for tweening properties.
18 | class PropertyTweener extends Tweener:
19 | var _target: Object
20 | var _property: NodePath
21 | var _from
22 | var _to
23 | var _duration: float
24 | var _trans: int
25 | var _ease: int
26 |
27 | var _delay: float
28 | var _continue := true
29 | var _advance := false
30 |
31 | func _init(target: Object, property: NodePath, to_value, duration: float) -> void:
32 | assert(target, "Invalid target Object.")
33 | _target = target
34 | _property = property
35 | _from = _target.get_indexed(property)
36 | _to = to_value
37 | _duration = duration
38 | _trans = Tween.TRANS_LINEAR
39 | _ease = Tween.EASE_IN_OUT
40 |
41 |
42 | # Sets custom starting value for the tweener.
43 | # By default, it starts from value at the start of this tweener.
44 | func from(val) -> Tweener:
45 | _from = val
46 | _continue = false
47 | return self
48 |
49 |
50 | # Sets the starting value to the current value,
51 | # i.e. value at the time of creating sequence.
52 | func from_current() -> Tweener:
53 | _continue = false
54 | return self
55 |
56 |
57 | # Sets transition type of this tweener, from Tween.TransitionType.
58 | func set_trans(t: int) -> Tweener:
59 | _trans = t
60 | return self
61 |
62 |
63 | # Sets ease type of this tweener, from Tween.EaseType.
64 | func set_ease(e: int) -> Tweener:
65 | _ease = e
66 | return self
67 |
68 |
69 | # Sets the delay after which this tweener will start.
70 | func set_delay(d: float) -> Tweener:
71 | _delay = d
72 | return self
73 |
74 |
75 | func _start(tween: Tween) -> void:
76 | if not is_instance_valid(_target):
77 | push_warning("Target object freed, aborting Tweener.")
78 | return
79 |
80 | if _continue:
81 | _from = _target.get_indexed(_property)
82 |
83 | if _advance:
84 | tween.interpolate_property(_target, _property, _from, _from + _to, _duration, _trans, _ease, _delay)
85 | else:
86 | tween.interpolate_property(_target, _property, _from, _to, _duration, _trans, _ease, _delay)
87 |
88 |
89 | # Generic tweener for creating delays in sequence.
90 | class IntervalTweener extends Tweener:
91 | var _time: float
92 |
93 | func _init(time: float) -> void:
94 | _time = time
95 |
96 |
97 | func _start(tween: Tween) -> void:
98 | tween.interpolate_callback(self, _time, "_")
99 |
100 |
101 | func _():
102 | pass
103 |
104 | # Tweener for calling methods.
105 | class CallbackTweener extends Tweener:
106 | var _target: Object
107 | var _delay: float
108 | var _method: String
109 | var _args: Array
110 |
111 | func _init(target: Object, method: String, args: Array) -> void:
112 | assert(target, "Invalid target Object.")
113 | _target = target
114 | _method = method
115 | _args = args
116 |
117 |
118 | # Set delay after which the method will be called.
119 | func set_delay(d: float) -> Tweener:
120 | _delay = d
121 | return self
122 |
123 |
124 | func _start(tween: Tween) -> void:
125 | if not is_instance_valid(_target):
126 | push_warning("Target object freed, aborting Tweener.")
127 | return
128 |
129 | tween.interpolate_callback(_target, _delay, _method,
130 | _get_argument(0), _get_argument(1), _get_argument(2),
131 | _get_argument(3), _get_argument(4))
132 |
133 |
134 | func _get_argument(i: int):
135 | if i < _args.size():
136 | return _args[i]
137 | else:
138 | return null
139 |
140 |
141 | # Tweener for tweening arbitrary values using getter/setter method.
142 | class MethodTweener extends Tweener:
143 | var _target: Object
144 | var _method: String
145 | var _from
146 | var _to
147 | var _duration: float
148 | var _trans: int
149 | var _ease: int
150 |
151 | var _delay: float
152 |
153 | func _init(target: Object, method: String, from_value, to_value, duration: float) -> void:
154 | assert(target, "Invalid target Object.")
155 | _target = target
156 | _method = method
157 | _from = from_value
158 | _to = to_value
159 | _duration = duration
160 | _trans = Tween.TRANS_LINEAR
161 | _ease = Tween.EASE_IN_OUT
162 |
163 |
164 | # Sets transition type of this tweener, from Tween.TransitionType.
165 | func set_trans(t: int) -> Tweener:
166 | _trans = t
167 | return self
168 |
169 |
170 | # Sets ease type of this tweener, from Tween.EaseType.
171 | func set_ease(e: int) -> Tweener:
172 | _ease = e
173 | return self
174 |
175 |
176 | # Sets the delay after which this tweener will start.
177 | func set_delay(d: float) -> Tweener:
178 | _delay = d
179 | return self
180 |
181 |
182 | func _start(tween: Tween) -> void:
183 | if not is_instance_valid(_target):
184 | push_warning("Target object freed, aborting Tweener.")
185 | return
186 |
187 | tween.interpolate_method(_target, _method, _from, _to, _duration, _trans, _ease, _delay)
188 |
189 |
190 | # Emited when one step of the sequence is finished.
191 | signal step_finished(idx)
192 | # Emited when a loop of the sequence is finished.
193 | signal loop_finished()
194 | # Emitted when whole sequence is finished. Doesn't happen with inifnite loops.
195 | signal finished()
196 |
197 | var _tree: SceneTree
198 | var _tween: Tween
199 | var _tweeners: Array
200 |
201 | var _current_step := 0
202 | var _loops := 0
203 | var _autostart := true
204 | var _started := false
205 | var _running := false
206 |
207 | var _kill_when_finised := true
208 | var _parallel := false
209 |
210 | # You need to provide SceneTree to be used by the sequence.
211 | func _init(tree: SceneTree) -> void:
212 | _tree = tree
213 | _tween = Tween.new()
214 | _tween.set_meta("sequence", self)
215 | _tree.get_root().call_deferred("add_child", _tween)
216 |
217 | _tree.connect("idle_frame", self, "start", [], CONNECT_ONESHOT)
218 | _tween.connect("tween_all_completed", self, "_step_complete")
219 |
220 | # All Tweener-creating methods will return the Tweeners for further chained usage.
221 |
222 | # Appends a PropertyTweener for tweening properties.
223 | func append(target: Object, property: NodePath, to_value, duration: float) -> PropertyTweener:
224 | var tweener := PropertyTweener.new(target, property, to_value, duration)
225 | _add_tweener(tweener)
226 | return tweener
227 |
228 |
229 | # Appends a PropertyTweener operating on relative values.
230 | func append_advance(target: Object, property: NodePath, by_value, duration: float) -> PropertyTweener:
231 | var tweener := PropertyTweener.new(target, property, by_value, duration)
232 | tweener._advance = true
233 | _add_tweener(tweener)
234 | return tweener
235 |
236 |
237 | # Appends an IntervalTweener for creating delay intervals.
238 | func append_interval(time: float) -> IntervalTweener:
239 | var tweener := IntervalTweener.new(time)
240 | _add_tweener(tweener)
241 | return tweener
242 |
243 |
244 | # Appends a CallbackTweener for calling methods on target object.
245 | func append_callback(target: Object, method: String, args := []) -> CallbackTweener:
246 | var tweener := CallbackTweener.new(target, method, args)
247 | _add_tweener(tweener)
248 | return tweener
249 |
250 |
251 | # Appends a MethodTweener for tweening arbitrary values using methods.
252 | func append_method(target: Object, method: String, from_value, to_value, duration: float) -> MethodTweener:
253 | var tweener := MethodTweener.new(target, method, from_value, to_value, duration)
254 | _add_tweener(tweener)
255 | return tweener
256 |
257 |
258 | # When used, next Tweener will be added as a parallel to previous one.
259 | # Example: sequence.parallel().append(...)
260 | func parallel() -> Reference:
261 | if _tweeners.empty():
262 | _tweeners.append([])
263 | _parallel = true
264 | return self
265 |
266 |
267 | # Alias to parallel(), except it won't work without first tweener.
268 | func join() -> Reference:
269 | assert(!_tweeners.empty(), "Can't join with empty sequence!")
270 | _parallel = true
271 | return self
272 |
273 |
274 | # Sets the speed scale of tweening.
275 | func set_speed(speed: float) -> Reference:
276 | _tween.playback_speed = speed
277 | return self
278 |
279 |
280 | # Sets how many the sequence should repeat.
281 | # When used without arguments, sequence will run infinitely.
282 | func set_loops(loops := -1) -> Reference:
283 | _loops = loops
284 | return self
285 |
286 |
287 | # Whether the sequence should autostart or not.
288 | # Enabled by default.
289 | func set_autostart(autostart: bool) -> Reference:
290 | if _autostart and not autostart:
291 | _tree.disconnect("idle_frame", self, "start")
292 | elif not _autostart and autostart:
293 | _tree.connect("idle_frame", self, "start", [], CONNECT_ONESHOT)
294 |
295 | _autostart = autostart
296 | return self
297 |
298 |
299 | # Starts the sequence manually, unless it's already started.
300 | func start() -> void:
301 | assert(_tween, "Tween was removed!")
302 | assert(!_started, "Sequence already started!")
303 | _started = true
304 | _running = true
305 | _run_next_step()
306 |
307 |
308 | # Returns whether the sequence is currently running.
309 | func is_running() -> bool:
310 | return _running
311 |
312 |
313 | # Pauses the execution of the tweens.
314 | func pause() -> void:
315 | assert(_tween, "Tween was removed!")
316 | assert(_running, "Sequence not running!")
317 | _tween.stop_all()
318 | _running = false
319 |
320 |
321 | # Resumes the execution of the tweens.
322 | func resume() -> void:
323 | assert(_tween, "Tween was removed!")
324 | assert(!_running, "Sequence already running!")
325 | _tween.resume_all()
326 | _running = true
327 |
328 |
329 | # Stops the sequence and resets it to the beginning.
330 | func reset() -> void:
331 | assert(_tween, "Tween was removed!")
332 | if _running:
333 | pause()
334 | _started = false
335 | _current_step = 0
336 | _tween.reset_all()
337 |
338 |
339 | # Frees the underlying Tween. Sequence is unusable after this operation.
340 | func kill():
341 | assert(_tween, "Tween was already removed!")
342 | if _running:
343 | pause()
344 | _tween.queue_free()
345 |
346 |
347 | # Whether the Tween should be freed when sequence finishes.
348 | # Default is true. If set to false, sequence will restart on end.
349 | func set_autokill(autokill: bool):
350 | _kill_when_finised = autokill
351 |
352 |
353 | func _add_tweener(tweener: Tweener):
354 | assert(_tween, "Tween was removed!")
355 | assert(!_started, "Can't append to a started sequence!")
356 | if not _parallel:
357 | _tweeners.append([])
358 | _tweeners.back().append(tweener)
359 | _parallel = false
360 |
361 |
362 | func _run_next_step() -> void:
363 | assert(!_tweeners.empty(), "Sequence has no steps!")
364 | var group := _tweeners[_current_step] as Array
365 | for tweener in group:
366 | tweener._start(_tween)
367 | _tween.start()
368 |
369 |
370 | func _step_complete() -> void:
371 | emit_signal("step_finished", _current_step)
372 | _current_step += 1
373 |
374 | if _current_step == _tweeners.size():
375 | _loops -= 1
376 | if _loops == -1:
377 | emit_signal("finished")
378 | if _kill_when_finised:
379 | kill()
380 | else:
381 | reset()
382 | else:
383 | emit_signal("loop_finished")
384 | _current_step = 0
385 | _run_next_step()
386 | else:
387 | _run_next_step()
388 |
--------------------------------------------------------------------------------
/addons/godot-next/references/tween_sequence/tweener.gd:
--------------------------------------------------------------------------------
1 | class_name Tweener
2 | extends Reference
3 | # author: KoBeWi
4 | # license: MIT
5 | # description:
6 | # Abstract class for all Tweeners.
7 |
8 | func _start(tween: Tween) -> void:
9 | pass
10 |
--------------------------------------------------------------------------------
/addons/godot-next/resources/behavior.gd:
--------------------------------------------------------------------------------
1 | tool
2 | class_name Behavior
3 | extends Resource
4 | # author: xdgamestudios
5 | # license: MIT
6 | # description:
7 | # This is an abstract base "Behavior" class for use in the "Behaviors" node class.
8 | # "Behaviors" manages "Behavior" resources and calls notification methods that the Behavior implements.
9 | # usage:
10 | # - Supported notifications:
11 | # _enter_tree() -> void
12 | # _exit_tree() -> void
13 | # _ready() -> void
14 | # _process(p_delta: float) -> void
15 | # _physics_process(delta: float) -> void:
16 | # _input(event: InputEvent) -> void:
17 | # _unhandled_input(event: InputEvent) -> void:
18 | # _unhandled_key_input(event: InputEventKey) -> void:
19 | # Note:
20 | # - If present notifications, are automatically triggered by the owner class.
21 | # - If the behavior is disabled its notifications will not be processed.
22 |
23 | # A reference to the owning Behaviors node.
24 | var owner: Node = null setget set_owner, get_owner
25 |
26 | # Allows users to toggle processing callbacks on the owner.
27 | var enabled: bool = true setget set_enabled, get_enabled
28 |
29 | # This name is used to match the convention in Unity's MonoBehaviour class.
30 | func _awake() -> void:
31 | pass
32 |
33 |
34 | # This name is used to match the convention in Unity's MonoBehaviour class.
35 | func _on_enable() -> void:
36 | pass
37 |
38 |
39 | # This name is used to match the convention in Unity's MonoBehaviour class.
40 | func _on_disable() -> void:
41 | pass
42 |
43 |
44 | # Returns an instance of the stored Behavior resource from the owner.
45 | func get_behavior(p_type: Script) -> Resource:
46 | return owner.get_element(p_type)
47 |
48 |
49 | func set_enabled(p_enable: bool) -> void:
50 | if enabled == p_enable:
51 | return
52 | enabled = p_enable
53 | if p_enable:
54 | _on_enable()
55 | owner._add_to_callbacks()
56 | else:
57 | _on_disable()
58 | owner._remove_from_callbacks()
59 |
60 |
61 | func get_enabled() -> bool:
62 | return enabled
63 |
64 |
65 | func set_owner(p_owner: Node) -> void:
66 | assert(p_owner) # Must be assigned a valid owner at all times, except initially.
67 | owner = p_owner
68 |
69 |
70 | func get_owner() -> Node:
71 | return owner
72 |
73 |
74 | # Should only override if one wishes to create their own abstract Behaviors
75 | # By default, the absence of this method is interpreted as a non-abstract type!
76 | static func is_abstract() -> bool:
77 | return true
78 |
--------------------------------------------------------------------------------
/addons/godot-next/resources/discrete_gradient_texture.gd:
--------------------------------------------------------------------------------
1 | tool
2 | class_name DiscreteGradientTexture
3 | extends ImageTexture
4 | # author: Athrunen
5 | # license: MIT
6 | # description: Has the same functionality as the GradientTexture but does not interpolate colors.
7 | # todos:
8 | # - Write a more elegant way of updating the texture than changing the resolution.
9 | # - Persuade Godot to repeat the texture vertically in the inspector.
10 |
11 | export var resolution: int = 256 setget _update_resolution
12 | export var gradient: Gradient = Gradient.new() setget _update_gradient
13 |
14 | func _ready() -> void:
15 | _update_texture()
16 |
17 |
18 | func _update_texture() -> void:
19 | var image := Image.new()
20 | image.create(resolution, 1, false, Image.FORMAT_RGBA8)
21 |
22 | if not gradient:
23 | return
24 |
25 | image.lock()
26 |
27 | var last_offset := 0
28 | var last_pixel := 0
29 | var index := 0
30 | for offset in gradient.offsets:
31 | var amount := int(round((offset - last_offset) * resolution))
32 | amount -= 1 if amount > 0 else 0
33 | var color := gradient.colors[index]
34 | for x in range(amount):
35 | image.set_pixel(x + last_pixel, 0, color)
36 |
37 | last_offset = offset
38 | last_pixel = last_pixel + amount
39 | index += 1
40 |
41 | if last_pixel < resolution:
42 | var color := gradient.colors[-1]
43 | for x in resolution - last_pixel:
44 | image.set_pixel(x + last_pixel, 0, color)
45 |
46 | image.unlock()
47 | self.create_from_image(image, 0)
48 |
49 |
50 | func _update_gradient(g: Gradient) -> void:
51 | gradient = g
52 | _update_texture()
53 |
54 |
55 | func _update_resolution(r: int) -> void:
56 | resolution = r
57 | _update_texture()
58 |
--------------------------------------------------------------------------------
/addons/godot-next/resources/resource_collections/resource_array.gd:
--------------------------------------------------------------------------------
1 | tool
2 | class_name ResourceArray
3 | extends ResourceCollection
4 | # author: xdgamestudios
5 | # license: MIT
6 | # description:
7 | # A ResourceCollection implementation that manages an Array of Resources.
8 | # One can add multiple instances of any given Resource type.
9 | # deps:
10 | # - ResourceCollection
11 | # - PropertyInfo
12 |
13 | const COLLECTION_NAME = "[ Array ]"
14 |
15 | var _data := []
16 |
17 | func _init() -> void:
18 | resource_name = COLLECTION_NAME
19 |
20 |
21 | func clear() -> void:
22 | _data.clear()
23 |
24 |
25 | func get_data() -> Array:
26 | return _data
27 |
28 |
29 | func _get(p_property: String):
30 | if p_property.begins_with(DATA_PREFIX):
31 | var index := int(p_property.trim_prefix(DATA_PREFIX + "item_"))
32 | return _data[index] if index < _data.size() else null
33 | return null
34 |
35 |
36 | func _set(p_property, p_value):
37 | if p_property.begins_with(DATA_PREFIX):
38 | var index := int(p_property.trim_prefix(DATA_PREFIX + "item_"))
39 | if not p_value:
40 | _data.remove(index)
41 | property_list_changed_notify()
42 | else:
43 | var res = _instantiate_script(p_value) if p_value is Script else p_value
44 | _class_type.res = res
45 | if res and _class_type.is_type(_type):
46 | _data[index] = res
47 | property_list_changed_notify()
48 | return true
49 | return false
50 |
51 |
52 | func _add_element(script) -> void:
53 | _data.append(script.new())
54 |
55 |
56 | func _refresh_data() -> void:
57 | if _type == null:
58 | clear()
59 | return
60 | var data_cache := _data.duplicate()
61 | for a_resource in data_cache:
62 | if not ClassType.new(a_resource).is_type(_type):
63 | _data.erase(a_resource)
64 |
65 |
66 | func _export_data_group() -> Array:
67 | var list := ._export_data_group()
68 | list.append(PropertyInfoFactory.new_storage_only("_data").to_dict())
69 | if _data.empty():
70 | list.append(PropertyInfoFactory.new_nil(DATA_PREFIX + EMPTY_ENTRY).to_dict())
71 | for an_index in _data.size():
72 | list.append(PropertyInfoFactory.new_resource("%sitem_%s" % [DATA_PREFIX, an_index], "", PROPERTY_USAGE_EDITOR).to_dict())
73 | return list
74 |
--------------------------------------------------------------------------------
/addons/godot-next/resources/resource_collections/resource_collection.gd:
--------------------------------------------------------------------------------
1 | tool
2 | class_name ResourceCollection
3 | extends Resource
4 | # author: xdgamestudios
5 | # license: MIT
6 | # description:
7 | # An abstract base class for data structures that store Resource objects.
8 | # Uses a key-value store, but can also append items.
9 |
10 | const SETUP_PREFIX = "setup/"
11 | const DATA_PREFIX = "data/"
12 |
13 | const EMPTY_ENTRY = "[ Empty ]"
14 |
15 | var _type: Script = null
16 | var _type_readonly: bool = false
17 | var _class_type: ClassType = ClassType.new()
18 |
19 | func clear() -> void:
20 | assert(false)
21 |
22 |
23 | func get_base_type() -> Script:
24 | return _type
25 |
26 |
27 | func set_base_type(p_type: Script) -> void:
28 | if _type == p_type:
29 | return
30 | _type = p_type
31 | property_list_changed_notify()
32 |
33 |
34 | func is_type_readonly() -> bool:
35 | return _type_readonly
36 |
37 |
38 | func set_type_readonly(read_only: bool) -> void:
39 | if _type_readonly == read_only:
40 | return
41 | _type_readonly = read_only
42 | property_list_changed_notify()
43 |
44 |
45 | func _get(p_property: String):
46 | match p_property.trim_prefix(SETUP_PREFIX):
47 | "base_type":
48 | return _type
49 | return null
50 |
51 |
52 | func _set(p_property: String, p_value) -> bool:
53 | match p_property.trim_prefix(SETUP_PREFIX):
54 | "base_type":
55 | if _type != p_value:
56 | _type = p_value
57 | property_list_changed_notify()
58 | return true
59 | return false
60 |
61 |
62 | func _get_property_list() -> Array:
63 | var list := []
64 | list += _export_setup_group()
65 |
66 | if not _type:
67 | return list
68 |
69 | list += _export_data_group()
70 | return list
71 |
72 |
73 | # Append an element to the collection.
74 | #warning-ignore:unused_argument
75 | func _add_element(p_script: Script) -> void:
76 | assert(false)
77 |
78 |
79 | # Refresh the data upon type change.
80 | func _refresh_data() -> void:
81 | assert(false)
82 |
83 |
84 | # Export properties within the 'data' group.
85 | func _export_data_group() -> Array:
86 | return [ PropertyInfoFactory.new_editor_only(DATA_PREFIX + "dropdown").to_dict() ]
87 |
88 |
89 | # Export properties within the 'setup' group.
90 | func _export_setup_group() -> Array:
91 | return [ PropertyInfoFactory.new_resource(SETUP_PREFIX + "base_type", "Script").to_dict() ] if not _type_readonly else []
92 |
93 |
94 | # Injects controls to the EditorInspectorPlugin.
95 | func _parse_property(p_plugin: EditorInspectorPlugin, p_pinfo: PropertyInfo) -> bool:
96 | match p_pinfo.name.trim_prefix(DATA_PREFIX):
97 | "dropdown":
98 | var elements = _find_inheritors()
99 | var control = InspectorControls.new_dropdown_appender(elements, self, "_on_dropdown_selector_selected")
100 | p_plugin.add_custom_control(control)
101 | return true
102 | return false
103 |
104 |
105 | func _instantiate_script(p_script: Script) -> Resource:
106 | var res: Resource = null
107 | if ClassDB.is_parent_class(p_script.get_instance_base_type(), "Resource"):
108 | push_warning("Must assign non-Script Resource instances. Auto-instantiating the given Resource script.")
109 | res = p_script.new()
110 | else:
111 | push_error("Must assign non-Script Resource instances. Fallback error: cannot auto-instantiate non-Resource scripts into ResourceCollection.")
112 | return res
113 |
114 |
115 | func _find_inheritors() -> Dictionary:
116 | _class_type.res = _type
117 | var list = _class_type.get_deep_inheritors_list()
118 | var type_map = _class_type.get_deep_type_map()
119 | var inheritors = { }
120 | for a_name in list:
121 | inheritors[a_name] = load(type_map[a_name].path)
122 | return inheritors
123 |
124 |
125 | func _on_dropdown_selector_selected(dropdown_selector):
126 | var script = dropdown_selector.get_selected_meta()
127 | _add_element(script)
128 | property_list_changed_notify()
129 |
--------------------------------------------------------------------------------
/addons/godot-next/resources/resource_collections/resource_set.gd:
--------------------------------------------------------------------------------
1 | tool
2 | class_name ResourceSet
3 | extends ResourceCollection
4 | # author: xdgamestudios
5 | # license: MIT
6 | # description:
7 | # A ResourceCollection implementation that manages a Set of Resources.
8 | # One can add only one instance of any given Resource type.
9 | # deps:
10 | # - ResourceCollection
11 | # - PropertyInfo
12 |
13 | const COLLECTION_NAME: String = "[ Set ]"
14 |
15 | var _data: Dictionary = {}
16 |
17 | func _init() -> void:
18 | resource_name = COLLECTION_NAME
19 |
20 |
21 | func clear() -> void:
22 | _data.clear()
23 |
24 |
25 | func get_data() -> Dictionary:
26 | return _data
27 |
28 |
29 | func _get(p_property: String):
30 | if p_property.begins_with(DATA_PREFIX):
31 | var key = p_property.trim_prefix(DATA_PREFIX)
32 | return _data.get(key, null)
33 | return null
34 |
35 |
36 | func _set(p_property: String, p_value) -> bool:
37 | if p_property.begins_with(DATA_PREFIX):
38 | var key = p_property.trim_prefix(DATA_PREFIX)
39 | if not p_value:
40 | #warning-ignore:return_value_discarded
41 | _data.erase(key)
42 | property_list_changed_notify()
43 | elif _data[key].get_script() == p_value.get_script():
44 | var res = _instantiate_script(p_value) if p_value is Script else p_value
45 | if res:
46 | _data[key] = res
47 | property_list_changed_notify()
48 | return true
49 | return false
50 |
51 |
52 | func _add_element(p_script: Script) -> void:
53 | _class_type.res = p_script
54 | var key := _class_type.get_name()
55 | if not _data.has(key):
56 | _data[key] = p_script.new()
57 |
58 |
59 | func _refresh_data() -> void:
60 | if _type == null:
61 | clear()
62 | return
63 | var typenames := _data.keys()
64 | for a_typename in typenames:
65 | _class_type.res = _data[a_typename]
66 | if not _class_type.is_type(_type):
67 | #warning-ignore:return_value_discarded
68 | _data.erase(a_typename)
69 |
70 |
71 | func _export_data_group() -> Array:
72 | var list := ._export_data_group()
73 | list.append(PropertyInfoFactory.new_storage_only("_data").to_dict())
74 | if _data.empty():
75 | list.append(PropertyInfoFactory.new_nil(DATA_PREFIX + EMPTY_ENTRY).to_dict())
76 | for a_typename in _data:
77 | list.append(PropertyInfoFactory.new_resource(DATA_PREFIX + a_typename, "", PROPERTY_USAGE_EDITOR).to_dict())
78 | return list
79 |
--------------------------------------------------------------------------------
/addons/godot-next/resources/singletons/singleton_cache.gd:
--------------------------------------------------------------------------------
1 | tool
2 | extends Resource
3 | # author: xdgamestudios
4 | # license: MIT
5 | # description:
6 | # A resource file that is preloaded into memory to allow for accessing
7 | # singleton classes project wide using Singletons
8 |
9 | var _cache: Dictionary = {}
10 | var _paths: Dictionary = {}
11 |
12 | func get_cache() -> Dictionary:
13 | return _cache
14 |
15 |
16 | func get_paths() -> Dictionary:
17 | return _paths
18 |
--------------------------------------------------------------------------------
/addons/godot-next/singletons/icons.gd:
--------------------------------------------------------------------------------
1 | tool
2 | class_name Icons
3 | extends Reference
4 | # author: willnationsdev
5 | # license: MIT
6 | # description:
7 | # A singleton that stores paths to icons, but fetches them loaded for users.
8 | # icons must have a `icon_.svg` file path, anywhere in the project.
9 | # The name can then be accessed directly as a property of Icons.fetch().
10 |
11 | const SELF_PATH: String = "res://addons/godot-next/singletons/icons.gd"
12 |
13 | var data: Dictionary = {}
14 |
15 | func _init() -> void:
16 | register_dir("res://")
17 |
18 |
19 | static func fetch() -> Reference:
20 | return Singletons.fetch(_this()) as Reference
21 |
22 |
23 | static func _this() -> Script:
24 | return load(SELF_PATH) as Script
25 |
26 |
27 | func register_dir(p_path: String) -> void:
28 | var files_data = FileSearch.search_regex_full_path(".*icon_(.*)\\.svg$", p_path)
29 | for a_data in files_data:
30 | var a_match = files_data[a_data]["match"]
31 | var name = ClassType.namify_path(a_match.strings[1])
32 | data[name] = a_match.subject
33 |
34 |
35 | func _get_property_list():
36 | var list := []
37 | for a_name in data:
38 | list.append(PropertyInfoFactory.new_resource(a_name, "Texture").to_dict())
39 | return list
40 |
41 |
42 | func _get(p_property):
43 | if data.has(p_property):
44 | return load(data[p_property]) if ResourceLoader.exists(data[p_property]) else null
45 | #return data[p_property]
46 | return null
47 |
48 |
49 | func _set(p_property, p_value) -> bool:
50 | if data.has(p_property):
51 | match typeof(p_value):
52 | TYPE_STRING:
53 | data[p_property] = p_value
54 | return true
55 | TYPE_OBJECT:
56 | if p_value:
57 | if p_value is Texture:
58 | data[p_property] = p_value.resource_path
59 | return true
60 | else:
61 | return false
62 | else:
63 | data[p_property] = null
64 | #warning-ignore:return_value_discarded
65 | data.erase(p_property)
66 | return false
67 |
--------------------------------------------------------------------------------
/default_env.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="Environment" load_steps=2 format=2]
2 |
3 | [sub_resource type="ProceduralSky" id=1]
4 |
5 | [resource]
6 | background_mode = 2
7 | background_sky = SubResource( 1 )
8 |
--------------------------------------------------------------------------------
/demo/demo.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=4 format=2]
2 |
3 | [ext_resource path="res://demo/demo_2d.tscn" type="PackedScene" id=1]
4 | [ext_resource path="res://demo/demo_3d.tscn" type="PackedScene" id=2]
5 | [ext_resource path="res://demo/scripts/demo.gd" type="Script" id=4]
6 |
7 | [node name="Demo" type="Node"]
8 | script = ExtResource( 4 )
9 |
10 | [node name="Demo2D" parent="." instance=ExtResource( 1 )]
11 |
12 | [node name="Demo3D" parent="." instance=ExtResource( 2 )]
13 |
--------------------------------------------------------------------------------
/demo/demo_2d.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=8 format=2]
2 |
3 | [ext_resource path="res://addons/godot-next/2d/geometry_2d.gd" type="Script" id=1]
4 | [ext_resource path="res://addons/godot-next/2d/trail_2d.gd" type="Script" id=2]
5 | [ext_resource path="res://addons/godot-next/gui/debug_label.gd" type="Script" id=3]
6 | [ext_resource path="res://addons/godot-next/2d/vector_display_2d.gd" type="Script" id=4]
7 | [ext_resource path="res://demo/scripts/wandering_node_2d.gd" type="Script" id=5]
8 | [ext_resource path="res://demo/scripts/test_vector_display.gd" type="Script" id=6]
9 |
10 | [sub_resource type="CapsuleShape2D" id=1]
11 | radius = 50.0
12 | height = 100.0
13 |
14 | [node name="Demo2D" type="Node2D"]
15 |
16 | [node name="StaticBody2D" type="StaticBody2D" parent="."]
17 | position = Vector2( 900, 450 )
18 |
19 | [node name="Geometry2D" type="CollisionShape2D" parent="StaticBody2D"]
20 | shape = SubResource( 1 )
21 | script = ExtResource( 1 )
22 | color = Color( 1, 1, 1, 1 )
23 | offset_position = Vector2( 0, 0 )
24 |
25 | [node name="WanderingNode2D" type="Node2D" parent="."]
26 | position = Vector2( 500, 450 )
27 | script = ExtResource( 5 )
28 |
29 | [node name="Trail2D" type="Line2D" parent="."]
30 | position = Vector2( 500, 450 )
31 | script = ExtResource( 2 )
32 | target_path = NodePath("../WanderingNode2D")
33 | trail_length = 50
34 |
35 | [node name="DebugLabel" type="Label" parent="."]
36 | margin_left = 100.0
37 | margin_top = 400.0
38 | margin_right = 289.0
39 | margin_bottom = 499.0
40 | text = "DebugLabel
41 | WanderingNode2D
42 | position = Vector2( 500, 450 )
43 | velocity = null
44 | name = \"WanderingNode2D\"
45 | "
46 | script = ExtResource( 3 )
47 | __meta__ = {
48 | "_edit_use_anchors_": false
49 | }
50 | update_mode = 0
51 | target_path = NodePath("../WanderingNode2D")
52 | show_label_name = true
53 | show_target_name = true
54 | properties = PoolStringArray( "position", "velocity", "name" )
55 |
56 | [node name="TestVectorDisplay2D" type="Node2D" parent="."]
57 | position = Vector2( 100, 100 )
58 | script = ExtResource( 6 )
59 | pool_vector2_array = PoolVector2Array( 100, 200, 200, 100 )
60 |
61 | [node name="VectorDisplay2D" type="Node" parent="TestVectorDisplay2D"]
62 | script = ExtResource( 4 )
63 | variable_name = "pool_vector2_array"
64 |
--------------------------------------------------------------------------------
/demo/demo_3d.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=5 format=2]
2 |
3 | [ext_resource path="res://addons/godot-next/3d/trail_3d.gd" type="Script" id=1]
4 | [ext_resource path="res://demo/scripts/wandering_node_3d.gd" type="Script" id=2]
5 | [ext_resource path="res://addons/godot-next/3d/vector_display_3d.gd" type="Script" id=3]
6 | [ext_resource path="res://demo/scripts/test_vector_display.gd" type="Script" id=4]
7 |
8 | [node name="Demo3D" type="Spatial"]
9 |
10 | [node name="WanderingNode3D" type="Spatial" parent="."]
11 | script = ExtResource( 2 )
12 |
13 | [node name="Trail3D" type="ImmediateGeometry" parent="WanderingNode3D"]
14 | script = ExtResource( 1 )
15 | length = 5.0
16 | max_radius = 0.25
17 | density_lengthwise = 50
18 | density_around = 20
19 |
20 | [node name="Camera" type="Camera" parent="."]
21 | transform = Transform( 1, 0, 0, 0, 0.866025, 0.5, 0, -0.5, 0.866025, 0, 2, 8 )
22 |
23 | [node name="TestVectorDisplay3D" type="Spatial" parent="."]
24 | transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0.5, 0, 0.5 )
25 | script = ExtResource( 4 )
26 | pool_vector3_array = PoolVector3Array( 1, 0, 2, 2, 0, 1 )
27 |
28 | [node name="VectorDisplay3D" type="Node" parent="TestVectorDisplay3D"]
29 | script = ExtResource( 3 )
30 | variable_name = "pool_vector3_array"
31 |
--------------------------------------------------------------------------------
/demo/scripts/demo.gd:
--------------------------------------------------------------------------------
1 | extends Node
2 |
3 | func _ready():
4 | # Array2D
5 | var array_2d = Array2D.new()
6 | array_2d.resize(3, 4)
7 | array_2d.set_cell(2, 3, "Array2D test")
8 | print(array_2d.get_cell(2, 3))
9 |
10 | # BitFlag
11 | var bit_flag_dict = {"a": 1, "b": 2}
12 | var bit_flag = BitFlag.new(bit_flag_dict)
13 | bit_flag.a = true
14 | print(bit_flag.get_active_keys())
15 |
16 | # Bitset
17 | var bitset = Bitset.new(5)
18 | bitset.set_bit(2, true)
19 | bitset.set_bit(3, true)
20 | bitset.print_bits(false)
21 |
--------------------------------------------------------------------------------
/demo/scripts/test_vector_display.gd:
--------------------------------------------------------------------------------
1 | extends Node
2 |
3 | export(Vector2) var vector2 = Vector2(100, 200)
4 | export(Vector3) var vector3 = Vector3(1, 2, 3)
5 | export(PoolVector2Array) var pool_vector2_array = PoolVector2Array()
6 | export(PoolVector3Array) var pool_vector3_array = PoolVector3Array()
7 | export(Array) var array = [Vector2(100, 100), Vector3(0, 1, 2)]
8 |
--------------------------------------------------------------------------------
/demo/scripts/wandering_node_2d.gd:
--------------------------------------------------------------------------------
1 | extends Node2D
2 |
3 | var velocity = Vector2()
4 | onready var center = position
5 |
6 | func _ready():
7 | randomize()
8 |
9 |
10 | func _physics_process(_delta):
11 | velocity += Vector2(randf() - 0.5, randf() - 0.5)
12 | if velocity.length_squared() > 10:
13 | velocity *= 0.99
14 | position += velocity
15 | position = position.linear_interpolate(center, 0.03).round()
16 |
--------------------------------------------------------------------------------
/demo/scripts/wandering_node_3d.gd:
--------------------------------------------------------------------------------
1 | extends Spatial
2 |
3 | var velocity = Vector3()
4 | onready var center = transform.origin
5 |
6 | func _ready():
7 | randomize()
8 |
9 |
10 | func _physics_process(_delta):
11 | velocity += Vector3(randf() * 2 - 1, randf() - 0.5, randf() - 0.5) * 0.05
12 | if velocity.length_squared() > 1:
13 | velocity *= 0.99
14 | transform.origin += velocity
15 | transform.origin = transform.origin.linear_interpolate(center, 0.125)
16 |
--------------------------------------------------------------------------------
/docs/use_cases.md:
--------------------------------------------------------------------------------
1 | # Use Cases
2 |
3 | 1. Have you ever wanted to have an overrideable print method in Objects?
4 | - Variant.to_string(value)
5 | 2. Have you ever wanted to get a type as a string, regardless of whether it's an Object (return `get_class()`), or a built-in, e.g. int (return "int")?
6 | - Variant.get_type(value)
7 | 3. Have you ever wanted multiple scripts per Node?
8 | - CallbackDelegator node + Behavior resources
9 | - Supply a "base_type" script or click to initialize the default one.
10 | - This CallbackDelegator has a private property of a new "ResourceSet" type; it's a collection of unique-script resource instances housing types which...
11 | 1. can see the CallbackDelegator node as an 'owner' property.
12 | 2. can be toggled on and off as an 'enabled' property.
13 | 3. receive Node notification callbacks that have been delegated to them by the CallbackDelegator node.
14 | - This is much more efficient than simply having a large number of child nodes.
15 | 1. Resources are more lightweight than scripts.
16 | 2. One can directly save and load Resources from the filesystem.
17 | 3. Better than nodes, one can expand each resource into its own sub-inspector within a single Inspector "view", viewing all the data at once.
18 | 4. Have you ever wanted to wrap an engine type, script type, or scene type under a single API?
19 | - ClassType
20 | - It stores a reference to a *type*. This means it can represent "Node" engine class, "MyNode" script class, anonymous scripts and anonymous scenes equally.
21 | - ClassType.new() functions with being...
22 | - the string name of the class.
23 | - a reference to the script or scene.
24 | - a path to the script or scene.
25 | - an instance of an example object.
26 | - Supplying a Script or PackedScene will revert to the previous cases
27 | - Providing a Node that is the root of a scene will load that scene (since that is an approximation of the Node's type)
28 | - Providing an Object with a script will load that script (since that is the Object's type)
29 | - Providing an Object without a script will set the ClassType.name to be the Object.get_class() value
30 | - `.instance()` returns an instance of the type
31 | - `.get_type_class()` returns the string name of the type
32 | - `.get_type_parent()` returns a ClassType representing the base class of the type.
33 | - Anonymous script vs. named script doesn't matter. Uses `Script.get_base_script()`.
34 | - Also fetches base scene from a PackedScene instance
35 | - If there are no more inherited scenes, a PackedScene will defer first to the root node's script, then to the engine type of the root Node.
36 | - `.get_inheritors_list()` returns a list of the types' derived types.
37 | - The `res` property is the script or scene associated with the type. Therefore, one can get a script class by name with `ClassType.new("MyType").res`.
38 | 5. Have you ever wanted to search through your project folder and identify files which match certain criteria?
39 | - FileSearch
40 | - Has a variety of .search_(p_param, p_starting_directory = "res://", p_do_a_recursive_search = true) methods
41 | 6. Have you ever wanted to create singletons that exist even in the editor context?
42 | - Singletons
43 | - This Reference type stores a static database of all Reference-derived types which can be fetched by their script.
44 | - `Singletons.fetch(MyType)` will return an instance of MyType and ensure that only one instance of it is managed by the Singletons database.
45 | - Can implement one's own static method which converts `Singletons.fetch(MyType)` to `MyType.fetch()`.
46 | 6. Have you ever wanted to send signals to child nodes, resources or even references but you don't want to define all the possible signals in the instance?
47 | - MessageDispatcher
48 | - Allows any object to register a function that handles a specific message_type.
49 | - Emit a message on the dispatcher and it sends it to all relevant handlers or discards it if no handlers were registered.
50 | 7. Have you ever wanted to create a flat gradient with hard transitions?
51 | - DiscreteGradientTexture
52 | - It works like the GradientTexture but ignores the color interpolation of the gradient.
53 |
--------------------------------------------------------------------------------
/format.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Loops through all text files tracked by Git.
4 | git grep -zIl '' |
5 | while IFS= read -rd '' f; do
6 | # Exclude csproj and hdr files.
7 | if [[ $f == *"csproj" ]]; then
8 | continue
9 | elif [[ $f == *"hdr" ]]; then
10 | continue
11 | fi
12 | # Ensures that files are UTF-8 formatted.
13 | recode UTF-8 $f 2> /dev/null
14 | # Ensures that files have LF line endings.
15 | dos2unix $f 2> /dev/null
16 | # Ensures that files do not contain a BOM.
17 | sed -i '1s/^\xEF\xBB\xBF//' "$f"
18 | # Ensures that files end with newline characters.
19 | tail -c1 < "$f" | read -r _ || echo >> "$f";
20 | done
21 |
22 | git diff > patch.patch
23 | FILESIZE=$(stat -c%s patch.patch)
24 | MAXSIZE=5
25 |
26 | # If no patch has been generated all is OK, clean up, and exit.
27 | if (( FILESIZE < MAXSIZE )); then
28 | printf "Files in this commit comply with the formatting rules.\n"
29 | rm -f patch.patch
30 | exit 0
31 | fi
32 |
33 | # A patch has been created, notify the user, clean up, and exit.
34 | printf "\n*** The following differences were found between the code "
35 | printf "and the formatting rules:\n\n"
36 | cat patch.patch
37 | printf "\n*** Aborting, please fix your commit(s) with 'git commit --amend' or 'git rebase -i '\n"
38 | rm -f patch.patch
39 | exit 1
40 |
--------------------------------------------------------------------------------
/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/willnationsdev/godot-next/3b2949fce032bf827ce4fadb7e70f8872b635144/icon.png
--------------------------------------------------------------------------------
/icon.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://icon.png"
13 | dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | stream=false
32 | size_limit=0
33 | detect_3d=true
34 | svg/scale=1.0
35 |
--------------------------------------------------------------------------------
/licenses/LICENSE_Inflector.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) .NET Foundation and Contributors
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
23 | ==============================================================================
24 |
25 | Inflector (https://github.com/srkirkland/Inflector)
26 | The MIT License (MIT)
27 | Copyright (c) 2013 Scott Kirkland
28 |
29 | ==============================================================================
30 |
31 | ByteSize (https://github.com/omar/ByteSize)
32 | The MIT License (MIT)
33 | Copyright (c) 2013-2014 Omar Khudeira (http://omar.io)
34 |
35 | ==============================================================================
36 |
--------------------------------------------------------------------------------
/project.godot:
--------------------------------------------------------------------------------
1 | ; Engine configuration file.
2 | ; It's best edited using the editor UI and not directly,
3 | ; since the parameters that go here are not all obvious.
4 | ;
5 | ; Format:
6 | ; [section] ; section goes between []
7 | ; param=value ; assign values to parameters
8 |
9 | config_version=4
10 |
11 | _global_script_classes=[ {
12 | "base": "Reference",
13 | "class": "Array2D",
14 | "language": "GDScript",
15 | "path": "res://addons/godot-next/references/array_2d.gd"
16 | }, {
17 | "base": "Resource",
18 | "class": "Behavior",
19 | "language": "GDScript",
20 | "path": "res://addons/godot-next/resources/behavior.gd"
21 | }, {
22 | "base": "Reference",
23 | "class": "BitFlag",
24 | "language": "GDScript",
25 | "path": "res://addons/godot-next/references/bit_flag.gd"
26 | }, {
27 | "base": "Reference",
28 | "class": "Bitset",
29 | "language": "GDScript",
30 | "path": "res://addons/godot-next/references/bitset.gd"
31 | }, {
32 | "base": "Reference",
33 | "class": "CSVFile",
34 | "language": "GDScript",
35 | "path": "res://addons/godot-next/references/csv_file.gd"
36 | }, {
37 | "base": "Node",
38 | "class": "CallbackDelegator",
39 | "language": "GDScript",
40 | "path": "res://addons/godot-next/nodes/callback_delegator.gd"
41 | }, {
42 | "base": "Reference",
43 | "class": "ClassType",
44 | "language": "GDScript",
45 | "path": "res://addons/godot-next/references/class_type.gd"
46 | }, {
47 | "base": "TabContainer",
48 | "class": "Cycle",
49 | "language": "GDScript",
50 | "path": "res://addons/godot-next/gui/cycle.gd"
51 | }, {
52 | "base": "Label",
53 | "class": "DebugLabel",
54 | "language": "GDScript",
55 | "path": "res://addons/godot-next/gui/debug_label.gd"
56 | }, {
57 | "base": "ImageTexture",
58 | "class": "DiscreteGradientTexture",
59 | "language": "GDScript",
60 | "path": "res://addons/godot-next/resources/discrete_gradient_texture.gd"
61 | }, {
62 | "base": "Reference",
63 | "class": "EditorTools",
64 | "language": "GDScript",
65 | "path": "res://addons/godot-next/global/editor_tools.gd"
66 | }, {
67 | "base": "Reference",
68 | "class": "FileSearch",
69 | "language": "GDScript",
70 | "path": "res://addons/godot-next/global/file_search.gd"
71 | }, {
72 | "base": "Reference",
73 | "class": "FileSystemLink",
74 | "language": "GDScript",
75 | "path": "res://addons/godot-next/global/file_system_link.gd"
76 | }, {
77 | "base": "CollisionShape2D",
78 | "class": "Geometry2D",
79 | "language": "GDScript",
80 | "path": "res://addons/godot-next/2d/geometry_2d.gd"
81 | }, {
82 | "base": "Reference",
83 | "class": "Icons",
84 | "language": "GDScript",
85 | "path": "res://addons/godot-next/singletons/icons.gd"
86 | }, {
87 | "base": "Reference",
88 | "class": "Inflector",
89 | "language": "GDScript",
90 | "path": "res://addons/godot-next/references/inflector.gd"
91 | }, {
92 | "base": "Reference",
93 | "class": "InspectorControls",
94 | "language": "GDScript",
95 | "path": "res://addons/godot-next/global/inspector_controls.gd"
96 | }, {
97 | "base": "Reference",
98 | "class": "MessageDispatcher",
99 | "language": "GDScript",
100 | "path": "res://addons/godot-next/references/message_dispatcher.gd"
101 | }, {
102 | "base": "Node",
103 | "class": "MessageDispatcherWrapper",
104 | "language": "GDScript",
105 | "path": "res://addons/godot-next/nodes/message_dispatcher_wrapper.gd"
106 | }, {
107 | "base": "Resource",
108 | "class": "PhysicsLayers",
109 | "language": "GDScript",
110 | "path": "res://addons/godot-next/global/physics_layers.gd"
111 | }, {
112 | "base": "Reference",
113 | "class": "ProjectTools",
114 | "language": "GDScript",
115 | "path": "res://addons/godot-next/global/project_tools.gd"
116 | }, {
117 | "base": "Reference",
118 | "class": "PropertyInfo",
119 | "language": "GDScript",
120 | "path": "res://addons/godot-next/references/property_info.gd"
121 | }, {
122 | "base": "Reference",
123 | "class": "PropertyInfoFactory",
124 | "language": "GDScript",
125 | "path": "res://addons/godot-next/references/property_info_factory.gd"
126 | }, {
127 | "base": "ResourceCollection",
128 | "class": "ResourceArray",
129 | "language": "GDScript",
130 | "path": "res://addons/godot-next/resources/resource_collections/resource_array.gd"
131 | }, {
132 | "base": "Resource",
133 | "class": "ResourceCollection",
134 | "language": "GDScript",
135 | "path": "res://addons/godot-next/resources/resource_collections/resource_collection.gd"
136 | }, {
137 | "base": "ResourceCollection",
138 | "class": "ResourceSet",
139 | "language": "GDScript",
140 | "path": "res://addons/godot-next/resources/resource_collections/resource_set.gd"
141 | }, {
142 | "base": "Reference",
143 | "class": "Singletons",
144 | "language": "GDScript",
145 | "path": "res://addons/godot-next/global/singletons.gd"
146 | }, {
147 | "base": "Line2D",
148 | "class": "Trail2D",
149 | "language": "GDScript",
150 | "path": "res://addons/godot-next/2d/trail_2d.gd"
151 | }, {
152 | "base": "ImmediateGeometry",
153 | "class": "Trail3D",
154 | "language": "GDScript",
155 | "path": "res://addons/godot-next/3d/trail_3d.gd"
156 | }, {
157 | "base": "Reference",
158 | "class": "TweenSequence",
159 | "language": "GDScript",
160 | "path": "res://addons/godot-next/references/tween_sequence/tween_sequence.gd"
161 | }, {
162 | "base": "Reference",
163 | "class": "Tweener",
164 | "language": "GDScript",
165 | "path": "res://addons/godot-next/references/tween_sequence/tweener.gd"
166 | }, {
167 | "base": "VBoxContainer",
168 | "class": "VBoxItemList",
169 | "language": "GDScript",
170 | "path": "res://addons/godot-next/gui/v_box_item_list.gd"
171 | }, {
172 | "base": "Reference",
173 | "class": "Variant",
174 | "language": "GDScript",
175 | "path": "res://addons/godot-next/global/variant.gd"
176 | }, {
177 | "base": "Node",
178 | "class": "VectorDisplay2D",
179 | "language": "GDScript",
180 | "path": "res://addons/godot-next/2d/vector_display_2d.gd"
181 | }, {
182 | "base": "Node",
183 | "class": "VectorDisplay3D",
184 | "language": "GDScript",
185 | "path": "res://addons/godot-next/3d/vector_display_3d.gd"
186 | } ]
187 | _global_script_class_icons={
188 | "Array2D": "",
189 | "Behavior": "",
190 | "BitFlag": "",
191 | "Bitset": "",
192 | "CSVFile": "",
193 | "CallbackDelegator": "",
194 | "ClassType": "",
195 | "Cycle": "res://addons/godot-next/icons/icon_cycle.svg",
196 | "DebugLabel": "",
197 | "DiscreteGradientTexture": "",
198 | "EditorTools": "",
199 | "FileSearch": "",
200 | "FileSystemLink": "",
201 | "Geometry2D": "res://addons/godot-next/icons/icon_geometry_2d.svg",
202 | "Icons": "",
203 | "Inflector": "",
204 | "InspectorControls": "",
205 | "MessageDispatcher": "",
206 | "MessageDispatcherWrapper": "",
207 | "PhysicsLayers": "",
208 | "ProjectTools": "",
209 | "PropertyInfo": "",
210 | "PropertyInfoFactory": "",
211 | "ResourceArray": "",
212 | "ResourceCollection": "",
213 | "ResourceSet": "",
214 | "Singletons": "",
215 | "Trail2D": "res://addons/godot-next/icons/icon_trail_2d.svg",
216 | "Trail3D": "res://addons/godot-next/icons/icon_trail_3d.svg",
217 | "TweenSequence": "",
218 | "Tweener": "",
219 | "VBoxItemList": "res://addons/godot-next/icons/icon_v_box_item_list.svg",
220 | "Variant": "",
221 | "VectorDisplay2D": "",
222 | "VectorDisplay3D": ""
223 | }
224 |
225 | [application]
226 |
227 | config/name="Godot Node Extensions"
228 | config/description="Godot Node Extensions, AKA Godot NExt.
229 | Contains many script classes that extend Godot with new functionality."
230 | run/main_scene="res://demo/demo.tscn"
231 | config/icon="res://icon.png"
232 |
233 | [editor_plugins]
234 |
235 | enabled=PoolStringArray( "godot-next" )
236 |
237 | [rendering]
238 |
239 | quality/driver/driver_name="GLES2"
240 | vram_compression/import_etc=true
241 | vram_compression/import_etc2=false
242 | environment/default_environment="res://default_env.tres"
243 |
--------------------------------------------------------------------------------