private void MergeDuplicateClasses()
        {
            // Rarely, a class is defined multiple times.
            // See replay 5F9D44B6400E284FD15A95AC8D5C5B45 which has 2 entries for TAGame.GameEvent_Soccar_TA
            // Merge their properties and drop the extras to keep everything from starting on fire

            var deletedClasses = new List <ClassNetCache>();

            var groupedClasses = ClassNetCaches.GroupBy(cnc => Objects[cnc.ObjectIndex]);

            foreach (var g in groupedClasses.Where(gc => gc.Count() > 1))
            {
                var goodClass = g.First();
                foreach (var badClass in g.Skip(1))
                {
                    foreach (var p in badClass.Properties)
                    {
                        goodClass.Properties[p.Key] = p.Value;
                    }
                    deletedClasses.Add(badClass);
                }
            }

            ClassNetCaches = ClassNetCaches.Where(cnc => !deletedClasses.Contains(cnc)).ToArray();
        }
        public string ToDebugString()
        {
            var sb = new StringBuilder();

            sb.AppendLine(TAGame_Replay_Soccar_TA);
            foreach (var prop in Properties.Values)
            {
                sb.AppendLine(prop.ToDebugString());
            }

            foreach (var ds in DebugStrings)
            {
                sb.AppendLine(ds.ToString());
            }

            foreach (var t in TickMarks)
            {
                sb.AppendLine(t.ToDebugString());
            }

            foreach (var kf in KeyFrames)
            {
                sb.AppendLine(kf.ToDebugString());
            }

            for (int i = 0; i < Objects.Length; ++i)
            {
                sb.AppendLine(string.Format("Object: Index {0} Name {1}", i, Objects[i]));
            }

            for (int i = 0; i < Names.Length; ++i)
            {
                sb.AppendLine(string.Format("Name: Index {0} Name {1}", i, Names[i]));
            }

            foreach (var ci in ClassIndexes)
            {
                sb.AppendLine(ci.ToDebugString());
            }

            foreach(var c in ClassNetCaches.Where(x=>x.Root))
            {
                sb.AppendLine(c.ToDebugString(Objects));
            }

            return sb.ToString();
        }
        private void FixClassParent(string childClassName, string parentClassName)
        {
            var parentClass = ClassNetCaches.Where(cnc => Objects[cnc.ObjectIndex] == parentClassName).SingleOrDefault();
            var childClass = ClassNetCaches.Where(cnc => Objects[cnc.ObjectIndex] == childClassName).SingleOrDefault();
            if (parentClass != null && childClass != null && (childClass.Parent == null || childClass.Parent != parentClass))
            {
                var oldParent = childClass.Parent == null ? "NULL" : Objects[childClass.Parent.ObjectIndex];
                System.Diagnostics.Trace.WriteLine($"Fixing class {childClassName}, setting its parent to {parentClassName} from {oldParent}");

                childClass.Root = false;
                if (childClass.Parent != null)
                {
                    childClass.Parent.Children.Remove(childClass);
                }
                childClass.Parent = parentClass;
                parentClass.Children.Add(childClass);
            }
        }
        private void FixClassParent(string childClassName, string parentClassName)
        {
            var parentClass = ClassNetCaches.Where(cnc => Objects[cnc.ObjectIndex] == parentClassName).SingleOrDefault();
            var childClass  = ClassNetCaches.Where(cnc => Objects[cnc.ObjectIndex] == childClassName).SingleOrDefault();

            if (parentClass != null && childClass != null && (childClass.Parent == null || childClass.Parent != parentClass))
            {
#if DEBUG
                Console.WriteLine(string.Format("Fixing class {0}, setting its parent to {1} from {2}", childClassName, parentClassName, childClass.Parent == null ? "NULL" : Objects[childClass.Parent.ObjectIndex]));
#endif
                childClass.Root = false;
                if (childClass.Parent != null)
                {
                    childClass.Parent.Children.Remove(childClass);
                }
                childClass.Parent = parentClass;
                parentClass.Children.Add(childClass);
            }
        }