urho icon indicating copy to clipboard operation
urho copied to clipboard

Node.GetVar

Open wmigor opened this issue 8 years ago • 5 comments

The Node does not have GetVar

wmigor avatar May 04 '17 18:05 wmigor

I have an extension class for Node and UIElement GetVar(string name) and a Variant Reader for Variant returned from GetAttribute() It's not tested much and it is missing some types of Variant but it works on Android 32 and 64 bit and on Windows Desktop. here is the code: https://pastebin.com/n17fkHwF

I didn't have the time to track down how some of the types must be read and i didn't perform any optimization on it.

Anybody who wants to use it, feel free to, just share other Variant getters and let me know if it works at all on iOS

Question for UrhoSharp Developers (or anyone who can explain it) The code in Variant IntPtrToVariant(this IntPtr ptr) must read all VariantValueLine with an offset of 4 bytes from the previous value line to work, even on 64 bit architectures. Whitout this function the Variants read from the unmanaged memory (Urho3D) on 64 bit architectures becomes unaligned: VariantValueLine1 reads the first and second union and VariantValueLine2 reads the third and fourth union VariantValueLine3 and VariantValueLine4 end up as gibberish. Why?

Fastran avatar May 12 '17 17:05 Fastran

@Fastran wow, great job! is not that offset is a VariantType Type field? Have you tried to just read Variant as Marshal.PtrToStructure(ptr, typeof(Variant)) ?

EgorBo avatar May 13 '17 01:05 EgorBo

I tried Marshal.PtrToStructure(ptr, typeof(Variant)), it works fine on a 32 bit architecture. On a 64 bit architecture for a Variant of type Vector4 it reads the type correctly, VariantValueLine1 was also correct but VariantValueLine2 reads what is supposed to be the third value and VariantValueLine3 and VariantValueLine4 read after the end of the c++ struct.

From what i have seen a Urho3D Variant is always like this in memory

Field 32 bit offset 32 bit size 64 bit offset 64 bit size
type 0 4 0 4
Value1 4 4 8 8
Value2 8 4 12 8
Value3 12 4 16 8
Value4 16 4 20 8

I really can't understand the strange alignment of variables on the 64 bit architecture, the only thing that comes to mind is if it can derive from how Urho3D is compiled to be used on Xamarin, but i don't know anything of how that works

Edit

The table i've written before is wrong. I think the problem arises because the c++ code basically copies the corresponding object over the structure using the assignment operator i.e.

*(reinterpret_cast<Vector4*>(&value_)) = rhs;

on 64bit machine, when those data are copied into the variantvalue struct, there is a mismatch between the memory alignment of the copied type(i.e. vector4) and the variantvalue struct: the vector4 components are correctly 32bit wide on both 32 and 64 bit machine (since the components are float) while the c# structure (defined as sequential and composed by intptr) is correctly 8 bytes on a 64bit machine and 4 byte on a 32bit machine. This results on alignment problems depending on the type therefore the reading of each type must be done accordingly. Am i missing something?

Fastran avatar May 15 '17 08:05 Fastran

Here is the code from before, with a couple of correction and the rest of the types, albeit some untested (the ones marked as obsolete). https://pastebin.com/KKjVqnw8 At the moment i can't test it on iOS but i don't see why it shouldn't work there.

Correction

static public void PrintVariant(this Variant v)
        {
            var dummy = v.GetValue();
            try
            {
                Debug.WriteLine(v.Type + " " + dummy);
            }
            finally { }
        }

should be

static public void PrintVariant(this Variant v)
        {
            dynamic dummy = v.GetValue();
            try
            {
                System.Diagnostics.Debug.WriteLine(v.Type+" "+dummy);
            }
            finally { }
        }

Fastran avatar May 16 '17 10:05 Fastran

Hi! I use UrhoSharp.1.8.91

public static float GetVarFloat(this Node node, string name) {
             float res = 0f;
             var map = node.GetAttribute("Variables").Value;
             var ptr = Marshal.AllocHGlobal(Marshal.SizeOf(map));
             Marshal.StructureToPtr(map, ptr, false);
             var data = new EventDataContainer(ptr);
             res = data.get_float(new StringHash(name).Code);
             Marshal.FreeHGlobal(ptr);
             return res;
        }

this code works on Windows 64, but fails on Android 32, just throws it out of the application

AlekseySilver avatar Mar 14 '18 06:03 AlekseySilver