Skip to content

Conversation

@ELDment
Copy link
Contributor

@ELDment ELDment commented Sep 25, 2025

Description

This pull request implements the AddTimer method in the ISchedulerService interface and fixes dependency injection issues in the plugin system. The changes enable plugins to use a simplified timer API and resolve runtime configuration generation for .NET hosting.

Type of Change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Code refactoring (no functional changes)
  • Performance improvement
  • Test coverage improvement
  • Build/CI improvement

Related Issues

Related to plugin timer functionality and dependency injection issues.

Changes Made

  • Native changes (C++)
  • Managed Changes (C#)
  • API additions/modifications
  • Memory management improvements
  • Network handling changes
  • SDK updates
  • Build system changes

Detailed Changes

List the specific changes made:

  • Added AddTimer(int delayTick, Action task) method to ISchedulerService interface
  • Implemented AddTimer method in SchedulerService class with proper timer lifecycle management
  • Fixed dependency injection registration for EventSubscriber as IEventSubscriber interface
  • Added GenerateRuntimeConfigurationFiles to project configuration for proper .NET runtime config generation

Testing

Test Environment

  • OS: Windows 11
  • Game: Counter-Strike 2

Test Cases

Describe the test cases you've run:

  1. Plugin timer creation using Core.Scheduler.AddTimer(10, () => {...})
  2. Dependency injection resolution for scheduler services
  3. Runtime configuration file generation during build process

Breaking Changes

List any breaking changes and migration steps:

  • None - all changes are backward compatible

Performance Impact

  • No performance impact
  • Positive performance impact
  • Negative performance impact (explain below)
  • Performance impact unknown

Details: The changes only add new functionality without modifying existing timer mechanisms.

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

Screenshots/Videos (if applicable)

image Error occurred when trying to compile TestPlugin.cs: image (error CS1061: 'ISchedulerService' does not contain a definition for 'AddTimer' and no accessible extension method 'AddTimer' accepting a first argument of type 'ISchedulerService' could be found (are you missing a using directive or an assembly reference?))
image image

Additional Notes

  • The AddTimer method provides a simplified interface for one-time delayed execution timers
  • Fixed circular dependency issue where SchedulerService required IEventSubscriber but registration was incomplete
  • Build configuration now properly generates SwiftlyS2.runtimeconfig.json required for .NET hosting

For Maintainers

  • Code review completed
  • Tests pass
  • Ready to merge

@ELDment
Copy link
Contributor Author

ELDment commented Sep 25, 2025

Closing because the scheduler functionality is still work in progress

@ELDment ELDment closed this Sep 25, 2025
@ELDment
Copy link
Contributor Author

ELDment commented Sep 25, 2025

System.InvalidOperationException: Unable to resolve service for type 'SwiftlyS2.Shared.Events.IEventSubscriber' while
attempting to activate 'SwiftlyS2.Core.Scheduler.SchedulerService'.
  at ServiceCallSite[[]] Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(
     ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[]
     parameters, bool throwIfCallSiteNotFound)
  at ConstructorCallSite Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.
     CreateConstructorCallSite(ResultCache lifetime, ServiceIdentifier serviceIdentifier, Type implementationType,
     CallSiteChain callSiteChain)
  at ServiceCallSite Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateExact(
     ServiceDescriptor descriptor, ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain, int slot)
  at ServiceCallSite Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(
     ServiceDescriptor descriptor, ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain, int slot)
  at ServiceCallSite Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(
     ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain)
  at ServiceCallSite Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(
     ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain)
  at ServiceCallSite Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.GetCallSite(
     ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain)
  at ServiceAccessor Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(ServiceIdentifier
     serviceIdentifier)
  at TValue System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func<TKey, TValue> valueFactory)
  at object Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(ServiceIdentifier serviceIdentifier,
     ServiceProviderEngineScope serviceProviderEngineScope)
  at object Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType)
  at object Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(
     IServiceProvider provider, Type serviceType)
  at T Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService<T>(IServiceProvider
     provider)
  at SwiftlyS2.Core.Services.SwiftlyCore..ctor(string contextId, string contextBaseDirectory, Type contextType,
     IServiceProvider coreProvider) in D:\Github\swiftlys2\managed\src\SwiftlyS2.Core\Modules\Plugins\SwiftlyCore.cs:103
  at PluginContext SwiftlyS2.Core.Plugins.PluginManager.LoadPlugin(string dir) in
     D:\Github\swiftlys2\managed\src\SwiftlyS2.Core\Modules\Plugins\PluginManager.cs:163
  at void SwiftlyS2.Core.Plugins.PluginManager.LoadPlugins() in
     D:\Github\swiftlys2\managed\src\SwiftlyS2.Core\Modules\Plugins\PluginManager.cs:75
