/// <summary> /// Initializes a new instance of the <see cref="GameBuilder"/> class. /// </summary> public GameBuilder() { _commandBindings = new Dictionary <string, Type>(); ServerLog.LogInfo($"Game server {Assembly.GetCallingAssembly().GetName().Name} is now building..."); // Prime our game runner, and add to it as we construct the builder _game = new GameRunner(); }
/// <summary> /// Add a <see cref="SharperEntity"/> to the Sharper Universe. /// </summary> /// <returns>An <see cref="EntityBuilder"/>, for adding multiple <see cref="SharperEntity"/> or <see cref="BaseSharperComponent"/> to the Sharper Universe.</returns> public EntityBuilder AddEntity() { ServerLog.LogInfo("Creating new SharperEntity..."); _currentEntity = new SharperEntity(); _entities.Add(_currentEntity); return(this); }
/// <summary> /// Add a <see cref="IUniverseCommandInfo"/> to the <see cref="GameRunner"/>. /// </summary> /// <typeparam name="T">The type of <see cref="IUniverseCommandInfo"/> to add as a command binding.</typeparam> /// <param name="name">The name/identifier of this <see cref="IUniverseCommandInfo"/>.</param> /// <returns>An <see cref="IOHandlerBuilder"/>, for building the next phase of the Sharper Universe.</returns> public GameBuilder AddCommand <T>(string name) where T : IUniverseCommandInfo { ServerLog.LogInfo($"Adding command type {typeof(T).FullName} with assigned name of \"{name}\""); _commandBindings.Add(name, typeof(T)); return(this); }
/// <summary> /// Attach a <see cref="BaseSharperComponent"/> to the most previously created <see cref="SharperEntity"/>. /// </summary> /// <typeparam name="T">The type of <see cref="BaseSharperComponent"/> to attach to the previously created <see cref="SharperEntity"/>.</typeparam> /// <param name="args">Any parameters that your <see cref="BaseSharperComponent"/> takes in its constructor must be pased through this parameter.</param> /// <returns>An <see cref="EntityBuilder"/>, for adding multiple <see cref="SharperEntity"/> or <see cref="BaseSharperComponent"/> to the Sharper Universe.</returns> /// <remarks>Even if your <see cref="BaseSharperComponent"/> takes a <see cref="SharperEntity"/> as its first parameter, do not add it to the <paramref name="args"/> array. It is automatically provided for you. Only add parameters beyond the <see cref="SharperEntity"/> to <paramref name="args"/>.</remarks> public EntityBuilder WithComponent <T>(params object[] args) where T : BaseSharperComponent { ServerLog.LogInfo($"Attempting to add component to SharperEntity of type {typeof(T).FullName}"); foreach (var system in _game.Systems) { var componentToMatch = system.GetType().BaseType.GetGenericArguments().SingleOrDefault(c => c.ToString().Equals(typeof(T).ToString())); if (componentToMatch == null) { continue; } // POSSIBLE HACK - MIGHT ACTUALLY WORK OUT 100% OF THE TIME // If we're calling this, we're always going to attach it to the most recently created entity (from the builder pattern) // It's possible we could maybe improve this by forcing it to always follow the creation of an entity // TODO: Possible refactor var newArgsList = new List <object>(); newArgsList.Add(_currentEntity); foreach (var arg in args) { newArgsList.Add(arg); } var result = (T)Activator.CreateInstance(typeof(T), newArgsList.ToArray()); system.RegisterComponentAsync(result).GetAwaiter().GetResult(); break; } return(this); }
/// <summary> /// Signals that no more <see cref="ISharperSystem{T}"/> will be needed to build this Sharper Universe. /// </summary> /// <returns>An <see cref="EntityBuilder"/>, for building the next phase of the Sharper Universe.</returns> public EntityBuilder ComposeSystems() { // Loop through all requested systems - these are the systems that were requested by the builder config foreach (var systemBuilder in _systemBuilders) { List <object> systemParameters = new List <object>(); // Systems can depend on 2 types, a GameRunner, and another system // Loop through this particular system's constructor's parameters looking for those types // and instantiating them along the way foreach (var parameter in systemBuilder.GetParameters()) { systemParameters.Add(RegisterParameter(parameter)); } // Finally, register this top-level system into this builder's graph. _registeredSystemParameters.Add(systemBuilder.DeclaringType, systemBuilder.Invoke(systemParameters.ToArray())); } (_game.Systems.First(x => x is SharperInputSystem) as SharperInputSystem).CommandBindings = _commands; ServerLog.LogInfo("Systems attached."); return(new EntityBuilder(_game)); }
/// <summary> /// Add a <see cref="ISharperSystem{T}"/> to the <see cref="GameRunner"/>. /// </summary> /// <typeparam name="TSystem">The <see cref="ISharperSystem{T}"/> to add to the <see cref="GameRunner"/>.</typeparam> /// <returns>A <see cref="SystemBuilder"/>, for adding multiple sytsems to the Sharper Universe.</returns> public SystemBuilder AddSystem <TSystem>() where TSystem : ISharperSystem <BaseSharperComponent> { ServerLog.LogInfo($"Attaching system of type {typeof(TSystem).FullName}."); var systemConstructors = typeof(TSystem).GetConstructors(); foreach (var systemConstructor in systemConstructors) { foreach (var parameter in systemConstructor.GetParameters()) { if (parameter.ParameterType != typeof(GameRunner) && !typeof(BaseSharperSystem <>).IsSubclassOfRawGeneric(parameter.ParameterType)) { // Maybe we want to `break;` here? // For now, assume that if it's not a GameRunner or a system, then it's not supported. throw new InvalidOperationException( "Systems only support GameRunner and other systems as parameters."); } } _systemBuilders.Add(systemConstructor); break; } return(this); }
/// <summary> /// The main entry point for the application. /// </summary> static void Main(string[] args) { Config.AppName = typeof(Program).Assembly.GetName().Name; Config.AppName = typeof(Program).Assembly.GetName().Version.ToString(); Config.AdminUser = Config.GetSetting <string>("AdminUser", "Market"); Config.DefaultPrice = Config.GetSetting <double>("DefaultPrice", "1.00"); Config.DefaultVolume = Config.GetSetting <int>("DefaultVolume", "10000"); Config.Commission = Config.GetSetting <double>("Commission", "0.0"); User user = new User(Config.AdminUser, 0.0); MatchMeDB.Instance.AddUser(user); ServerLog.LogInfo("Starting {0} version: {1}", Config.AppName, Config.AppVersion); if (args.Length == 0) { ServerLog.LogInfo("Running MacheMe in service mode"); System.Diagnostics.Debugger.Launch(); System.ServiceProcess.ServiceBase.Run(new System.ServiceProcess.ServiceBase[] { new MatchMeService() }); } else if (args[0].ToUpper() == "DEBUG") { ServerLog.ConsoleLogMode = true; ServerLog.LogInfo("Running Match Me Server in debug mode"); ServerLog.LogInfo("Match Me version {0}", typeof(Program).Assembly.GetName().Version); MatchMeServer server = new MatchMeServer(); server.Start(); WaitForQ(); server.Stop(); } else { Console.WriteLine(@"Usage:DEBUG (run in console mode) (install service)"); } }
/// <summary> /// Signals that no more <see cref="SharperEntity"/> or <see cref="BaseSharperComponent"/> will be needed to build this Sharper Universe. /// </summary> /// <returns>An <see cref="EntityBuilder"/>, for adding multiple <see cref="SharperEntity"/> or <see cref="BaseSharperComponent"/> to the Sharper Universe.</returns> public EntityBuilder ComposeEntities() { ServerLog.LogInfo("Entities composed."); // TODO: Probably should add a bool class member to track whether this method has been called or not // If it has been called, then set the member to true, and check its true-ness in the other creation methods in this class // We return an EntityBuilder here for convenience, in-case they don't want to add an OptionsBuilder _game.Entities.AddRange(_entities); return(this); }
/// <summary> /// Initializes a new instance of the <see cref="SystemBuilder"/> class. /// </summary> /// <param name="game">The <see cref="GameRunner"/> being built by this <see cref="GameBuilder"/>.</param> internal SystemBuilder(GameRunner game, Dictionary <string, Type> commands) { _commands = commands; ServerLog.LogInfo("Now attempting to compose ISharperSystem types..."); _game = game; _systemBuilders = new List <ConstructorInfo>(); _registeredSystemParameters = new Dictionary <Type, object> { { typeof(GameRunner), _game } }; _systemBuilders.AddRange(typeof(SharperInputSystem).GetConstructors()); }
public void Disconnect() { if (!_socket.Connected) { return; } _socket.Shutdown(SocketShutdown.Both); _socket.Close(); ClientDisconnected?.Invoke(this, new ClientDisconnectedArgs(Id)); ServerLog.LogInfo($"client at {((IPEndPoint)_socket.RemoteEndPoint).Address} Disconnected from game server {Assembly.GetCallingAssembly().GetName().Name}."); }
public void Stop() { ServerLog.LogInfo("Stopping remaining tasks"); Task[] remainingTasks; lock (runningTasks) { stopping = true; remainingTasks = new Task[runningTasks.Count]; runningTasks.CopyTo(remainingTasks); } Task.WaitAll(remainingTasks); ServerLog.LogInfo("Stopping HTTP listener"); listener.Stop(); }
public void Start() { AppDomain.CurrentDomain.UnhandledException += (o, ea) => { if (ea.ExceptionObject is Exception) { ServerLog.LogException(ea.ExceptionObject as Exception, "Unhandled exception handler called"); } else { ServerLog.LogError("Unhandled exception handler called with unrecognized exception objhect"); } }; ServerLog.LogInfo("Starting MatchMe Host"); listener.Start(); listener.BeginGetContext(OnContext, null); }
private void OnClientConnect(IAsyncResult asyncResult) { // Stop accepting new connections and creat a specific connection for the client. var socket = _mainSocket.EndAccept(asyncResult); ISharperConnection connection = new Connection(socket); Connections.TryAdd(connection.Id, connection); connection.ClientDisconnected += ClientDisconnected; connection.ListenForData(); NewConnectionMade?.Invoke(this, new NewConnectionArgs(connection)); ServerLog.LogInfo($"Client {((IPEndPoint)socket.RemoteEndPoint).Address} now connected to server running {Assembly.GetCallingAssembly().GetName().Name}."); // Start accepting new connections again. _mainSocket.BeginAccept(OnClientConnect, null); }
/// <summary> /// Launches the Game. This task runs for as long as the game is running. /// </summary> /// <returns>A <see cref="Task"/> representing the asynchronous game loop.</returns> public async Task RunGameAsync() { var inputSystem = (SharperInputSystem)Systems.First(x => x is SharperInputSystem); Server.NewConnectionMade += inputSystem.OnNewInputConnectionAsync; ServerLog.LogInfo("Server launch successful."); while (!_cancellationTokenSource.IsCancellationRequested) { foreach (var sharperSystem in Systems) { await sharperSystem.CycleUpdateAsync(DeltaMs); var entitiesToDestroy = Entities.Where(x => x.ShouldDestroy).ToList(); for (var i = entitiesToDestroy.Count - 1; i > -1; i--) { var entity = entitiesToDestroy[i]; await sharperSystem.UnregisterAllComponentsByEntityAsync(entity); } } await inputSystem.CycleCommandFlushAsync(); await Task.Delay(DeltaMs); } }
public void ProcessTransactionRequest(TransactionRequest transactionRequest, IClient client, SafeDictionary <string, DataStore> dataStores) { if (transactionRequest.TransactionId == default) { client.SendResponse(new ExceptionResponse( new CacheException( "Transaction request received without transaction id"))); return; } // First try to acquire a write lock on all concerned data stores var types = transactionRequest.AllCollections; var keys = dataStores.Keys; if (types.Any(t => !keys.Contains(t))) { throw new NotSupportedException("Type not registered"); } var transactionId = transactionRequest.TransactionId; // do not work too hard if it's single stage if (transactionRequest.IsSingleStage) { ProcessSingleStageTransactionRequest(transactionRequest, client, dataStores); return; } var lockAcquired = _lockManager.TryAcquireWriteLock(transactionId, Constants.DelayForLockInMilliseconds, types.ToArray()); if (lockAcquired) { var answer = client.ShouldContinue(); if (answer.HasValue && answer.Value) { } else { _lockManager.CloseSession(transactionId); return; } } else { client.SendResponse(new ExceptionResponse( new CacheException( $"can not acquire write lock on server for transaction {transactionRequest.TransactionId}"), ExceptionType.FailedToAcquireLock)); return; } Dbg.Trace($"S: lock acquired by all clients for transaction {transactionRequest.TransactionId}"); // Second register a durable delayed transaction. It can be cancelled later try { CheckConditions(transactionRequest, dataStores); // if we reach here the condition check has passed SaveDurableTransaction(transactionRequest, dataStores); client.SendResponse(new ReadyResponse()); Dbg.Trace($"S: end writing delayed transaction {transactionRequest.TransactionId}"); } catch (CacheException e) { Dbg.Trace($"error in first stage:{e.Message} "); client.SendResponse(new ExceptionResponse(e, e.ExceptionType)); // failed to write a durable transaction so stop here // unlock _lockManager.CloseSession(transactionRequest.TransactionId); return; } catch (Exception e) { Dbg.Trace($"error in first stage:{e.Message} "); client.SendResponse(new ExceptionResponse(e)); // failed to write a durable transaction so stop here // unlock _lockManager.CloseSession(transactionRequest.TransactionId); return; } try { Dbg.Trace($"S: begin waiting for client go {transactionRequest.TransactionId}"); var answer = client.ShouldContinue(); Dbg.Trace($"S: end waiting for client go answer = {answer}"); if (answer.HasValue) // the client has answered { if (answer.Value) { // update the data in memory ExecuteInMemory(transactionRequest, dataStores); ServerLog.LogInfo( $"S: two stage transaction committed successfully {transactionRequest.TransactionId}"); } else { ServerLog.LogWarning( $"S: two stage transaction cancelled by client on server {transactionRequest.TransactionId}"); // cancel the delayed transaction _transactionLog?.CancelDelayedTransaction(); } } else // the client failed to answer in a reasonable delay (which is less than the delay to commit a delayed transaction ) { _transactionLog?.CancelDelayedTransaction(); } } catch (Exception e) { ServerLog.LogInfo($"error in the second stage of a transaction:{e.Message}"); } // unlock _lockManager.CloseSession(transactionRequest.TransactionId); }
/// <summary> /// Initializes a new instance of the <see cref="EntityBuilder"/> class. /// </summary> /// <param name="game">The <see cref="GameRunner"/> being built by this <see cref="GameBuilder"/>.</param> internal EntityBuilder(GameRunner game) { ServerLog.LogInfo("Composing initially predefined entities..."); _game = game; _entities = new List <SharperEntity>(); }
public SystemBuilder CreateSystem() { ServerLog.LogInfo("Beginning System composition..."); return(new SystemBuilder(_game, _commandBindings)); }
public OptionsBuilder RegisterServer(ISharperServer sharperServer) { ServerLog.LogInfo($"Using ISharperServer of type {sharperServer.GetType().FullName} as server mainframe."); _game.Server = sharperServer; return(new OptionsBuilder(_game)); }
public OptionsBuilder DefaultServer(int port) { ServerLog.LogInfo($"Using default telnet ISharperServer type as server mainframe."); _game.Server = new Server(port); return(new OptionsBuilder(_game)); }
protected override void OnStop() { server.Stop(); ServerLog.LogInfo("MatchMe Service Stopped"); }
public void Start() { _storage = Container != null ? new ReliableStorage(new ObjectProcessor(Container), WorkingDirectory) : new ReliableStorage(new NullObjectProcessor(), WorkingDirectory); ServerLog.LogInfo("start processing schema"); // Stage 1 load the schema and // register types (this will create an in-memory data store for each type) lock (_schemaSync) { Container?.LoadSchema(SchemaFilePath); Container?.LoadSequence(SequenceFilePath); } ServerLog.LogInfo("end processing schema"); ServerLog.LogInfo("start loading transaction log"); TransactionLog = new TransactionLog(WorkingDirectory); ServerLog.LogInfo("end loading transaction log"); // if there are pending transactions data needs to be loaded twice // first without processing the persistent objects; simply initializing offset tables // second after processing pending transactions reload and store objects in memory if (TransactionLog.PendingTransactionsCount > 0) { ServerLog.LogInfo("start loading data before transaction processing"); // load once without processing the objects _storage.LoadPersistentData(false); ServerLog.LogInfo("end loading data before transaction processing"); } // start the thread that will process pending transactions StartProcessingTransactions(); ServerLog.LogInfo("start waiting for pending transactions to be processed"); // Stage 2 wait for the persistence engine to commit all the pending transactions in the log // in the storage WaitForPendingTransactions(); ServerLog.LogInfo("end waiting for pending transactions"); // Stage 3 house keeping ServerLog.LogInfo("start compacting the transaction log"); TransactionLog.ClearLog(); ServerLog.LogInfo("end compacting the transaction log"); ServerLog.LogInfo("start compacting the persistence storage"); _storage.CleanStorage(); ServerLog.LogInfo("end compacting the persistence storage"); ServerLog.LogInfo("begin load data"); // Stage 4 load data from persisent storage to memory _storage.LoadPersistentData(); ServerLog.LogInfo("end load data"); }
/// <summary> /// Sets the delay between game loops within the Sharper Universe. /// </summary> /// <param name="ms">The delay between game loops.</param> /// <returns>An <see cref="OptionsBuilder"/>, for setting additional options on the <see cref="GameRunner"/>.</returns> public OptionsBuilder SetLoopDelay(int ms) { ServerLog.LogInfo($"Setting the delta time of the game loop at {ms} milliseconds."); _game.DeltaMs = ms; return(this); }
/// <summary> /// Initializes a new instance of the <see cref="OptionsBuilder"/> class. /// </summary> /// <param name="game">The <see cref="GameRunner"/> being built by this <see cref="GameBuilder"/>.</param> internal OptionsBuilder(GameRunner game) { ServerLog.LogInfo("Adjusting settings based on the following options..."); _game = game; }
private void OnContext(IAsyncResult ar) { DateTime reqStartTime = DateTime.Now; HttpListenerContext context; try { context = listener.EndGetContext(ar); } catch (HttpListenerException) { ServerLog.LogInfo("HttpListener has been shut down"); return; } if (!stopping) { listener.BeginGetContext(OnContext, null); } var processWebRequest = new Task(() => { System.Threading.Interlocked.Increment(ref totalRequests); byte[] json = null; int httpStatus = 200; string redirectUrl = null; string outContentType = "application/json"; try { string processor; string command; string jsonInput; string module; string contentType; string source; string agent; var args = ParseUrl(context.Request, out processor, out command, out jsonInput, out module, out contentType, out source, out agent); if (module == "test") { if (processor == "util") { if (command == "stats") { StatRespond(context, reqStartTime); } else if (command == "health") { HealthRespond(context, reqStartTime); } else { throw new ApplicationException(string.Format("Unknown util command: {0}", command)); } return; } } else if (module == "action") { string jsonString = actionProcessor.Execute(command, args, jsonInput, contentType, source, agent, out outContentType, out redirectUrl, out httpStatus); if (jsonString == null) { jsonString = ""; } json = Encoding.UTF8.GetBytes(jsonString); } else if (module == "db") { string jsonString = dataProcessor.Execute(command, args, jsonInput, contentType, source, agent, out outContentType, out redirectUrl, out httpStatus); if (jsonString == null) { jsonString = ""; } json = Encoding.UTF8.GetBytes(jsonString); } else { throw new ApplicationException(string.Format("Unknown module: {0}", module)); } } catch (Exception e) { ExceptionRespond(context, e, 500, reqStartTime); return; } if (redirectUrl != null) { RespondRedirect(context, redirectUrl); } else { Respond(context, json, httpStatus, reqStartTime, outContentType); } }); lock (runningTasks) { if (stopping) { Respond(context, serverCharSet.GetBytes("MatchMe is shutting down.") , 500, reqStartTime); return; } runningTasks.Add(processWebRequest); } processWebRequest.ContinueWith(t => { lock (runningTasks) { runningTasks.Remove(t); } if (t.IsFaulted) { ServerLog.LogException(t.Exception.InnerException, "Exception was unhandled in task"); } }); processWebRequest.Start(); }
public NetworkBuilder(GameRunner game) { ServerLog.LogInfo("Now composing defined network behaviour..."); _game = game; }
public string AddCompany(string Symbol, string Volume, string Price) { if (!MatchMeDB.Instance.UserTable.ContainsKey(Config.AdminUser)) { User user = new User(Config.AdminUser, 0.0); MatchMeDB.Instance.AddUser(user); } string message = string.Empty; double price = Config.DefaultPrice; int volume = Config.DefaultVolume; string userId = MatchMeDB.Instance.GetUserId(Config.AdminUser); var status = enumStatus.Unknown; enumOrderType ordertype; enumSide orderside; try { Symbol = Symbol.ToUpper(); if (string.IsNullOrEmpty(Price) || !double.TryParse(Price, out price)) { ServerLog.LogInfo(message); } if (string.IsNullOrEmpty(message) && (string.IsNullOrEmpty(Volume) || !int.TryParse(Volume, out volume))) { ServerLog.LogInfo(message); } List <Order> companies = MatchMeDB.Instance.OrderTable.ContainsKey(userId) ? MatchMeDB.Instance.OrderTable[userId] : new List <Order>(); foreach (Order company in companies) { if (company.Symbol.Equals(Symbol)) { message = string.Format("Error: duplicate company. Existing User: {0} New Company Symbol (rejected): {1}", company, Symbol); status = enumStatus.CompanyAddFailed; } } ordertype = enumOrderType.Market; orderside = enumSide.Sell; price = -Math.Abs(price); Order newOrder = new Order(Symbol, volume, price, userId, ordertype, orderside); if (string.IsNullOrEmpty(message) && Exchange.Instance.PlaceSell(newOrder, true).Equals(enumStatus.OrderPlaced)) { Position position = MatchMeDB.Instance.GetPosition(userId, Symbol); position.Quantity = volume; MatchMeDB.Instance.UpdatePosition(position); message = string.Format("Company Created: {0}, Volume: {1}, Price: {2}", newOrder.Symbol, newOrder.Volume, newOrder.Price); status = enumStatus.CompanyAdded; } } catch (Exception ex) { ServerLog.LogException(ex, string.Format("Add Company, Symbol {0}, Volume {1}, Price", Symbol, Volume, price.ToString())); message = ex.Message; status = enumStatus.CompanyAddFailed; } var result = new Dictionary <string, string> { { "status", status.ToString() }, { "message", message } }; return(JsonConvert.SerializeObject(result)); }
/// <summary> /// Signals that no more <see cref="ISharperSystem{T}"/> will be needed to build this Sharper Universe. /// </summary> /// <returns>An <see cref="EntityBuilder"/>, for building the next phase of the Sharper Universe.</returns> public EntityBuilder ComposeSystems() { // Loop through all requested systems - these are the systems that were requested by the builder config foreach (var systemBuilder in _systemBuilders) { List <object> systemParameters = new List <object>(); // Systems can depend on 2 types, a GameRunner, and another system // Loop through this particular system's constructor's parameters looking for those types // and instantiating them along the way foreach (var parameter in systemBuilder.GetParameters()) { if (_registeredSystemParameters.TryGetValue(parameter.ParameterType, out var parameterInstance)) { // We've already registered this type, so simply retrieve its registered instance and use it systemParameters.Add(parameterInstance); } else { // This type hasn't been registered yet, so recursively look through its // dependencies and grab/register them as needed var composedSystem = ComposeSystem(parameter.ParameterType); if (composedSystem != null) { systemParameters.Add(composedSystem); } } } // Finally, register this top-level system into this builder's graph. _registeredSystemParameters.Add(systemBuilder.DeclaringType, systemBuilder.Invoke(systemParameters.ToArray())); } (_game.Systems.First(x => x is SharperInputSystem) as SharperInputSystem).CommandBindings = _commands; ServerLog.LogInfo("Systems attached."); return(new EntityBuilder(_game)); // Local method - recursively called to build dependency graph object ComposeSystem(Type type) { // If we're not GameRunner or a system, then get out of here // We may want to consider throwing InvalidOperationException here? if (type != typeof(GameRunner) && !typeof(BaseSharperSystem <>).IsSubclassOfRawGeneric(type)) { return(null); } object instance = null; // Recursively look through this dependency, registering any new systems we come across // and re-using systems/gamerunners we've already registered along the way foreach (var ctor in type.GetConstructors()) { List <object> systemParameters = new List <object>(); foreach (var parameter in ctor.GetParameters()) { if (_registeredSystemParameters.TryGetValue(parameter.ParameterType, out var parameterInstance)) { systemParameters.Add(parameterInstance); } else { systemParameters.Add(ComposeSystem(parameter.ParameterType)); } } // Instantiates this system's constructor, implicitly registering itself to the GameRunner // and caching off its instance for use as a parent system's constructor parameter instance = ctor.Invoke(systemParameters.ToArray()); } _registeredSystemParameters.Add(type, instance); return(instance); } }
/// <summary> /// Starts a Sharper Universe game. /// </summary> /// <returns>A <see cref="Task"/> representing this <see cref="GameRunner"/> execution.</returns> public async Task StartGameAsync() { ServerLog.LogInfo("Game server now launching..."); _game.Server.Start(); await _game.RunGameAsync(); }
protected override void OnStart(string[] args) { server = new MatchMeServer(); server.Start(); ServerLog.LogInfo("MatchMe Service Started"); }