internal ModEntityData()
 {
     directoryHelper = new StellarisDirectoryHelper("null");
     previous        = null;
     entities        = new Dictionary <string, T>();
     Links           = new HashSet <Link>();
 }
 public ModEntityData(StellarisDirectoryHelper directoryHelper, ModEntityData <T> previous = null)
 {
     this.directoryHelper = directoryHelper;
     this.previous        = previous;
     entities             = new Dictionary <string, T>();
     Links = new HashSet <Link>();
 }
 private ModEntityData(StellarisDirectoryHelper directoryHelper, ModEntityData <T> previous, Dictionary <string, T> entities, ISet <Link> links)
 {
     this.directoryHelper = directoryHelper;
     this.previous        = previous;
     this.entities        = entities;
     Links = links;
 }
Example #4
0
 public TechTreeGraphCreator(ILocalisationApiHelper localisationApiHelper, ICWParserHelper cwParserHelper,
                             StellarisDirectoryHelper stellarisDirectoryHelper, IEnumerable <StellarisDirectoryHelper> modDirectoryHelpers) : base(localisationApiHelper, cwParserHelper)
 {
     this.stellarisDirectoryHelper = stellarisDirectoryHelper;
     this.modDirectoryHelpers      = modDirectoryHelpers;
     IgnoreFiles = new List <string>();
     IgnoreFiles.AddRange(new [] { "00_tier.txt", "00_category.txt", "eac_category.txt" });
 }
        public ModEntityData <T> ProcessDirectoryHelper(ModEntityData <T> previous, StellarisDirectoryHelper directoryHelper, ModEntityData <Tech> techs)
        {
            var directoryPath = GetDirectory(directoryHelper);

            if (Directory.Exists(directoryPath))
            {
                var result    = new ModEntityData <T>(directoryHelper, previous);
                var techFiles = DirectoryWalker.FindFilesInDirectoryTree(directoryPath, ParseFileMask, IgnoreFiles);
                Log.Logger.Debug("Directory {directory} produced files {files}", directoryPath, techFiles);
                var parsedTechFiles = CWParserHelper.ParseParadoxFiles(techFiles.Select(x => x.FullName).ToList(), true);
                foreach (var(file, cwNode) in parsedTechFiles)
                {
                    Log.Logger.Debug("Processing file {file}", file);
                    // top level nodes are files, so we process the immediate children of each file, which is the individual techs.
                    foreach (var node in cwNode.Nodes)
                    {
                        try {
                            var entity = Construct(node);
                            Initialise(entity, file, directoryHelper.ModName, directoryHelper.ModGroup, node);
                            SetVariables(entity, node);
                            if (ShouldInclude(entity))
                            {
                                result[entity.Id] = entity;
                            }
                            else
                            {
                                Log.Logger.Debug("File {file} contained node {key} was processed, but failed the include filter so is discarded", file, entity.Id);
                            }
                        }
                        catch (Exception e) {
                            if (AbortOnFailure)
                            {
                                throw new Exception($"Error Processing node {node.Key} in file: {file}", e);
                            }
                            Log.Logger.Error(e, "Error Processing node {node} in file: {file}", node.Key, file);
                        }
                    }
                }

                // special case for managing techs
                // techs are their own tech lookup.
                var latestTechData = result as ModEntityData <Tech>;
                if (latestTechData != null)
                {
                    AddLinks(result, latestTechData);
                }
                else
                {
                    AddLinks(result, techs);
                }

                return(result);
            }
            Log.Logger.Debug("{mod} did not have {directory}", directoryHelper.ModName, directoryPath.Replace(directoryHelper.Root, ""));
            return(previous);
        }
        private void CopyMainImages(IEnumerable <Entity> entities, string inputPath, string outputPath)
        {
            //build the mod input list
            var inputDirectories = StellarisDirectoryHelper
                                   .CreateCombinedList(StellarisDirectoryHelper, modDirectoryHelpers, Last)
                                   .Select(x => Path.Combine(x.Icons, inputPath)).ToList();

            // tech images
            ImageOutput.TransformAndOutputImages(inputDirectories, Path.Combine(outputRoot, outputPath), entities);
        }
Example #7
0
 public DependantsGraphCreator(ILocalisationApiHelper localisationApiHelper, ICWParserHelper cwParserHelper,
                               StellarisDirectoryHelper stellarisDirectoryHelper, IEnumerable <StellarisDirectoryHelper> modDirectoryHelpers,
                               ModEntityData <Tech> techsAndDependencies)
 {
     this.localisationApiHelper    = localisationApiHelper;
     this.cwParserHelper           = cwParserHelper;
     this.stellarisDirectoryHelper = stellarisDirectoryHelper;
     this.modDirectoryHelpers      = modDirectoryHelpers;
     this.techsAndDependencies     = techsAndDependencies;
 }
Example #8
0
        private ModEntityData <T> CreateDependant <T>(EntityCreator <T> creator, ParseTarget parseTarget) where T : Entity
        {
            ModEntityData <T> entities = null;

            foreach (var modDirectoryHelper in StellarisDirectoryHelper.CreateCombinedList(stellarisDirectoryHelper, modDirectoryHelpers))
            {
                entities = creator.ProcessDirectoryHelper(entities, modDirectoryHelper, techsAndDependencies);
            }

            return(entities);
        }
        /// <summary>
        /// Will initalise optional values to sensible defaults.
        /// </summary>
        /// <param name="stellarisRoot"></param>
        /// <param name="outputRoot"></param>
        public TechTreeCreatorManager(string stellarisRoot, string outputRoot)
        {
            this.outputRoot = outputRoot;
            //Support UTF-8
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
            Language = STLLang.English;

            OutputDirectoryHelper = new OutputDirectoryHelper(outputRoot);

            // setup parser
            // Include extra pie! Especially for Piebadger.
            StellarisDirectoryHelper = new StellarisDirectoryHelper(stellarisRoot);

            CopyImages = true;
        }
Example #10
0
        public ModEntityData <Tech> CreateTechnologyGraph()
        {
            ModEntityData <Tech> techs = null;

            foreach (var modDirectoryHelper in StellarisDirectoryHelper.CreateCombinedList(stellarisDirectoryHelper, modDirectoryHelpers))
            {
                techs = ProcessDirectoryHelper(techs, modDirectoryHelper, null);
            }

            // post process because while most things work on the principle of:
            // later mod override core
            // later mod override core
            // core
            // some have the core first, then additional features that depend on it (Zenith, I am looking at you)
            // so need to post process

            techs?.ApplyToChain((modTechs, modLinks) => {
                foreach (var(key, tech) in modTechs)
                {
                    if (tech.Prerequisites.Count == tech.PrerequisiteIds.Count())
                    {
                        continue;
                    }

                    Log.Logger.Debug("Tech {id} had missing pre-requisite, trying to find it in the complete listing", key);
                    var populatedPreReqs = tech.Prerequisites.Select(preReq => preReq.Id).ToHashSet();
                    foreach (var missingPreReq in tech.PrerequisiteIds.Where(x => !populatedPreReqs.Contains(x)))
                    {
                        if (techs.ContainsEntityInTree(missingPreReq))
                        {
                            Tech attemptToFindPreq = techs[missingPreReq];
                            tech.Prerequisites.Add(attemptToFindPreq);
                            modLinks.Add(new Link()
                            {
                                From = attemptToFindPreq, To = tech
                            });
                            Log.Logger.Debug("Found prereq {key} in file {file}", attemptToFindPreq.Id, attemptToFindPreq.FilePath);
                        }
                        else
                        {
                            Log.Logger.Debug("Still unable to find {prereqId} for Tech {id}", missingPreReq, key);
                        }
                    }
                }
            });

            return(techs);
        }
