Beispiel #1
0
        /// <summary>
        /// Parts of a vessel are first read one after the other, so the first part can only store indices of later parts it is connected to.
        /// After a complete vessel is read also all parts are read and the indices can be translated in references to now existing KmlParts.
        /// This is done by this method. Also reverse information (what parts are connected to this one) is then stored in a part.
        /// </summary>
        /// <param name="parts">The list of KmlParts, a KmlVessel will have one</param>
        /// <returns>A list of root parts (not pointing to another parent part). Could be more than one, if some connections are broken.</returns>
        public static List <KmlPart> BuildAttachmentStructure(List <KmlPart> parts)
        {
            List <KmlPart> roots = new List <KmlPart>();

            for (int i = 0; i < parts.Count; i++)
            {
                // Check parent connection
                KmlPart part = parts[i];
                if (part.ParentPartIndex == i)
                {
                    // Parent part is itself, so ParentPart property stays null
                    roots.Add(part);
                }
                else if (part.ParentPartIndex < 0 || part.ParentPartIndex >= parts.Count)
                {
                    Syntax.Warning(part, "Part's parent part index [" + part.ParentPartIndex + "] does not point to a valid part.");
                    roots.Add(part);
                }
                else
                {
                    part.ParentPart = parts[part.ParentPartIndex];
                    if (!part.AttachedToNodeIndices.Contains(part.ParentPartIndex) && part.AttachedToSurfaceIndex != part.ParentPartIndex)
                    {
                        // Part could be docked to parent
                        if ((part is KmlPartDock) && (part.ParentPart is KmlPartDock))
                        {
                            KmlPartDock docker = (KmlPartDock)part;
                            KmlPartDock dockee = (KmlPartDock)part.ParentPart;

                            // In case of "Docked (same vessel)" there has to be another docker-dockee connection and that would have connection via parent part
                            if (docker.DockState.ToLower() == "docked (docker)")
                            {
                                if (dockee.DockState.ToLower() != "docked (dockee)")
                                {
                                    Syntax.Warning(dockee, "Dock part is parent of other docker part. Docking state should be 'Docked (dockee)' but is '" + dockee.DockState + "', other dock: " + docker);
                                    docker.NeedsRepair = true;
                                    dockee.NeedsRepair = true;
                                }
                                else
                                {
                                    KmlPartDock.BuildDockStructure(dockee, docker);
                                    KmlPartDock.BuildDockStructure(docker, dockee);
                                }
                            }
                            else if (docker.DockState.ToLower() == "docked (dockee)")
                            {
                                if (dockee.DockState.ToLower() != "docked (docker)")
                                {
                                    Syntax.Warning(dockee, "Dock part is parent of other dockee part. Docking state should be 'Docked (docker)' but is '" + dockee.DockState + "', other dock: " + docker);
                                    docker.NeedsRepair = true;
                                    dockee.NeedsRepair = true;
                                }
                                else
                                {
                                    KmlPartDock.BuildDockStructure(dockee, docker);
                                    KmlPartDock.BuildDockStructure(docker, dockee);
                                }
                            }
                            else
                            {
                                if (dockee.DockState.ToLower() == "docked (dockee)")
                                {
                                    Syntax.Warning(docker, "Dock part is docked to parent dockee part. Docking state should be 'Docked (docker)' but is '" + docker.DockState + "', parent dock: " + dockee);
                                }
                                else if (dockee.DockState.ToLower() == "docked (docker)")
                                {
                                    Syntax.Warning(docker, "Dock part is docked to parent docker part. Docking state should be 'Docked (dockee)' but is '" + docker.DockState + "', parent dock: " + dockee);
                                }
                                else
                                {
                                    Syntax.Warning(docker, "Dock part is docked to parent dock part. Docking state should be 'Docked (docker)' or 'Docked (dockee)' but is '" + docker.DockState + "', parent dock: " + dockee);
                                    Syntax.Warning(dockee, "Dock part is parent of other dock part. Docking state should be 'Docked (dockee)' or 'Docked (docker)' but is '" + dockee.DockState + "', other dock: " + docker);
                                }
                                docker.NeedsRepair = true;
                                dockee.NeedsRepair = true;
                            }
                        }
                        // Part could be grappled by parent
                        else if ((part.ParentPart is KmlPartDock) && (part.ParentPart as KmlPartDock).DockType == KmlPartDock.DockTypes.Grapple)
                        {
                            KmlPartDock grapple = (KmlPartDock)part.ParentPart;

                            if (grapple.DockUid != part.Uid)
                            {
                                Syntax.Warning(part, "Part not attached or grappled by parent grappling part: " + grapple);
                                Syntax.Warning(grapple, "Grappling part is parent of other part, but is not grappled to it: " + part);
                                grapple.NeedsRepair = true;
                            }
                            else if (grapple.DockState.ToLower() != "grappled")
                            {
                                Syntax.Warning(part, "Part grappled by parent part. Docking state should be 'Grappled' but is '" + grapple.DockState + "', parent grapple: " + grapple);
                                Syntax.Warning(grapple, "Grappling part is parent of grappled part. Docking state should be 'Grappled' but is '" + grapple.DockState + "', grappled part: " + part);
                                grapple.NeedsRepair = true;
                            }
                            else
                            {
                                // It's docked but grappling needs a node attachment
                                KmlPartDock.BuildDockStructure(grapple, part);
                                Syntax.Warning(part, "Part is docked but not attached to parent grappling part: " + grapple);
                                Syntax.Warning(grapple, "Grappling part is parent and docked but not attached to grappled part: " + part);
                                grapple.NeedsRepair = true;
                            }
                        }

                        // TODO KmlPart.BuildAttachmentStructure(): How do KAS links work?

                        // Usually you can only attach a new part by a node to the surface of parent
                        // and not attach a part by surface to parents node. But if you have vessels docked
                        // this situation may happen and this leads to this additional check
                        else if (part.ParentPart.AttachedToSurfaceIndex != i)
                        {
                            Syntax.Warning(part, "Part not attached to parent part: " + part.ParentPart);
                        }
                    }
                }

                // Check attachments
                foreach (int p in part.AttachedToNodeIndices)
                {
                    if (p >= 0 && p < parts.Count)
                    {
                        KmlPart other = parts[p];
                        // Sort attached part in the corresponding list, identified by position not by node name
                        double diffX = part.Position.X - other.Position.X;
                        double diffY = part.Position.Y - other.Position.Y;
                        double diffZ = part.Position.Z - other.Position.Z;
                        if (Math.Abs(diffX) > Math.Abs(diffY) && Math.Abs(diffX) > Math.Abs(diffZ))
                        {
                            if (diffX > 0)
                            {
                                other.AttachedPartsRight.Add(part);
                                part.AttachedToPartsLeft.Add(other);
                            }
                            else
                            {
                                other.AttachedPartsLeft.Add(part);
                                part.AttachedToPartsRight.Add(other);
                            }
                        }
                        else if (Math.Abs(diffZ) > Math.Abs(diffX) && Math.Abs(diffZ) > Math.Abs(diffY))
                        {
                            if (diffZ > 0)
                            {
                                other.AttachedPartsFront.Add(part);
                                part.AttachedToPartsBack.Add(other);
                            }
                            else
                            {
                                other.AttachedPartsBack.Add(part);
                                part.AttachedToPartsFront.Add(other);
                            }
                        }
                        else
                        {
                            if (diffY > 0)
                            {
                                other.AttachedPartsTop.Add(part);
                                part.AttachedToPartsBottom.Add(other);
                            }
                            else
                            {
                                other.AttachedPartsBottom.Add(part);
                                part.AttachedToPartsTop.Add(other);
                            }
                        }
                        if (!other.AttachedToNodeIndices.Contains(parts.IndexOf(part)))
                        {
                            if ((other is KmlPartDock) && (other as KmlPartDock).DockType == KmlPartDock.DockTypes.Grapple)
                            {
                                KmlPartDock grapple = (KmlPartDock)other;
                                if (grapple.DockUid != part.Uid)
                                {
                                    Syntax.Warning(part, "Part node attachment not responded from other grappling part: " + grapple);
                                    grapple.NeedsRepair = true;
                                }
                                else if (grapple.DockState.ToLower() != "grappled")
                                {
                                    Syntax.Warning(part, "Part grappled by other grappling part. Docking state should be 'Grappled' but is '" + grapple.DockState + ", other grapple: " + grapple);
                                    grapple.NeedsRepair = true;
                                }
                                else
                                {
                                    KmlPartDock.BuildDockStructure(grapple, part);
                                }
                            }
                            else if ((part is KmlPartDock) && (part as KmlPartDock).DockType == KmlPartDock.DockTypes.Grapple)
                            {
                                KmlPartDock grapple = (KmlPartDock)part;
                                if (grapple.DockUid != other.Uid)
                                {
                                    Syntax.Warning(grapple, "Grappling part node attachment not responded from other grappled part: " + other);
                                    grapple.NeedsRepair = true;
                                }
                                else if (grapple.DockState.ToLower() != "grappled")
                                {
                                    Syntax.Warning(grapple, "Grappling part grappled attached part. Docking state should be 'Grappled' but is '" + grapple.DockState + ", attached part: " + other);
                                    grapple.NeedsRepair = true;
                                }
                                else
                                {
                                    KmlPartDock.BuildDockStructure(grapple, other);
                                }
                            }
                            else
                            {
                                Syntax.Warning(part, "Part node attachment not responded from other part: " + other.ToString());
                            }
                        }
                    }
                    else
                    {
                        Syntax.Warning(part, "Part supposed to be node attached to part index [" + p + "], which does not point to a valid part");
                    }
                }
                if (part.AttachedToSurfaceIndex >= 0 && part.AttachedToSurfaceIndex < parts.Count)
                {
                    parts[part.AttachedToSurfaceIndex].AttachedPartsSurface.Add(part);
                }
                else if (part.AttachedToSurfaceIndex != -1)
                {
                    Syntax.Warning(part, "Part supposed to be surface attached to part index [" + part.AttachedToSurfaceIndex + "], which does not point to a valid part");
                }

                // Check docking (with parent involved is already checked above, here needs to e checked a 'Docked (same vessel)'
                // Need to check one side only, other part will be touched here in another iteration of the loop
                if (part is KmlPartDock)
                {
                    KmlPartDock dock  = (KmlPartDock)part;
                    KmlPart     other = null;
                    foreach (KmlPart p in parts)
                    {
                        if (p.Uid == dock.DockUid)
                        {
                            other = p;
                            break;
                        }
                    }
                    if (other == null)
                    {
                        // This happens a lot, parts show UId 0 or some other UId they have been attached to before
                        if (dock.DockState.ToLower() == "docked (docker)" || dock.DockState.ToLower() == "docked (dockee)" ||
                            dock.DockState.ToLower() == "docked (same vessel)" || dock.DockState.ToLower() == "grappled")
                        {
                            Syntax.Warning(dock, "Dock part supposed to be attached to (UId " + dock.DockUid + "), which does not point to a valid part");
                            dock.NeedsRepair = true;
                        }
                        // If it still says 'Disengage' something went wron on undocking. We can repair if undocked part is now another vessel
                        // so other will be null because not found in this vessel
                        // Also could be 'Disarmed', 'Disabled' etc., so it's not checked to be 'Ready'.
                        else if (dock.DockState.ToLower() == "disengage")
                        {
                            Syntax.Warning(dock, "Dock part state should be 'Ready' but is '" + dock.DockState + "'");
                            dock.NeedsRepair = true;
                        }
                    }
                    // Docking with parent already checked
                    else if (other != dock.ParentPart && other.ParentPartIndex != i)
                    {
                        if (dock.DockState.ToLower() == "docked (docker)" || dock.DockState.ToLower() == "docked (dockee)" ||
                            dock.DockState.ToLower() == "docked (same vessel)" || dock.DockState.ToLower() == "grappled")
                        {
                            KmlPartDock.BuildDockStructure(dock, other);
                            if (other is KmlPartDock)
                            {
                                KmlPartDock otherDock = (KmlPartDock)other;
                                if (otherDock.DockUid != dock.Uid)
                                {
                                    Syntax.Warning(dock, "Dock part docked to other dock part, but docking not responded from other side. Other dock: " + otherDock);
                                    dock.NeedsRepair      = true;
                                    otherDock.NeedsRepair = true;
                                }
                                else if (otherDock.DockState.ToLower() == "docked (dockee)")
                                {
                                    if (dock.DockState.ToLower() != "docked (same vessel)")
                                    {
                                        Syntax.Warning(dock, "Dock part is docked to dockee part. Docking state should be 'Docked (same vessel)' but is '" + dock.DockState + "', dockee part: " + otherDock);
                                        dock.NeedsRepair      = true;
                                        otherDock.NeedsRepair = true;
                                    }
                                }
                                else if (otherDock.DockState.ToLower() == "docked (same vessel)")
                                {
                                    if (dock.DockState.ToLower() != "docked (dockee)")
                                    {
                                        Syntax.Warning(dock, "Dock part is docked to same vessel docking part. Docking state should be 'Docked (dockee)' but is '" + dock.DockState + "', same vessel docking part: " + otherDock);
                                        dock.NeedsRepair      = true;
                                        otherDock.NeedsRepair = true;
                                    }
                                }
                                else
                                {
                                    Syntax.Warning(dock, "Dock part is docked to other dock part. Docking state should be 'Docked (same vessel)' or 'Docked (dockee)' but is '" + dock.DockState + "', other dock: " + otherDock);
                                    dock.NeedsRepair      = true;
                                    otherDock.NeedsRepair = true;
                                }
                            }
                            else if (dock.DockType != KmlPartDock.DockTypes.Grapple)
                            {
                                Syntax.Warning(dock, "Dock part is no grappling device, so it should be only docked to other dock parts, but is docked to: " + other);
                                dock.NeedsRepair = true;
                            }
                        }
                    }
                }
            }
            return(roots);
        }