static void Main(string[] args)
        {
            var oldVMFFilePath = string.Empty;
            var newVMFFilePath = string.Empty;

            var p = new OptionSet()
            {
                { "o|old=", v => { oldVMFFilePath = v; } }
                , { "n|new=", v => { newVMFFilePath = v; } }
            };
            var extra = p.Parse(args);

#if DEBUG
            oldVMFFilePath = "../../Test/test_2p.vmf";
            newVMFFilePath = "../../Test/test_2p_alt.vmf";
#endif

            if (!File.Exists(oldVMFFilePath) || !File.Exists(newVMFFilePath))
            {
                //exit
                return;
            }

            var oldVMF = new VMF(File.ReadAllLines(oldVMFFilePath));
            var newVMF = new VMF(File.ReadAllLines(newVMFFilePath));
            var outVMF = new VMF();

            var oldWorld = oldVMF.Body.Where(node => node.Name == "world").Where(node => node is VBlock).Cast <VBlock>().FirstOrDefault();
            var newWorld = newVMF.Body.Where(node => node.Name == "world").Where(node => node is VBlock).Cast <VBlock>().FirstOrDefault();

            //should totally use a dictionary instead
            var oldEntitiesList = oldVMF.Body.Where(node => node.Name == "entity").Where(node => node is VBlock).Cast <VBlock>().Select(block => Tuple.Create(block.Body.Where(property => property.Name == "id" && property is VProperty).Cast <VProperty>().FirstOrDefault()?.Value ?? "0", block)).ToList();
            var newEntitiesList = newVMF.Body.Where(node => node.Name == "entity").Where(node => node is VBlock).Cast <VBlock>().Select(block => Tuple.Create(block.Body.Where(property => property.Name == "id" && property is VProperty).Cast <VProperty>().FirstOrDefault()?.Value ?? "0", block)).ToList();

            //copy oldVMF
            outVMF = new VMF(oldVMF.ToVMFStrings());
            //remove all the entities
            outVMF = new VMF(outVMF.Body.Where(node => node.Name != "entity").ToList());
            //find the world
            var outWorldIndex = outVMF.Body.IndexOf(outVMF.Body.Where(node => node.Name == "world").Where(node => node is VBlock).Cast <VBlock>().FirstOrDefault());
            //make a new one
            var outNewWorld = (outVMF.Body[outWorldIndex] as VBlock).Body.Where(node => node.Name != "solid").ToList();
            //swap it in
            outVMF.Body[outWorldIndex] = new VBlock("world", outNewWorld);

            //don't include any duplicate IDs in the diffing process
            var entitiesNewDuplicateID = newEntitiesList.Where(newEntityTuple1 => newEntitiesList.Where(newEntityTuple2 => newEntityTuple1.Item1 == newEntityTuple2.Item1).Count() > 1).ToList();
            var entitiesOldDuplicateID = oldEntitiesList.Where(oldEntityTuple1 => oldEntitiesList.Where(oldEntityTuple2 => oldEntityTuple1.Item1 == oldEntityTuple2.Item1).Count() > 1).ToList();
            newEntitiesList.RemoveAll(entityTuple => entitiesNewDuplicateID.Where(duplicate => duplicate == entityTuple).Count() > 0);
            oldEntitiesList.RemoveAll(entityTuple => entitiesOldDuplicateID.Where(duplicate => duplicate == entityTuple).Count() > 0);

            var entitiesRemoved      = oldEntitiesList.Where(oldEntityTuple => newEntitiesList.Where(newEntityTuple => newEntityTuple.Item1 == oldEntityTuple.Item1).Count() == 0).ToList();
            var entitiesAdded        = newEntitiesList.Where(newEntityTuple => oldEntitiesList.Where(oldEntityTuple => newEntityTuple.Item1 == oldEntityTuple.Item1).Count() == 0).ToList();
            var entitiesOldRemaining = oldEntitiesList.Where(oldEntityTuple => newEntitiesList.Where(newEntityTuple => newEntityTuple.Item1 == oldEntityTuple.Item1).Count() > 0).ToList();
            var entitiesNewRemaining = newEntitiesList.Where(newEntityTuple => oldEntitiesList.Where(oldEntityTuple => newEntityTuple.Item1 == oldEntityTuple.Item1).Count() > 0).ToList();

            var entitiesNoChange  = new List <Tuple <string, VBlock> >();
            var entitiesOldChange = new List <Tuple <string, VBlock> >();
            var entitiesNewChange = new List <Tuple <string, VBlock> >();
            foreach (var oldEntityTuple in entitiesOldRemaining)
            {
                var newEntityTuple = entitiesNewRemaining.Where(newEntTuple => newEntTuple.Item1 == oldEntityTuple.Item1).FirstOrDefault();

                if (VBlockMatches(oldEntityTuple.Item2, newEntityTuple.Item2))
                {
                    entitiesNoChange.Add(oldEntityTuple);
                }
                else
                {
                    entitiesOldChange.Add(oldEntityTuple);
                    entitiesNewChange.Add(newEntityTuple);
                }
            }

            //TODO: Include solids in the above diff checking, and separate them out when generating final VMF

            //set mapversion to 1
            //iterate through world find differences, add to outWorld and visgroups
            //iterate through the rest of the entities and do the same

            File.WriteAllLines("diff.vmf", outVMF.ToVMFStrings());
        }
        static int Main(string[] args)
        {
#if DEBUG
            //args = new string[] { "-file", "dev_room.vmf" };
            args = new string[] { "-file", "1_instance.vmf" };

            Utils.DirectoryCopy(@"../../instances", "instances", true, true);
#endif

#if !DEBUG
            try
            {
#endif
            #region Get execution parameters
            string filePath = null;
            string gamePath = null;

            for (int i = 0; i < args.Length; i++)
            {
                if (args[i] == "-file" && i + 1 < args.Length && !args[i + 1].StartsWith("-"))
                {
                    filePath = args[++i];
                }
                else if (args[i] == "-game" && i + 1 < args.Length && !args[i + 1].StartsWith("-"))
                {
                    gamePath = args[++i]; //does this matter, or should I use the vmfs path to find the instances
                }
                // else if // Add additional parameters here
            }
            if (filePath == null)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                return(1);
            }
            #endregion

            #region Load VMF
            Console.Write("Loading file contents from \"" + filePath + "\"...");
            string[] fileContents = File.ReadAllLines(filePath);
            Console.WriteLine("Complete.");

            Console.Write("Parsing vmf ");
            VMF vmf = new VMF(fileContents);
            #endregion

            CollapseInstances(vmf);

            #region Save Altered VMF
            string newFilePath = "";
            newFilePath = filePath.EndsWith(".vmf")
                ? filePath.Insert(filePath.LastIndexOf("."), "_new")
                : filePath + "_new";

            File.WriteAllLines(newFilePath, vmf.ToVMFStrings());
            #endregion

#if !DEBUG
        }

        #region catch - display exception
        catch (Exception ex)
        {
            WriteLine("Exception:", ConsoleColor.Yellow);
            WriteLine(ex.ToString(), ConsoleColor.Red);
            return(1);
        }
        #endregion
#endif

            return(0);
        }