Example #11
0
 public LocalisationApiHelper(StellarisDirectoryHelper stellarisDirectoryHelper,
                              IEnumerable <StellarisDirectoryHelper> modDirectoryHelpers,
                              STLLang language)
 {
     //When using the ILocalisationAp for a specific language, the key thing being used is the Values property,
     //which is a raw dictionary of keys to text values.
     localisation = new Dictionary <string, string>();
     foreach (var directoryHelper in StellarisDirectoryHelper.CreateCombinedList(stellarisDirectoryHelper, modDirectoryHelpers))
     {
         if (Directory.Exists(directoryHelper.Localisation))
         {
             var localisationService =
                 new STLLocalisation.STLLocalisationService(new LocalisationSettings(directoryHelper.Localisation));
             var values = localisationService.Api(Lang.NewSTL(language)).Values;
             localisation.PutAll(values);
         }
         else
         {
             Log.Logger.Debug("{name} has no localisation files", directoryHelper.ModName);
         }
     }
 }
        internal ScriptedVariableAccessor(StellarisDirectoryHelper stellarisDirectoryHelper,
                                          IEnumerable <StellarisDirectoryHelper> modDirectoryHelpers,
                                          IDirectoryWalker directoryWalker,
                                          ICWParserHelper cwParserHelper)
        {
            DirectoryWalker = directoryWalker;
            CWParserHelper  = cwParserHelper;

            variables = new Dictionary <string, string>();
            foreach (var directoryHelper in StellarisDirectoryHelper.CreateCombinedList(stellarisDirectoryHelper, modDirectoryHelpers))
            {
                if (Directory.Exists(directoryHelper.ScriptedVariables))
                {
                    var modVariables = ParseScriptedVariables(directoryHelper.ScriptedVariables);
                    variables.PutAll(modVariables);
                }
                else
                {
                    Log.Logger.Debug("{0} does not contain scripted variables", directoryHelper.ModName);
                }
            }
        }
        private void CopyCategoryImages(string techOutputDir)
        {
            var categoryDir = Path.Combine(techOutputDir, "categories");

            Directory.CreateDirectory(categoryDir);

            var helpers = StellarisDirectoryHelper
                          .CreateCombinedList(StellarisDirectoryHelper, modDirectoryHelpers);

            foreach (var helper in helpers)
            {
                List <FileInfo> categoryFiles = new List <FileInfo>();
                var             catPath       = Path.Combine(helper.Technology, "category");
                if (Directory.Exists(catPath))
                {
                    List <FileInfo> findFilesInDirectoryTree = DirectoryWalker.FindFilesInDirectoryTree(catPath, StellarisDirectoryHelper.TextMask);
                    Log.Logger.Debug("{helper} has categories files: {modFiles}", helper.ModName, findFilesInDirectoryTree.Select(x => x.Name));
                    categoryFiles.AddRange(findFilesInDirectoryTree);
                }
                else
                {
                    Log.Logger.Debug("{helper} has no tech categories folder", helper.ModName);
                }

                var categoryFileNodes = new CWParserHelper().ParseParadoxFiles(categoryFiles.Select(x => x.FullName).ToList());
                foreach (CWNode fileNode in categoryFileNodes.Values)
                {
                    foreach (var category in fileNode.Nodes)
                    {
                        var catName   = category.Key;
                        var imagePath = category.GetKeyValue("icon") ?? category.Key;

                        ImageOutput.TransformAndOutputImage(Path.Combine(helper.Root, imagePath),
                                                            Path.Combine(categoryDir, catName + ".png"));
                    }
                    ;
                }
            }
        }
Example #14
0
 protected override string GetDirectory(StellarisDirectoryHelper directoryHelper)
 {
     return(directoryHelper.Decisions);
 }
 protected abstract string GetDirectory(StellarisDirectoryHelper directoryHelper);
Example #16
0
 public LocalisationApiHelper(StellarisDirectoryHelper stellarisDirectoryHelper, STLLang language) : this(stellarisDirectoryHelper,
                                                                                                          new StellarisDirectoryHelper[] { }, language)
 {
 }
Example #17
0
        /// <summary>
        /// Example of using the helpers to parse tech files.
        /// </summary>
        /// <param name="stellarisRoot">The root directory to Stellaris</param>
        /// <param name="modRoots">The root directory of any mods you also wish to use.  The mod list will be processed in the same way Stellaris would, with earlier mods in the list overriding later ones.  (Conflict resolution: first-in wins), thus suggest you use an ordered collection!</param>
        public static void Example(string stellarisRoot, string stellarisUserDirectory, string modConfigFilePath)
        {
            // Setting up mods
            // if you don't want mods, you can skip all this to the "ending mods" comment
            // These Steps will show you the steps you need to take to work with mods that you have installed in stellaris with a minimum amount of boilerplate.
            // There are several steps, where you will do different ones on different runs of the code

            // First: Get all mods you are using in Stellaris and write out to a file that can be easily edited.

            // Open that file in your favourite text editor and review the mods it has found
            // Set the "include" property to true for all the mods you want to parse
            // For mods that are sensible to group together (E.g. the various mods in the At War series or Zenith of Fallen Empires) set a mod group so they will get processed together.

            // Last step: run the program again, loading that file from disk and making the mod definitions.


            // Locate your mods.
            // These are all the mods configured in the Stellaris Launcher
            IList <ModDefinitionFile> stellarisModDefinitions = ModDirectoryHelper.LoadModDefinitions(stellarisUserDirectory);

            // Write a config file that you can edit.
            ModDirectoryHelper.WriteModInfoFile(modConfigFilePath, stellarisModDefinitions);

            // FIRST RUN: STOP HERE!  GO EDIT THE FILE YOU JUST CREATED.  Then remember to not run the load mods and write mod file on your next run, or you are going to overwrite your edits.

            // TODO write a "merge" tool that will take an existing config and a stellaris directory and add any mods missing to the config but not overwrite changes.

            // Load the mod configs
            // This will be all the mods, including ones with include : false as they get filtered later.
            List <ModInfo> modInfos = ModDirectoryHelper.ReadModInfoFile(modConfigFilePath);

            // now create StellarisDirectoryHelpers for accessing your mods.
            // this will handling extracting zip files for you
            // and will only work over mods you ahve set the include parameter on.
            // The force override flag determines whether a mod will be extracted from steam workshop event if it already exists in the temp directory
            // For the first run of a "session" as you are parsing i alwayus recommend setting to true, to make sure you get the latest mod data
            // If you are running multiple times in succession (e.g. debugging your app), then set to false to speed things up.
            IList <StellarisDirectoryHelper> modDirectoryHelpers = ModDirectoryHelper.CreateDirectoryHelpers(modInfos, true);



            // Done with all the preprocessing for mods now.


            // First job is to get a Directory Helper for Stellaris Root.
            // While at the moment I could get away with changing the API to simply take an IEnumerable that includes the main stellaris directory
            // I want to keep the door open for the time when the utilities have differing behaviour for the game directory and any mods

            // For ease there are overloaded constructors on all utilities that just take the root stellaris directory when you are not loading mods,
            // but this example will always use the full ones.
            // the utilities will also cope happily with null or empty mod collections.

            var stellarisDirectoryHelper = new StellarisDirectoryHelper(stellarisRoot);

            // create a localisation helper, need to specify the Language for this
            // this gives easy way to look up localised strings from ids
            // 2 methods: GetName and GetDescription
            // GetName: gets the direct value for a key
            // GetDescription: gets the value for key + "_desc" as its such a common operation it gets a helper.
            // both of these methods will follow any $OtherLocalisationString$ variables in the localisation file (and strip out comments) to generate a complete
            // non-variabled string but will not process formatting codes
            var localisationApiHelper = new LocalisationApiHelper(stellarisDirectoryHelper, modDirectoryHelpers, STLLang.English);

            // Numerous values in the game files make use of variables in the scriptedVariables folder.  e.g. @tier1cost1 for level 1 tech costs
            // The scripted variables accessor handles the converting of these into their actual values
            // If it cannot look up a value for a given request it returns the requesting key
            var scriptedVariableAccessor = new ScriptedVariableAccessor(stellarisDirectoryHelper, modDirectoryHelpers);


            // Create the main parser helper
            // You do not need to assign a scripted variables helper if you don't want to resolve variables.
            var cwParserHelper = new CWParserHelper(scriptedVariableAccessor);

            // parse over all the tech files and convert each teach into a basic descriptive string
            // am storing each tech in a dictionary to allow the mods (which process after main) to override values in the core game.
            var allDirectoryHelpers = StellarisDirectoryHelper.CreateCombinedList(stellarisDirectoryHelper, modDirectoryHelpers);
            var result = new Dictionary <string, string>();

            foreach (var directoryHelper in allDirectoryHelpers)
            {
                // use DirectoryWalker to find all tech files to process.  Do not want to process the tier or category files.
                List <FileInfo> techFiles = DirectoryWalker.FindFilesInDirectoryTree(directoryHelper.Technology, StellarisDirectoryHelper.TextMask, new [] { "00_tier.txt", "00_category.txt" });

                // each node is the contents of an individual file, keyed by file name
                IDictionary <string, CWNode> parsedTechFiles = cwParserHelper.ParseParadoxFiles(techFiles.Select(x => x.FullName).ToList());
                foreach (var fileAndContents in parsedTechFiles)
                {
                    // top level nodes are files, so we process the immediate children of each file, which is the individual techs.
                    foreach (var techNode in fileAndContents.Value.Nodes)
                    {
                        // extract some info about the tech and put it in a string
                        string techString = "[" + techNode.GetKeyValue("area") + "]" +
                                            "(" + (techNode.GetKeyValue("tier") ?? "0") + ") " +
                                            localisationApiHelper.GetName(techNode.Key) + ": " +
                                            localisationApiHelper.GetDescription(techNode.Key) +
                                            " (from: " + fileAndContents.Key + ")";
                        result[techNode.Key] = techString;
                    }
                }
            }

            // loop over and output
            result.Values.ForEach(Console.WriteLine);
        }
Example #18
0
 protected override string GetDirectory(StellarisDirectoryHelper directoryHelper)
 {
     return(directoryHelper.Technology);
 }
 public ScriptedVariableAccessor(StellarisDirectoryHelper stellarisDirectoryHelper) :
     this(stellarisDirectoryHelper, new StellarisDirectoryHelper[] { })
 {
 }
 public ScriptedVariableAccessor(StellarisDirectoryHelper stellarisDirectoryHelper,
                                 IEnumerable <StellarisDirectoryHelper> modDirectoryHelpers) :
     this(stellarisDirectoryHelper, modDirectoryHelpers, new DirectoryWalker(), new CWParserHelper())
 {
 }
Example #21
0
 protected override string GetDirectory(StellarisDirectoryHelper directoryHelper)
 {
     return(directoryHelper.Buildings);
 }
 protected override string GetDirectory(StellarisDirectoryHelper directoryHelper)
 {
     return(directoryHelper.ComponentSets);
 }