Skip to content
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

Attempted to convert an unmarshallable managed type to Variant #36351

Closed
cbaal83 opened this issue Feb 19, 2020 · 10 comments
Closed

Attempted to convert an unmarshallable managed type to Variant #36351

cbaal83 opened this issue Feb 19, 2020 · 10 comments

Comments

@cbaal83
Copy link

cbaal83 commented Feb 19, 2020

Godot version:
3.2
OS/device including version:
Linux/Windows , happens on all platforms i tested
Issue description:
It might be related to #17565, not sure. In my case it happens even with an Empty class, please see below how to reproduce. Not sure if iam doing something fundamentally wrong here, but this is how i understand the plugin system.
Steps to reproduce:
Activate the plugin under project settings ->
New Scene -> Create 3D Root Node -> Attach Child -> Pick "Bug" Spatial -> Select Spatial node in the tree -> Right Click -> Remove Node -> watch Console.
Minimal reproduction project:
PluginBug.zip

@git2013vb
Copy link

git2013vb commented Apr 10, 2020

I have similar error:
3.2.1. stable mono - Debian 10

E 0:00:08.498   mono_object_to_variant_impl: Attempted to convert an unmarshallable managed type to Variant. Name: 'CharacterInput2D' Encoding: 17.
  <C++ Error>   Method failed. Returning: Variant()
  <C++ Source>  modules/mono/mono_gd/gd_mono_marshal.cpp:912 @ mono_object_to_variant_impl()
  <Stack Trace> :0 @ Int32 Godot.Collections.Array.godot_icall_Array_Add(IntPtr , System.Object )()
                Array.cs:105 @ Int32 Godot.Collections.Array.Add(System.Object )()
                Array.cs:320 @ void Godot.Collections.Array`1[[GodotEntities.CharacterInput2D, desert_edge_sharp, Version=1.0.7405.29442, Culture=neutral, PublicKeyToken=null]].Add(GodotEntities.CharacterInput2D )()
                Peer.cs:124 @ void Peer.AuthCharInputProcess(Single )()
                Peer.cs:87 @ void Peer._Process(Single )()

My attempt is described in forum here: https://godotforums.org/discussion/22532/rpc-with-c-structs

I did some investigation and seems Godot limitation. It don't allow as parameters non primitive values. There is a plan to fix this?

@kayomn
Copy link
Contributor

kayomn commented Jun 9, 2020

Classes can circumvent this issue by inheriting Godot.Object but something to note is that this same rule does not apply when using generics.

Given the following structure signature:

public class ItemInstance<ItemType> : Object, IItemInstance where ItemType : BaseItem

The following code does not work:

visitor.Items.Add(new ItemInstance<BaseWeaponItem>
{
	Item = this,
	Durability = 100.0f
});

Producing the same type marshalling error as above. However, when extended into a new type like so:

public class WeaponInstance : ItemInstance<BaseWeaponItem>

It works fine when used:

visitor.Items.Add(new WeaponInstance
{
	Item = this,
	Durability = 100.0f
});

A similar behavior happens in Unity, as it is not able to serialize generic class instances without some kind of aliasing extension layer.

@kayomn
Copy link
Contributor

kayomn commented Jun 11, 2020

Had a look through the code that produces this error and I reckon the issue is here:

https://github.com/godotengine/godot/blob/master/modules/mono/mono_gd/gd_mono_marshal.cpp#L915

From what I can surmise from this quick check either Godot or the Mono runtime builds a cache of supported object types. I assume it fails the is_assignable_from check for non-Godot.Object types for obvious reasons, however for generics that implement Godot.Object I'm not sure why they're failing.

The best guess I can hazard is that because generics are generated at runtime by the Mono JIT compiler, the class cache never gets those types registered as being assignable to a Godot.Object instance?

Tho, to be honest I'm curious why user data references, like Mono objects, could not be supported by the Godot Variant type out of the box. I can kind of understand struct types not being supported due to the obvious concerns around references leaving scope but I reckon they could be boxed and raised onto the heap.

What might be a good alternative is requiring types all implement some interface that has no fields or methods?

I don't know the codebase well enough, and I certainly don't know Mono's runtime implementation well enough either though to be certain about any of this, however.

@codewing
Copy link

codewing commented Apr 29, 2021

I have the same issue when performing an RPC in C#
I've tried to change my struct (PlayerInfo.cs in the attached code) to a class inheriting from Godot.Object but this didn't solve the issue
lobby.zip

@cjpdev
Copy link

cjpdev commented May 27, 2021

Only 'Godot.Collections.Dictionary' seems works: Godot v3.3.stable.mono.official

        // Godot.Collections.Dictionary to JSON
        var dict = new Godot.Collections.Dictionary<string, object>();

        dict ["name"] = "chay";
        dict ["id"] = 80230;
       
        string result = JSON.Print(dict );
        GD.Print("JSON : = " + result);
        // JSON parse to Godot.Collections.Dictionary
        JSONParseResult parseResult = JSON.Parse("{\"name\":\"chay\",\"id\":80230}");

        if(parseResult.Error == Error.Ok)
        {
            var dict = new Godot.Collections.Dictionary<string, object>((Godot.Collections.Dictionary)parseResult.Result);
            GD.Print("name : = " + dict["name"]);
            GD.Print("id : = " + dict["id"]);
        }

@neikeq
Copy link
Contributor

neikeq commented May 28, 2021

Classes can circumvent this issue by inheriting Godot.Object but something to note is that this same rule does not apply when using generics.

Given the following structure signature:

public class ItemInstance<ItemType> : Object, IItemInstance where ItemType : BaseItem

The following code does not work:

visitor.Items.Add(new ItemInstance<BaseWeaponItem>
{
	Item = this,
	Durability = 100.0f
});

Producing the same type marshalling error as above. ...

That's a marshalling bug. I think it happens because we have two paths, one for generic types and another for non-generic. We only check for Godot Objects in the latter, and only use the generics path for collections. It should be a trivial fix.

@neikeq
Copy link
Contributor

neikeq commented May 28, 2021

Tho, to be honest I'm curious why user data references, like Mono objects, could not be supported by the Godot Variant type out of the box.

Direct support in Variant requires approval and IIRC last time I asked reduz he didn't agree. Albeit that was long ago.
An alternative is to wrap the handle into a Reference (as it needs to be released). That's expensive (unless we could use pooling) so it never felt good enough for me to implement.

@kayomn
Copy link
Contributor

kayomn commented May 28, 2021

Direct support in Variant requires approval and IIRC last time I asked reduz he didn't agree. Albeit that was long ago.
An alternative is to wrap the handle into a Reference (as it needs to be released). That's expensive (unless we could use pooling) so it never felt good enough for me to implement.

Passing structs between Mono and Godot can be worked around once the generics problem is resolved, as you can create a Box<T> type which only serves to raise data onto the heap.

However, I see no reason why C# arrays of structs shouldn't be directly supported without additional wrapping, as they already exist in dynamic memory.

@Beider
Copy link

Beider commented Aug 7, 2021

I am having a similar problem with editor plugins. I got a dictionary containing a custom class In my editor plugin, whenever I trigger a build of my game it will break my plugin and just give me this per item in the dictionary:

ERROR: Attempted to convert Variant to an unmarshallable managed type. Name: 'JsonViewer/UpdatableItem' Encoding: 18.
At: modules/mono/mono_gd/gd_mono_marshal.cpp:689

I get similar errors if I store my custom items in variables as well. I can inherit from Godot.Object to get rid of the errors but all my data seems to be lost if I do that. I also tried moving everything into a static datastorage class and only keeping string ID references around in my plugin but that also fails as the data in the static class is lost after build.

So my solution to this was to move my data into static storage classes so I avoid marshalling errors, then in addition I have a static boolean in the class for my plugin root Control.

public static bool Rebuild = true;

Then I simply check if this is true Inside the _Process and if it is true I rebuild every UI and make sure I setup all references again since I know all old references have been lost. This works since it seems after a build happens your static variables are all reset thus you can detect when a rebuild happens this way.

public override void _Process(float delta)
{
if (Rebuild)
{
ReloadEverything();
Rebuild = false;
}
}

This is a proper hassle but it works, hopefully in godot 4.0 or some later version this will no longer be necessary, but if anyone else has problems with C# EditorPlugins or [Tool] scripts this is the way to go.

@raulsntos
Copy link
Member

With the original author's MRP I could not reproduce the issue and since the MRP does not use structs or generics it seems like the rest of the comments refer to different issues:

I think the commenters ended up in this issue because the error message was the same but they all seem to be unrelated.

I'd suggest closing this issue since other issues are already open about the specific problems that the other commenters are having.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

10 participants