Esempio n. 1
0
        private void CreateEventsFromAssemblies()
        {
            // Find methods with EventAttribute in any ISystem in any assembly.
            var events = new AssemblyScanner()
                         .IncludeAllAssemblies()
                         .IncludeNonPublicMembers()
                         .Implements <ISystem>()
                         .ScanMethods <EventAttribute>();

            // Gather event data, compile invoker and add the data to the events collection.
            foreach (var(method, attribute) in events)
            {
                CoreLog.LogDebug("Adding event listener on {0}.{1}.", method.DeclaringType, method.Name);

                var name = attribute.Name ?? method.Name;

                if (!_events.TryGetValue(name, out var @event))
                {
                    _events[name] = @event = new Event(Invoke);
                }

                var argsPtr          = 0; // The current pointer in the event arguments array.
                var parameterSources = method.GetParameters()
                                       .Select(info => new MethodParameterSource(info))
                                       .ToArray();

                // Determine the source of each parameter.
                foreach (var source in parameterSources)
                {
                    var type = source.Info.ParameterType;

                    if (typeof(Component).IsAssignableFrom(type))
                    {
                        // Components are provided by the entity in the arguments array of the event.
                        source.ParameterIndex = argsPtr++;
                        source.IsComponent    = true;
                    }
                    else if (type.IsValueType || DefaultParameterTypes.Contains(type))
                    {
                        // Default types are passed straight trough.
                        source.ParameterIndex = argsPtr++;
                    }
                    else
                    {
                        // Other types are provided trough Dependency Injection.
                        source.IsService = true;
                    }
                }

                var invoker = CreateInvoker(method, parameterSources, argsPtr);
                @event.Invokers.Add(invoker);
            }
        }
Esempio n. 2
0
        private void CreateTimersFromAssemblies(long tick)
        {
            // Find methods with TimerAttribute in any ISystem in any assembly.
            var events = new AssemblyScanner()
                         .IncludeAllAssemblies()
                         .IncludeNonPublicMembers()
                         .Implements <ISystem>()
                         .ScanMethods <TimerAttribute>();

            // Create timer invokers and store timer info in registry.
            foreach (var(method, attribute) in events)
            {
                CoreLog.LogDebug("Adding timer on {0}.{1}.", method.DeclaringType, method.Name);

                if (!IsValidInterval(attribute.IntervalTimeSpan))
                {
                    CoreLog.Log(CoreLogLevel.Error, $"Timer {method} could not be registered the interval {attribute.IntervalTimeSpan} is invalid.");
                    continue;
                }

                var service = _serviceProvider.GetService(method.DeclaringType);

                if (service == null)
                {
                    CoreLog.Log(CoreLogLevel.Debug, "Skipping timer registration because service could not be loaded.");
                    continue;
                }

                var parameterInfos = method.GetParameters()
                                     .Select(info => new MethodParameterSource(info)
                {
                    IsService = true
                })
                                     .ToArray();

                var compiled = MethodInvokerFactory.Compile(method, parameterInfos);

                if (attribute.IntervalTimeSpan < LowInterval)
                {
                    CoreLog.Log(CoreLogLevel.Warning, $"Timer {method.DeclaringType}.{method.Name} has a low interval of {attribute.IntervalTimeSpan}.");
                }

                var timer = new TimerInfo
                {
                    IsActive      = true,
                    Invoke        = () => compiled(service, null, _serviceProvider, null),
                    IntervalTicks = attribute.IntervalTimeSpan.Ticks,
                    NextTick      = tick + attribute.IntervalTimeSpan.Ticks
                };

                _timers.Add(timer);
            }
        }
Esempio n. 3
0
        public ServerCommandData Wait(Func <ServerCommandData, bool> accept = null)
        {
            ServerCommandData value;

            lock (_backlog)
            {
                if (accept == null)
                {
                    if (_backlog.Count > 0)
                    {
                        value = _backlog[0];
                        _backlog.RemoveAt(0);// TODO: Improve O(n) performance
                        return(value);
                    }
                }
                else
                {
                    for (var i = 0; i < _backlog.Count; i++)
                    {
                        if (accept(_backlog[i]))
                        {
                            value = _backlog[i];
                            _backlog.RemoveAt(i);
                            return(value);
                        }
                    }
                }
            }

            for (;;)
            {
                // TODO: This is rather much of a workaround. It seems with certain timing the semaphore might stay in
                // TODO: the waiting state if it has been released too soon. In case that happens, the concurrent queue
                // TODO: will have the member added already.
                if (_asyncQueue.TryDequeue(out value))
                {
                    var ok = accept?.Invoke(value) ?? true;

                    if (ok)
                    {
                        return(value);
                    }

                    CoreLog.LogDebug("command added to backlog");
                    lock (_backlog)
                    {
                        _backlog.Add(value);
                        continue;
                    }
                }


                _semaphore.Wait();

                if (_asyncQueue.TryDequeue(out value))
                {
                    var ok = accept?.Invoke(value) ?? true;

                    if (ok)
                    {
                        return(value);
                    }

                    CoreLog.LogDebug("command added to backlog");
                    lock (_backlog)
                    {
                        _backlog.Add(value);
                    }
                }
            }
        }