private static unsafe JavaScriptValue CreateEntity(JavaScriptValue callee, bool isconstructcall, JavaScriptValue[] arguments, ushort argumentcount, IntPtr callbackdata)
        {
            var factory       = JSTypeFactories.GetFactory("Entity");
            var commandBuffer = arguments[0].ObjectFromJavaScriptValue <EntityCommandBuffer>();

            var entity = commandBuffer.CreateEntity();
            var ptr    = UnsafeUtility.Malloc(UnsafeUtility.SizeOf <Entity>(), UnsafeUtility.AlignOf <Entity>(), Allocator.Persistent);

            UnsafeUtility.CopyStructureToPtr <Entity>(ref entity, ptr);

            return(factory.CreateJsObjectForNative(ptr, true));
        }
        private static unsafe JavaScriptValue SetComponent(JavaScriptValue callee, bool isconstructcall, JavaScriptValue[] arguments, ushort argumentcount, IntPtr callbackdata)
        {
            var commandBuffer = arguments[0].ObjectFromJavaScriptValue <EntityCommandBuffer>();
            var componentName = arguments[1].ToString();
            var entityData    = (void *)arguments[2].ExternalData;
            var componentData = (void *)arguments[3].ExternalData;

            UnsafeUtility.CopyPtrToStructure <Entity>(entityData, out var entity);

            var factory = JSTypeFactories.GetFactory(componentName);

            commandBuffer.AddComponent(entity, factory.ReadComponentType);
            factory.EntityCommandBufferSetComponent(commandBuffer, entity, componentData);

            return(JavaScriptValue.Undefined);
        }
        public JavaScriptValue CreateQuery(string[] components, JavaScriptValue callback)
        {
            Array.Sort(components, StringComparer.InvariantCulture);
            var key = string.Join("_", components);

            if (!queryRefs.ContainsKey(key))
            {
                var componentTypes = new ComponentType[components.Length];
                var offsetMap      = new Dictionary <string, int>();

                //First slot is designated for entity reference
                offsetMap.Add("Entity", 0);
                var offset = UnsafeUtility.SizeOf <Entity>();

                for (var i = 0; i < components.Length; i++)
                {
                    var factory = JSTypeFactories.GetFactory(components[i]);

                    componentTypes[i] = factory.ReadComponentType;
                    offsetMap.Add(components[i], offset);

                    offset += factory.ComponentSize;
                }

                var q = GetEntityQuery(componentTypes);

                callback.AddRef();

                queryRefs.Add(key, new QueryData
                {
                    HasData          = false,
                    Query            = q,
                    Components       = components,
                    OffsetMap        = offsetMap,
                    SlotSize         = offset,
                    OnChangeCallback = callback,
                    ComponentTypes   = componentTypes
                });
            }

            var getSizeFunction = JavaScriptValue.CreateFunction("getSize", (callee, call, arguments, count, data) =>
            {
                var currentQueryData = arguments[0].ObjectFromJavaScriptValue <QueryData>();

                return(JavaScriptValue.FromInt32(currentQueryData.Size));
            });

            var getVersionFunction = JavaScriptValue.CreateFunction("getVersion", (callee, call, arguments, count, data) =>
            {
                var currentQueryData = arguments[0].ObjectFromJavaScriptValue <QueryData>();

                unsafe
                {
                    var ptr = (int *)currentQueryData.DataPtr;

                    return(JavaScriptValue.FromInt32(*ptr));
                }
            });

            var getHasDataFunction = JavaScriptValue.CreateFunction("getHasData", (callee, call, arguments, count, data) =>
            {
                var currentQueryData = arguments[0].ObjectFromJavaScriptValue <QueryData>();

                return(JavaScriptValue.FromBoolean(currentQueryData.HasData));
            });

            var getElementAtFunction = JavaScriptValue.CreateFunction("getElementAt", (callee, call, arguments, count, data) =>
            {
                var currentQueryData = arguments[0].ObjectFromJavaScriptValue <QueryData>();

                if (arguments.Length < 3 ||
                    arguments[1].ValueType != JavaScriptValueType.String ||
                    arguments[2].ValueType != JavaScriptValueType.Number ||
                    currentQueryData == null ||
                    currentQueryData.IsDisposed ||
                    !currentQueryData.HasData)
                {
                    return(JavaScriptValue.Null);
                }

                var slot = arguments[1].ToString();

                if (!currentQueryData.OffsetMap.ContainsKey(slot))
                {
                    return(JavaScriptValue.Null);
                }

                if (arguments[2].ToInt32() >= currentQueryData.Size)
                {
                    return(JavaScriptValue.Null);
                }

                var indexInArray = currentQueryData.SlotSize * arguments[2].ToInt32();
                var slotIndex    = currentQueryData.OffsetMap[slot];
                var factory      = JSTypeFactories.GetFactory(slot);

                if (!JavaScriptContext.Current.IsValid)
                {
                    return(JavaScriptValue.Null);
                }

                unsafe
                {
                    var ptr = (byte *)currentQueryData.DataPtr + HeaderDataOffset + indexInArray + slotIndex;

                    var output = UnsafeUtility.Malloc(factory.ComponentSize, 4, Allocator.Persistent);
                    UnsafeUtility.MemCpy(output, ptr, factory.ComponentSize);

                    return(factory.CreateJsObjectForNative(output, true));
                }
            });

            var disposeFunction = JavaScriptValue.CreateFunction("dispose", (callee, call, arguments, count, data) =>
            {
                var currentQueryData = arguments[0].ObjectFromJavaScriptValue <QueryData>();

                currentQueryData.Dispose();

                return(JavaScriptValue.Undefined);
            });

            var queryData = queryRefs[key];
            var handle    = GCHandle.Alloc(queryData);
            var p         = GCHandle.ToIntPtr(handle);

            var ret = JavaScriptValue.CreateExternalObject(p, Finalizer);

            ret.SetProperty(JavaScriptPropertyId.FromString("getSize"), getSizeFunction, true);
            ret.SetProperty(JavaScriptPropertyId.FromString("hasData"), getHasDataFunction, true);
            ret.SetProperty(JavaScriptPropertyId.FromString("getElementAt"), getElementAtFunction, true);
            ret.SetProperty(JavaScriptPropertyId.FromString("dispose"), disposeFunction, true);
            ret.SetProperty(JavaScriptPropertyId.FromString("getVersion"), getVersionFunction, true);

            return(ret);
        }