System.InvalidOperationException: Unable to resolve service for type 'SwiftlyS2.Shared.Events.IEventSubscriber' while
attempting to activate 'SwiftlyS2.Core.Scheduler.SchedulerService'.
  at ServiceCallSite[[]] Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(
     ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[]
     parameters, bool throwIfCallSiteNotFound)
  at ConstructorCallSite Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.
     CreateConstructorCallSite(ResultCache lifetime, ServiceIdentifier serviceIdentifier, Type implementationType,
     CallSiteChain callSiteChain)
  at ServiceCallSite Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateExact(
     ServiceDescriptor descriptor, ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain, int slot)
  at ServiceCallSite Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(
     ServiceDescriptor descriptor, ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain, int slot)
  at ServiceCallSite Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(
     ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain)
  at ServiceCallSite Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(
     ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain)
  at ServiceCallSite Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.GetCallSite(
     ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain)
  at ServiceAccessor Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(ServiceIdentifier
     serviceIdentifier)
  at TValue System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func<TKey, TValue> valueFactory)
  at object Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(ServiceIdentifier serviceIdentifier,
     ServiceProviderEngineScope serviceProviderEngineScope)
  at object Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType)
  at object Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(
     IServiceProvider provider, Type serviceType)
  at T Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService<T>(IServiceProvider
     provider)
  at SwiftlyS2.Core.Services.SwiftlyCore..ctor(string contextId, string contextBaseDirectory, Type contextType,
     IServiceProvider coreProvider) in D:\Github\swiftlys2\managed\src\SwiftlyS2.Core\Modules\Plugins\SwiftlyCore.cs:103
  at SwiftlyCore SwiftlyS2.Core.Bootstrap.<>c__DisplayClass0_0.<Start>b__0(IServiceProvider provider) in
     D:\Github\swiftlys2\managed\src\SwiftlyS2.Core\Bootstrap.cs:34
  at object Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite
     factoryCallSite, RuntimeResolverContext context)
  at TResult Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite
     callSite, TArgument argument)
  at object Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(
     ServiceCallSite callSite, RuntimeResolverContext context)
  at TResult Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite
     callSite, TArgument argument)
  at object Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(
     ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
  at TResult Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite
     callSite, TArgument argument)
  at object Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(
     ServiceCallSite callSite, RuntimeResolverContext context)
  at TResult Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite
     callSite, TArgument argument)
  at object Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite
     callSite, ServiceProviderEngineScope scope)
  at ServiceAccessor Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(ServiceIdentifier
     serviceIdentifier)
  at TValue System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func<TKey, TValue> valueFactory)
  at object Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(ServiceIdentifier serviceIdentifier,
     ServiceProviderEngineScope serviceProviderEngineScope)
  at object Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType)
  at object Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(
     IServiceProvider provider, Type serviceType)
  at T Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService<T>(IServiceProvider
     provider)
  at void SwiftlyS2.Core.Hosting.TestServiceInjection.UseTestService(IServiceProvider self) in
     D:\Github\swiftlys2\managed\src\SwiftlyS2.Core\Hosting\TestServiceInjection.cs:15
  at void SwiftlyS2.Core.Bootstrap.Start(IntPtr nativeTable, int nativeTableSize, string basePath) in
     D:\Github\swiftlys2\managed\src\SwiftlyS2.Core\Bootstrap.cs:44
  at void SwiftlyS2.Entrypoint.Start(IntPtr nativeTable, int nativeTableSize, IntPtr basePath) in
     D:\Github\swiftlys2\managed\src\Entrypoint.cs:15
PixPin_2025-09-25_18-31-25

@skuzzis
IDK why only I encounter this runtime error (SamyycX confirmed he don't have this issue)
Logically speaking, we indeed should register EventSubscriber as an interface implementation of IEventSubscriber

https://github.com/ELDment/swiftlys2/blob/d99c906427cfdd617d84bf13ad575fc1a7a44382/managed/src/SwiftlyS2.Core/Modules/Plugins/SwiftlyCore.cs#L68-L69

@skuzzis
Copy link
Member

skuzzis commented Sep 25, 2025

Logically yeah, but i'm not receiving that error either, which is strange.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants