November 14, 2013

Hack: Find Terraria Folder

Just a quick hack to share.  This is the code I'm using to find your Terraria installation in RomTerraria 3.0.

        static string GamePath = "";

        static List<string> FindDetails = new List<string>();

        static List<Process> GetProcessesByName(string machine, string filter, RegexOptions options)
        {
            List<Process> processList = new List<Process>();

            // Get the current processes
            Process[] runningProcesses = Process.GetProcesses(machine);

            // Find those that match the specified regular expression
            Regex processFilter = new Regex(filter, options);
            foreach (Process current in runningProcesses)
            {
                // Check for a match.
                if (processFilter.IsMatch(current.ProcessName))
                {
                    processList.Add(current);
                }
                // Dispose of any we're not keeping
                else current.Dispose();
            }

            // Return the filtered list as an array
            return processList;
        }

        static bool FindGame()
        {
            var steamCandidates = GetProcessesByName(".", "steam", RegexOptions.IgnoreCase);
            string steamFolder = String.Empty;
            foreach (var p in steamCandidates)
            {
                try
                {
                    if (p.MainModule.ModuleName.ToLower() == "steam.exe")
                    {
                        FindDetails.Add("Steam.exe process found.");
                        FileInfo f = new FileInfo(p.MainModule.FileName);
                        steamFolder = f.DirectoryName;
                        var d = f.Directory.GetDirectories("steamapps");
                        if (d.Count() > 0)
                        {
                            FindDetails.Add("Steamapps folder found.");
                            d = d[0].GetDirectories("common");
                            if (d.Count() > 0)
                            {
                                FindDetails.Add("Common folder found.");
                                d = d[0].GetDirectories("terraria");
                                if (d.Count() > 0)
                                {
                                    FindDetails.Add("Terraria folder found.");
                                    GamePath = d[0].FullName;
                                    return true;
                                }
                            }
                        }
                    }
                }
                catch (System.ComponentModel.Win32Exception)
                {
                    // Ignore this...means we were looking at SteamService.
                }
            }

            if (FindDetails.Count == 0)
            {
                FindDetails.Add("Could not find a process named Steam.exe running.");
                return false;
            }

            // Last chance: let's operate under the assumption that Terraria is in a different Steam install folder
            string steamConfig = Path.Combine(steamFolder, @"config/config.vdf");
            FindDetails.Add(String.Format("Checking Steam config at {0}", steamConfig));
            GamePath = ParseConfig(steamConfig, @"InstallConfigStore/Software/Valve/Steam/apps/105600/installdir");

            return !String.IsNullOrWhiteSpace(GamePath);
        }

        private static string ParseConfig(string steamConfig, string configNode)
        {
            Stack<string> keys = new Stack<string>();
            string lastString = String.Empty;
            using (StreamReader sr = new StreamReader(steamConfig))
            {
                while (!sr.EndOfStream)
                {
                    string s = sr.ReadLine().Trim();
                    if (s.StartsWith("{"))
                    {
                        keys.Push(lastString);
                    }
                    else if (s.StartsWith("}"))
                    {
                        keys.Pop();
                    }
                    else if (s.StartsWith("\""))
                    {
                        var tokens = s.Split('\t').Where(a => !String.IsNullOrWhiteSpace(a)).ToArray();
                        lastString = tokens[0].Trim('\"');
                        if (tokens.Length > 1)
                        {
                            string key = String.Join("/", keys.ToArray().Reverse()) + "/" + lastString;
                            Debug.WriteLine(key, "ParseConfig");
                            if (key.Equals(configNode, StringComparison.InvariantCultureIgnoreCase))
                            {
                                return tokens[1].Trim('\"').Replace(@"\\", @"\");
                            }
                        }
                    }
                }
            }

            return null;
        }

No comments: