-
-
Notifications
You must be signed in to change notification settings - Fork 21.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Code completion (type inference?) not working for custom types #74888
Comments
BTW, is this really "incorrect" or just "incomplete"? The screenshot shows methods for |
I believe so (in my opinion) because it's explicitly typed to the class, which has those properties. Using a variable specifically declared as PlayerState does not include RefCounted properties. You're a godot dev, so please correct me if I'm wrong! I have a class, PlayerState which is in a PlayerState.gd file that has no extends at all. Simply If I have a function that returns a value of type PlayerState, I would expect that it would be treated the same in the code editor as a variable who's type is explicitly defined as PlayerState. Even more confusingly, casting the returned value with "as PlayerState" makes the right values show up -- even though I'm literally casting it to itself. It feels like the editor seems to just default to RefCounted type when using a custom base type. Either that or I'm dumb and doing something wrong. |
Here's a partial file of PlayerState.gd (only included some of the vars, but the rest of the file is just more vars in the same manner: ## Represents an instance of a player
class_name PlayerState
## The multiplayer network ID
var remote_id:int = -1
## The name of the account (a@b.com)
var account_name:String = ""
## The selected character name
var character:String = ""
## True if account is logged in
var logged_in:bool = false
## True if character is loading a map
var loading:bool = true Here's the function in another module that uses this type: func player_get(network_id:int) -> PlayerState:
if not Director.is_server:
push_error("Tried to get a player on the client side!")
return null
if not players.has(network_id):
push_error("Failed to find player " + str(network_id) + "!")
return null
return players[network_id] as PlayerState Interesting to note that I have to cast players[network_id] as PlayerState because I can't define value types in Dictionaries (as far as I can tell), but the content is absolutely a PlayerState object. But perhaps this is somehow confusing things, or maybe the paths that return NULL? |
Did a quick test, is your PlayerManager an autoload? Using the function in the same file works, using an autoloaded class doesn't work. |
Yes, PlayerManager is autoloaded as it needs to basically be a singleton for the instance. Is there an alternative to AutoLoad for static instances (singletons) or is this a legit bug with auto loaded instances? Great find @Piralein! |
If you don't use There's definitely something odd going on given it's detecting something (RefCounted) but not the actual class. |
Awesome, I though I was going crazy and doing something horribly wrong. I just finished refactoring my entire codebase to use strongly defined class types and was worried I wasted a bunch of time. Thanks for figuring out what the specific problem is! |
v4.1.stable.official [9704596] It doesn't have to have class keywords. If you defined a var or func, it's not suggested in a different script's code completion. Along with increasing the risk of typos, it adds additional steps for writing correct code. I'm a relatively new dev. When I learned about type hints, I started using them too. Because getting completion saves many things. As can be seen, particle.gd file is saved, with a var called "potato". To make it resemble public variables, I even added @export to it. But it's not suggested in border.gd when I refer to the node in the script. I also made sure to edit both codes in main.tscn scene to make sure they were both instantiated in the scene in some way. |
@santibag In this particular case, the behavior is expected. The Autocompletion can give you correct suggestions for node paths, variables, functions, etc. only if this scene is the currently open one in the editor. This does not work for other scenes as the same script can be attached to different scenes. See also godotengine/godot-proposals#1935. To workaround this, I recommend using Also, some people use the |
This is actually quite annoying, having code complete on normal custom classes with properties of other custom classes work just fine, you put it as Autload and bam, it doesn't work anymore, to make matters worse there's not work around to that, managing a project with a couple autoloads and several properties/methods with custom classes. I'm almost certain this seems like a regression since I don't think I used to have this issue before 4.1. |
It felt like I been dealing with this bug since 3.x, even having type hints as your variables doesn't allow the autocomplete to work. Probably one of the most annoying bugs in this engine so far since most of my scripts in most of my projects point to an autoload so I basically never get any type hints at all. I usually have to do special key combos like Shift Alt O, and go between the files, just to check out the types. This happens to not just functions but variables as well in autoload. Wasn't there another issue on autoload not returning any type hints in a different way? |
So looking at this I found three issues in the code. Two of which should be easy to fix:
Those two things can be changed at one point and will fix most of the cases dealing with this. (That said before working on that, other issues and PR's should be cross referenced since the auto completion issues tend to overlap and I also kinda remember other issues and PR's regarding autoloads.
The two solutions I see for this is either expanding |
Not sure if this helps anything, but I noticed that if you set a custom type variable to static, suddenly the autoload code complete starts working # main_controller.gd
static var game: GameScene Quick update here... I digged through the whole thing and like @HolonProduction said, it boils down to PropertyInfo which's fed by StringName GDScript::get_instance_base_type() const {
if (native.is_valid()) {
return native->get_name();
}
if (base.is_valid() && base->is_valid()) {
return base->get_instance_base_type();
}
return StringName();
} And once it tries to check for a valid type from that property, it checks if a if (ScriptServer::is_global_class(p_property.class_name)) { I changed |
Just out of curiosity, is there a reason why |
Could you provide the exact case were this happens? I get this as output:
Would be good to look into the cases were this does not get propagated correctly. |
Also changing |
It's because, like you mentioned, autoloads are treated like var a1: CustomScript
var a2: Node all properties with custom types become the native class they extend, so Autoload.a1. as for your example, I was talking about the source, apparently, if your property is of type |
Ok somewhat misread what you wrote. Doesn't change much for me:
Still gives me: { "name": "val", "class_name": &"State", "type": 24, "hint": 0, "hint_string": "", "usage": 4096 } Furthermore I also debugged the problem and created three PR's for it. All those PR's make sure that the code completion properly handles the global class_name when it receives one. In all cases that I tested the global class_name reached the code completion without problems. So please provide clear steps to reproduce the case were the PropertyInfo does not contain the global class name.
In my tests
Screencast.from.2023-11-30.11-12-14.webm |
Try this: #thing.gd
extends Node
class_name StuffThing
var bla: int = 10 #autoload.gd
extends Node
var a: StuffThing #any other file
extends Node2D
func _ready():
var l = Autoload.get_script().get_script_property_list()
print(l) outputs:
As you can see, var Also like I mentioned before, |
Can't reproduce 😕
v4.3.dev.custom_build [d76c1d0] |
OH, good call, I've been testing around 4.1 branch not master, my bad, sorry |
Godot version
4.0
System information
MacOS
Issue description
When calling a function that has a custom class, the return type is disregarded unless I explicitly cast the result to the type in the editor (breaking code completion)...
I have this function defined in a global class:
When I try to use the value returned by it, I get incorrect code completion:
Creating a new variable of the same type works (in the same file)
And if I cast the type to itself it also works...
Steps to reproduce
Create a custom class with class_name.
Create a function in a global scene that returns an instance of that class type.
Try to reference the return value and see code completion is broken.
Minimal reproduction project
I've provided specific screenshots describing the issue.
The text was updated successfully, but these errors were encountered: