/// <inheritdoc />
        public void AddComponent <T>(IEntity entity, T component, bool overwrite = false) where T : Component
        {
            if (entity == null || !entity.IsValid())
            {
                throw new ArgumentException("Entity is not valid.", nameof(entity));
            }

            if (component == null)
            {
                throw new ArgumentNullException(nameof(component));
            }

            if (component.Owner != entity)
            {
                throw new InvalidOperationException("Component is not owned by entity.");
            }

            var uid = entity.Uid;

            // get interface aliases for mapping
            var reg = _componentFactory.GetRegistration(component);

            // Check that there are no overlapping references.
            foreach (var type in reg.References)
            {
                if (!TryGetComponent(uid, type, out var duplicate))
                {
                    continue;
                }

                if (!overwrite)
                {
                    throw new InvalidOperationException(
                              $"Component reference type {type} already occupied by {duplicate}");
                }

                // these two components are required on all entities and cannot be overwritten.
                if (duplicate is ITransformComponent || duplicate is IMetaDataComponent)
                {
                    throw new InvalidOperationException("Tried to overwrite a protected component.");
                }

                RemoveComponentImmediate((Component)duplicate);
            }

            // add the component to the grid
            foreach (var type in reg.References)
            {
                _entTraitDict[type].Add(uid, component);
                _entCompIndex.Add(uid, component);
            }

            // add the component to the netId grid
            if (component.NetID != null)
            {
                // the main comp grid keeps this in sync

                var netId = component.NetID.Value;
                _entNetIdDict[netId].Add(uid, component);

                // mark the component as dirty for networking
                component.Dirty();

                ComponentAdded?.Invoke(this, new AddedComponentEventArgs(component));
            }

            component.ExposeData(DefaultValueSerializer.Reader());

            component.OnAdd();

            if (!entity.Initialized && !entity.Initializing)
            {
                return;
            }

            component.Initialize();

            DebugTools.Assert(component.Initialized, "Component is not initialized after calling Initialize(). "
                              + "Did you forget to call base.Initialize() in an override?");

            if (entity.Initialized)
            {
                component.Running = true;
            }
        }
        /// <inheritdoc />
        public void AddComponent(IEntity entity, Component component, bool overwrite = false)
        {
            if (entity == null || !entity.IsValid())
            {
                throw new ArgumentException("Entity is not valid.", nameof(entity));
            }

            if (component == null)
            {
                throw new ArgumentNullException(nameof(component));
            }

            if (component.Owner != entity)
            {
                throw new InvalidOperationException("Component is not owned by entity.");
            }

            // get interface aliases for mapping
            var reg = _componentFactory.GetRegistration(component);

            // Check that there are no overlapping references.
            foreach (var type in reg.References)
            {
                if (!TryGetComponent(entity.Uid, type, out var duplicate))
                {
                    continue;
                }

                if (!overwrite)
                {
                    throw new InvalidOperationException(
                              $"Component reference type {type} already occupied by {duplicate}");
                }

                // these two components are required on all entities and cannot be overwritten.
                if (duplicate is ITransformComponent || duplicate is IMetaDataComponent)
                {
                    throw new InvalidOperationException("Tried to overwrite a protected component.");
                }

                RemoveComponentImmediate((Component)duplicate);
            }

            // add the component to the grid
            foreach (var type in reg.References)
            {
                _dictComponents[type].Add(entity.Uid, component);
            }

            // add the component to the netId grid
            if (component.NetID != null)
            {
                // the main comp grid keeps this in sync
                if (!_netComponents.TryGetValue(entity.Uid, out var netDict))
                {
                    netDict = new Dictionary <uint, Component>(CompTypeCapacity);
                    _netComponents.Add(entity.Uid, netDict);
                }

                netDict.Add(component.NetID.Value, component);

                // mark the component as dirty for networking
                component.Dirty();

                ComponentAdded?.Invoke(this, new ComponentEventArgs(component));
            }

            component.ExposeData(DefaultValueSerializer.Reader());

            component.OnAdd();

            if (entity.Initialized || entity.Initializing)
            {
                component.Initialize();

                if (entity.Initialized)
                {
                    component.Running = true;
                }
            }
        }