/// <summary> /// Abathur client is used to set up the Abathur framework. /// </summary> /// <param name="setupSettings">File containing list of modules Abathur should include</param> /// <param name="gameSettings">Settings for setting up the game with the StarCraft II client</param> /// <param name="essence">File containing data that is subject to change due to patches</param> /// <param name="log">Optional logging, will be used be the entire framework</param> public AbathurClient(AbathurSetup setupSettings, GameSettings gameSettings, Essence essence, ILogger log = null) { this.setupSettings = setupSettings; this.gameSettings = gameSettings; this.essence = essence; this.log = log; }
/// <summary> /// Run the Abathur framework with the settings specified in the data directory. /// </summary> /// <param name="dataPath">The absolute path for a directory where Abathur may place setting files</param> /// <param name="logPath">The absolute directory path for log files, no log files will be generated if left empty</param> public void Run(string dataPath, string logPath = null) { // ConsoleLogger prints in pretty colors... ILogger log = ConsoleLogger.Instance; // Check that the directory exist, or create it. log?.LogMessage("Checking data directory:"); FileService.ValidateOrCreateDirectory(dataPath, log); // Check that the game settings file exist, or create it a default template. log?.LogMessage("Checking game settings file:"); FileService.ValidateOrCreateJsonFile(dataPath + "gamesettings.json", Defaults.GameSettings, log); GameSettings gameSettings = FileService.ReadFromJson <GameSettings>(dataPath + "gamesettings.json", log); // Load the Abathur setup file, this file is used to add/remove modules to the framework log?.LogMessage("Checking setup file:"); FileService.ValidateOrCreateJsonFile(dataPath + "setup.json", Defaults.AbathurSetup, log); AbathurSetup abathurSetup = FileService.ReadFromJson <AbathurSetup>(dataPath + "setup.json", log); // Load or create the 'essence file' - a file containing UnitTypeData, AbilityTypeData, BuffData, UpgradeData and manually coded tech-trees for each race. var essence = EssenceService.LoadOrCreate(dataPath, log); // If a log path have been specified, check the directory and change add a filelogger (writes to files) if (logPath != null) { log?.LogMessage("Checking log directory:"); FileService.ValidateOrCreateDirectory(logPath, log); log = new MultiLogger(ConsoleLogger.Instance, new FileLogger(logPath, "abathur")); } // Check if gamesettings specify more than one participant (1 = Participant, 2 = Computer, 3 = Observer (not implemented)) IClient player1 = null; IClient player2 = null; player1 = new AbathurClient(abathurSetup, gameSettings, essence, log); if (gameSettings.IsMultiplayer()) { player2 = new AbathurClient(abathurSetup, gameSettings, essence, log); } // Start the game already! var game = new Game(gameSettings, player1, player2); game.ExecuteMatch(); }
/// <summary> /// Method for configuring the Abathur Framework using depedency injecting and reflection. /// </summary> /// <param name="essence">Patch-dependent Starcraft II data</param> /// <param name="gameSettings">Settings used for launching the StarCraft II client</param> /// <param name="log">Optional logger - useful for test and debug purposes</param> /// <param name="setup">Should contain the name of all modules the framework should launch with</param> /// <returns></returns> public static IAbathur Configure(Essence essence, GameSettings gameSettings, AbathurSetup setup, ILogger log = null) { if (log == null) { log = new MultiLogger(); // Give a 'decoy' logger to prevent null pointer exceptions if people rely on the log. } externalStrings = new Queue <string>(); var sp = ConfigureServices(essence, gameSettings, setup, log); var abathur = (Abathur.Abathur)sp.GetService <IAbathur>(); abathur.IsParallelized = setup.IsParallelized; abathur.Modules = sp.GetServices <IModule>().ToList(); // Setup external modules with commands. foreach (var m in abathur.Modules) { if (m is ExternalModule) { ((ExternalModule)m).Command = externalStrings.Dequeue(); } } return(abathur); }
/// <summary> /// Special service provider for the Abathur framework utilizing reflection to configurate setup without recompiling. /// </summary> /// <param name="essence">Patch-dependent Starcraft II data</param> /// <param name="gameSettings">Settings used for launching the StarCraft II client</param> /// <param name="log">Optional logger - useful for test and debug purposes</param> /// <param name="setup">Should contain the name of all modules the framework should launch with</param> /// <returns></returns> private static IServiceProvider ConfigureServices(Essence essence, GameSettings gameSettings, AbathurSetup setup, ILogger log) { var collection = new ServiceCollection(); // Add settings, data and logger. collection.AddSingleton(essence); collection.AddSingleton(gameSettings); collection.AddSingleton(log); // Add Abathur core modules collection.AddSingleton <IGameClient, GameClient>(); collection.AddSingleton <IIntelManager, IntelManager>(); collection.AddSingleton <IRawManager, RawManager>(); collection.AddSingleton <IProductionManager, ProductionManager>(); collection.AddSingleton <ICombatManager, CombatManager>(); collection.AddSingleton <ISquadRepository, CombatManager>(); collection.AddSingleton <IGameMap, GameMap>(); collection.AddSingleton <ITechTree, TechTree>(); // Add Abathur data repositories collection.AddSingleton <DataRepository, DataRepository>(); collection.AddSingleton <IUnitTypeRepository>(x => x.GetService <DataRepository>()); collection.AddSingleton <IUpgradeRepository>(x => x.GetService <DataRepository>()); collection.AddSingleton <IBuffRepository>(x => x.GetService <DataRepository>()); collection.AddSingleton <IAbilityRepository>(x => x.GetService <DataRepository>()); // Add services used for external modules (Python) collection.AddSingleton <IRawManagerService, RawManagerService>(); collection.AddSingleton <IProductionManagerService, ProductionManagerService>(); collection.AddSingleton <ICombatManagerService, CombatManagerService>(); collection.AddSingleton <IIntelManagerService, IntelManagerService>(); // Add all modules inheriting from IReplaceableModule, allowing any module to access them through their constructor foreach (var type in GetAllImplementations <IReplaceableModule>()) { collection.AddSingleton(type, type); } // Add class that inherits from IModule and is mentioned in the setup file #if DEBUG if (setup.Modules.Count == 0) { log?.LogWarning($"\tLauncher: Running without ANY modules."); } #endif foreach (string launchString in setup.Modules) { if (GetType <IModule>(launchString, out var implementationType)) { collection.AddSingleton(typeof(IModule), implementationType); #if DEBUG log?.LogSuccess($"\tLauncher: {launchString} resolved to a valid class."); #endif } else { // Assume the file mentioned in the setup file is a command for setting up an external module collection.AddSingleton <IModule, ExternalModule>(); externalStrings.Enqueue(launchString); #if DEBUG log?.LogWarning($"\tLauncher: [EXTERNAL] {launchString}"); #endif } } // Add Abathur! collection.AddScoped <IAbathur, Abathur.Abathur>(); return(collection.BuildServiceProvider()); }